mirror of
				https://github.com/pure-admin/vue-pure-admin.git
				synced 2025-11-03 13:44:47 +08:00 
			
		
		
		
	Merge branch 'main' into gitee
This commit is contained in:
		
						commit
						87a2af7181
					
				@ -90,6 +90,7 @@ menus:
 | 
				
			|||||||
  hsMenuTree: Menu Tree
 | 
					  hsMenuTree: Menu Tree
 | 
				
			||||||
  hsVideoFrame: Video Frame Capture
 | 
					  hsVideoFrame: Video Frame Capture
 | 
				
			||||||
  hsWavesurfer: Audio Visualization
 | 
					  hsWavesurfer: Audio Visualization
 | 
				
			||||||
 | 
					  hsRipple: Ripple
 | 
				
			||||||
  hsOptimize: Debounce、Throttle、Copy、Longpress Directives
 | 
					  hsOptimize: Debounce、Throttle、Copy、Longpress Directives
 | 
				
			||||||
  hsWatermark: Water Mark
 | 
					  hsWatermark: Water Mark
 | 
				
			||||||
  hsPrint: Print
 | 
					  hsPrint: Print
 | 
				
			||||||
 | 
				
			|||||||
@ -90,6 +90,7 @@ menus:
 | 
				
			|||||||
  hsMenuTree: 菜单树结构
 | 
					  hsMenuTree: 菜单树结构
 | 
				
			||||||
  hsVideoFrame: 视频帧截取-wasm版
 | 
					  hsVideoFrame: 视频帧截取-wasm版
 | 
				
			||||||
  hsWavesurfer: 音频可视化
 | 
					  hsWavesurfer: 音频可视化
 | 
				
			||||||
 | 
					  hsRipple: 波纹(Ripple)
 | 
				
			||||||
  hsOptimize: 防抖、截流、复制、长按指令
 | 
					  hsOptimize: 防抖、截流、复制、长按指令
 | 
				
			||||||
  hsWatermark: 水印
 | 
					  hsWatermark: 水印
 | 
				
			||||||
  hsPrint: 打印
 | 
					  hsPrint: 打印
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										16
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								package.json
									
									
									
									
									
								
							@ -49,7 +49,7 @@
 | 
				
			|||||||
  },
 | 
					  },
 | 
				
			||||||
  "dependencies": {
 | 
					  "dependencies": {
 | 
				
			||||||
    "@amap/amap-jsapi-loader": "^1.0.1",
 | 
					    "@amap/amap-jsapi-loader": "^1.0.1",
 | 
				
			||||||
    "@howdyjs/mouse-menu": "2.0.9",
 | 
					    "@howdyjs/mouse-menu": "^2.1.3",
 | 
				
			||||||
    "@logicflow/core": "^1.2.22",
 | 
					    "@logicflow/core": "^1.2.22",
 | 
				
			||||||
    "@logicflow/extension": "^1.2.22",
 | 
					    "@logicflow/extension": "^1.2.22",
 | 
				
			||||||
    "@pureadmin/descriptions": "^1.2.0",
 | 
					    "@pureadmin/descriptions": "^1.2.0",
 | 
				
			||||||
@ -78,7 +78,7 @@
 | 
				
			|||||||
    "path": "^0.12.7",
 | 
					    "path": "^0.12.7",
 | 
				
			||||||
    "pinia": "^2.1.7",
 | 
					    "pinia": "^2.1.7",
 | 
				
			||||||
    "pinyin-pro": "^3.19.6",
 | 
					    "pinyin-pro": "^3.19.6",
 | 
				
			||||||
    "plus-pro-components": "^0.0.1",
 | 
					    "plus-pro-components": "^0.0.2",
 | 
				
			||||||
    "qrcode": "^1.5.3",
 | 
					    "qrcode": "^1.5.3",
 | 
				
			||||||
    "qs": "^6.11.2",
 | 
					    "qs": "^6.11.2",
 | 
				
			||||||
    "responsive-storage": "^2.2.0",
 | 
					    "responsive-storage": "^2.2.0",
 | 
				
			||||||
@ -91,7 +91,7 @@
 | 
				
			|||||||
    "vue": "^3.4.21",
 | 
					    "vue": "^3.4.21",
 | 
				
			||||||
    "vue-i18n": "^9.10.1",
 | 
					    "vue-i18n": "^9.10.1",
 | 
				
			||||||
    "vue-json-pretty": "^2.3.0",
 | 
					    "vue-json-pretty": "^2.3.0",
 | 
				
			||||||
    "vue-pdf-embed": "1.2.1",
 | 
					    "vue-pdf-embed": "^2.0.2",
 | 
				
			||||||
    "vue-router": "^4.3.0",
 | 
					    "vue-router": "^4.3.0",
 | 
				
			||||||
    "vue-tippy": "^6.4.1",
 | 
					    "vue-tippy": "^6.4.1",
 | 
				
			||||||
    "vue-types": "^5.1.1",
 | 
					    "vue-types": "^5.1.1",
 | 
				
			||||||
@ -122,11 +122,11 @@
 | 
				
			|||||||
    "@types/qrcode": "^1.5.5",
 | 
					    "@types/qrcode": "^1.5.5",
 | 
				
			||||||
    "@types/qs": "^6.9.12",
 | 
					    "@types/qs": "^6.9.12",
 | 
				
			||||||
    "@types/sortablejs": "^1.15.8",
 | 
					    "@types/sortablejs": "^1.15.8",
 | 
				
			||||||
    "@typescript-eslint/eslint-plugin": "^7.1.0",
 | 
					    "@typescript-eslint/eslint-plugin": "^7.1.1",
 | 
				
			||||||
    "@typescript-eslint/parser": "^7.1.0",
 | 
					    "@typescript-eslint/parser": "^7.1.1",
 | 
				
			||||||
    "@vitejs/plugin-vue": "^5.0.4",
 | 
					    "@vitejs/plugin-vue": "^5.0.4",
 | 
				
			||||||
    "@vitejs/plugin-vue-jsx": "^3.1.0",
 | 
					    "@vitejs/plugin-vue-jsx": "^3.1.0",
 | 
				
			||||||
    "autoprefixer": "^10.4.17",
 | 
					    "autoprefixer": "^10.4.18",
 | 
				
			||||||
    "boxen": "^7.1.1",
 | 
					    "boxen": "^7.1.1",
 | 
				
			||||||
    "cloc": "^2.11.0",
 | 
					    "cloc": "^2.11.0",
 | 
				
			||||||
    "cssnano": "^6.0.5",
 | 
					    "cssnano": "^6.0.5",
 | 
				
			||||||
@ -147,14 +147,14 @@
 | 
				
			|||||||
    "rollup-plugin-visualizer": "^5.12.0",
 | 
					    "rollup-plugin-visualizer": "^5.12.0",
 | 
				
			||||||
    "sass": "^1.71.1",
 | 
					    "sass": "^1.71.1",
 | 
				
			||||||
    "stylelint": "^16.2.1",
 | 
					    "stylelint": "^16.2.1",
 | 
				
			||||||
    "stylelint-config-recess-order": "^4.6.0",
 | 
					    "stylelint-config-recess-order": "^5.0.0",
 | 
				
			||||||
    "stylelint-config-recommended-vue": "^1.5.0",
 | 
					    "stylelint-config-recommended-vue": "^1.5.0",
 | 
				
			||||||
    "stylelint-config-standard-scss": "^13.0.0",
 | 
					    "stylelint-config-standard-scss": "^13.0.0",
 | 
				
			||||||
    "stylelint-prettier": "^5.0.0",
 | 
					    "stylelint-prettier": "^5.0.0",
 | 
				
			||||||
    "svgo": "^3.2.0",
 | 
					    "svgo": "^3.2.0",
 | 
				
			||||||
    "tailwindcss": "^3.4.1",
 | 
					    "tailwindcss": "^3.4.1",
 | 
				
			||||||
    "typescript": "^5.3.3",
 | 
					    "typescript": "^5.3.3",
 | 
				
			||||||
    "vite": "^5.1.4",
 | 
					    "vite": "^5.1.5",
 | 
				
			||||||
    "vite-plugin-cdn-import": "^0.3.5",
 | 
					    "vite-plugin-cdn-import": "^0.3.5",
 | 
				
			||||||
    "vite-plugin-compression": "^0.5.1",
 | 
					    "vite-plugin-compression": "^0.5.1",
 | 
				
			||||||
    "vite-plugin-fake-server": "^2.1.1",
 | 
					    "vite-plugin-fake-server": "^2.1.1",
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										501
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										501
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@ -2,3 +2,4 @@ export * from "./auth";
 | 
				
			|||||||
export * from "./copy";
 | 
					export * from "./copy";
 | 
				
			||||||
export * from "./longpress";
 | 
					export * from "./longpress";
 | 
				
			||||||
export * from "./optimize";
 | 
					export * from "./optimize";
 | 
				
			||||||
 | 
					export * from "./ripple";
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										48
									
								
								src/directives/ripple/index.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								src/directives/ripple/index.scss
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,48 @@
 | 
				
			|||||||
 | 
					/* stylelint-disable-next-line scss/dollar-variable-colon-space-after */
 | 
				
			||||||
 | 
					$ripple-animation-transition-in:
 | 
				
			||||||
 | 
					  transform 0.4s cubic-bezier(0, 0, 0.2, 1),
 | 
				
			||||||
 | 
					  opacity 0.2s cubic-bezier(0, 0, 0.2, 1) !default;
 | 
				
			||||||
 | 
					$ripple-animation-transition-out: opacity 0.5s cubic-bezier(0, 0, 0.2, 1) !default;
 | 
				
			||||||
 | 
					$ripple-animation-visible-opacity: 0.25 !default;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.v-ripple {
 | 
				
			||||||
 | 
					  &__container {
 | 
				
			||||||
 | 
					    position: absolute;
 | 
				
			||||||
 | 
					    top: 0;
 | 
				
			||||||
 | 
					    left: 0;
 | 
				
			||||||
 | 
					    z-index: 0;
 | 
				
			||||||
 | 
					    width: 100%;
 | 
				
			||||||
 | 
					    height: 100%;
 | 
				
			||||||
 | 
					    overflow: hidden;
 | 
				
			||||||
 | 
					    pointer-events: none;
 | 
				
			||||||
 | 
					    border-radius: inherit;
 | 
				
			||||||
 | 
					    contain: strict;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  &__animation {
 | 
				
			||||||
 | 
					    position: absolute;
 | 
				
			||||||
 | 
					    top: 0;
 | 
				
			||||||
 | 
					    left: 0;
 | 
				
			||||||
 | 
					    overflow: hidden;
 | 
				
			||||||
 | 
					    pointer-events: none;
 | 
				
			||||||
 | 
					    background: currentcolor;
 | 
				
			||||||
 | 
					    border-radius: 50%;
 | 
				
			||||||
 | 
					    opacity: 0;
 | 
				
			||||||
 | 
					    will-change: transform, opacity;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    &--enter {
 | 
				
			||||||
 | 
					      opacity: 0;
 | 
				
			||||||
 | 
					      transition: none;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    &--in {
 | 
				
			||||||
 | 
					      opacity: $ripple-animation-visible-opacity;
 | 
				
			||||||
 | 
					      transition: $ripple-animation-transition-in;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    &--out {
 | 
				
			||||||
 | 
					      opacity: 0;
 | 
				
			||||||
 | 
					      transition: $ripple-animation-transition-out;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										234
									
								
								src/directives/ripple/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										234
									
								
								src/directives/ripple/index.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,234 @@
 | 
				
			|||||||
 | 
					import "./index.scss";
 | 
				
			||||||
 | 
					import { isObject } from "@pureadmin/utils";
 | 
				
			||||||
 | 
					import type { Directive, DirectiveBinding } from "vue";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface RippleOptions {
 | 
				
			||||||
 | 
					  class?: string;
 | 
				
			||||||
 | 
					  center?: boolean;
 | 
				
			||||||
 | 
					  circle?: boolean;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface RippleDirectiveBinding
 | 
				
			||||||
 | 
					  extends Omit<DirectiveBinding, "modifiers" | "value"> {
 | 
				
			||||||
 | 
					  value?: boolean | { class: string };
 | 
				
			||||||
 | 
					  modifiers: {
 | 
				
			||||||
 | 
					    center?: boolean;
 | 
				
			||||||
 | 
					    circle?: boolean;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function transform(el: HTMLElement, value: string) {
 | 
				
			||||||
 | 
					  el.style.transform = value;
 | 
				
			||||||
 | 
					  el.style.webkitTransform = value;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const calculate = (
 | 
				
			||||||
 | 
					  e: PointerEvent,
 | 
				
			||||||
 | 
					  el: HTMLElement,
 | 
				
			||||||
 | 
					  value: RippleOptions = {}
 | 
				
			||||||
 | 
					) => {
 | 
				
			||||||
 | 
					  const offset = el.getBoundingClientRect();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // 获取点击位置距离 el 的垂直和水平距离
 | 
				
			||||||
 | 
					  let localX = e.clientX - offset.left;
 | 
				
			||||||
 | 
					  let localY = e.clientY - offset.top;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  let radius = 0;
 | 
				
			||||||
 | 
					  let scale = 0.3;
 | 
				
			||||||
 | 
					  // 计算点击位置到 el 顶点最远距离,即为圆的最大半径(勾股定理)
 | 
				
			||||||
 | 
					  if (el._ripple?.circle) {
 | 
				
			||||||
 | 
					    scale = 0.15;
 | 
				
			||||||
 | 
					    radius = el.clientWidth / 2;
 | 
				
			||||||
 | 
					    radius = value.center
 | 
				
			||||||
 | 
					      ? radius
 | 
				
			||||||
 | 
					      : radius + Math.sqrt((localX - radius) ** 2 + (localY - radius) ** 2) / 4;
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    radius = Math.sqrt(el.clientWidth ** 2 + el.clientHeight ** 2) / 2;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // 中心点坐标
 | 
				
			||||||
 | 
					  const centerX = `${(el.clientWidth - radius * 2) / 2}px`;
 | 
				
			||||||
 | 
					  const centerY = `${(el.clientHeight - radius * 2) / 2}px`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // 点击位置坐标
 | 
				
			||||||
 | 
					  const x = value.center ? centerX : `${localX - radius}px`;
 | 
				
			||||||
 | 
					  const y = value.center ? centerY : `${localY - radius}px`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return { radius, scale, x, y, centerX, centerY };
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const ripples = {
 | 
				
			||||||
 | 
					  show(e: PointerEvent, el: HTMLElement, value: RippleOptions = {}) {
 | 
				
			||||||
 | 
					    if (!el?._ripple?.enabled) {
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 创建 ripple 元素和 ripple 父元素
 | 
				
			||||||
 | 
					    const container = document.createElement("span");
 | 
				
			||||||
 | 
					    const animation = document.createElement("span");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    container.appendChild(animation);
 | 
				
			||||||
 | 
					    container.className = "v-ripple__container";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (value.class) {
 | 
				
			||||||
 | 
					      container.className += ` ${value.class}`;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const { radius, scale, x, y, centerX, centerY } = calculate(e, el, value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // ripple 圆大小
 | 
				
			||||||
 | 
					    const size = `${radius * 2}px`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    animation.className = "v-ripple__animation";
 | 
				
			||||||
 | 
					    animation.style.width = size;
 | 
				
			||||||
 | 
					    animation.style.height = size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    el.appendChild(container);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 获取目标元素样式表
 | 
				
			||||||
 | 
					    const computed = window.getComputedStyle(el);
 | 
				
			||||||
 | 
					    // 防止 position 被覆盖导致 ripple 位置有问题
 | 
				
			||||||
 | 
					    if (computed && computed.position === "static") {
 | 
				
			||||||
 | 
					      el.style.position = "relative";
 | 
				
			||||||
 | 
					      el.dataset.previousPosition = "static";
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    animation.classList.add("v-ripple__animation--enter");
 | 
				
			||||||
 | 
					    animation.classList.add("v-ripple__animation--visible");
 | 
				
			||||||
 | 
					    transform(
 | 
				
			||||||
 | 
					      animation,
 | 
				
			||||||
 | 
					      `translate(${x}, ${y}) scale3d(${scale},${scale},${scale})`
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    animation.dataset.activated = String(performance.now());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    setTimeout(() => {
 | 
				
			||||||
 | 
					      animation.classList.remove("v-ripple__animation--enter");
 | 
				
			||||||
 | 
					      animation.classList.add("v-ripple__animation--in");
 | 
				
			||||||
 | 
					      transform(animation, `translate(${centerX}, ${centerY}) scale3d(1,1,1)`);
 | 
				
			||||||
 | 
					    }, 0);
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  hide(el: HTMLElement | null) {
 | 
				
			||||||
 | 
					    if (!el?._ripple?.enabled) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const ripples = el.getElementsByClassName("v-ripple__animation");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (ripples.length === 0) return;
 | 
				
			||||||
 | 
					    const animation = ripples[ripples.length - 1] as HTMLElement;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (animation.dataset.isHiding) return;
 | 
				
			||||||
 | 
					    else animation.dataset.isHiding = "true";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const diff = performance.now() - Number(animation.dataset.activated);
 | 
				
			||||||
 | 
					    const delay = Math.max(250 - diff, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    setTimeout(() => {
 | 
				
			||||||
 | 
					      animation.classList.remove("v-ripple__animation--in");
 | 
				
			||||||
 | 
					      animation.classList.add("v-ripple__animation--out");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      setTimeout(() => {
 | 
				
			||||||
 | 
					        const ripples = el.getElementsByClassName("v-ripple__animation");
 | 
				
			||||||
 | 
					        if (ripples.length === 1 && el.dataset.previousPosition) {
 | 
				
			||||||
 | 
					          el.style.position = el.dataset.previousPosition;
 | 
				
			||||||
 | 
					          delete el.dataset.previousPosition;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (animation.parentNode?.parentNode === el)
 | 
				
			||||||
 | 
					          el.removeChild(animation.parentNode);
 | 
				
			||||||
 | 
					      }, 300);
 | 
				
			||||||
 | 
					    }, delay);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function isRippleEnabled(value: any): value is true {
 | 
				
			||||||
 | 
					  return typeof value === "undefined" || !!value;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function rippleShow(e: PointerEvent) {
 | 
				
			||||||
 | 
					  const value: RippleOptions = {};
 | 
				
			||||||
 | 
					  const element = e.currentTarget as HTMLElement | undefined;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (!element?._ripple || element._ripple.touched) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  value.center = element._ripple.centered;
 | 
				
			||||||
 | 
					  if (element._ripple.class) {
 | 
				
			||||||
 | 
					    value.class = element._ripple.class;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ripples.show(e, element, value);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function rippleHide(e: Event) {
 | 
				
			||||||
 | 
					  const element = e.currentTarget as HTMLElement | null;
 | 
				
			||||||
 | 
					  if (!element?._ripple) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  window.setTimeout(() => {
 | 
				
			||||||
 | 
					    if (element._ripple) {
 | 
				
			||||||
 | 
					      element._ripple.touched = false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					  ripples.hide(element);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function updateRipple(
 | 
				
			||||||
 | 
					  el: HTMLElement,
 | 
				
			||||||
 | 
					  binding: RippleDirectiveBinding,
 | 
				
			||||||
 | 
					  wasEnabled: boolean
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
					  const { value, modifiers } = binding;
 | 
				
			||||||
 | 
					  const enabled = isRippleEnabled(value);
 | 
				
			||||||
 | 
					  if (!enabled) {
 | 
				
			||||||
 | 
					    ripples.hide(el);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  el._ripple = el._ripple ?? {};
 | 
				
			||||||
 | 
					  el._ripple.enabled = enabled;
 | 
				
			||||||
 | 
					  el._ripple.centered = modifiers.center;
 | 
				
			||||||
 | 
					  el._ripple.circle = modifiers.circle;
 | 
				
			||||||
 | 
					  if (isObject(value) && value.class) {
 | 
				
			||||||
 | 
					    el._ripple.class = value.class;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (enabled && !wasEnabled) {
 | 
				
			||||||
 | 
					    el.addEventListener("pointerdown", rippleShow);
 | 
				
			||||||
 | 
					    el.addEventListener("pointerup", rippleHide);
 | 
				
			||||||
 | 
					  } else if (!enabled && wasEnabled) {
 | 
				
			||||||
 | 
					    removeListeners(el);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function removeListeners(el: HTMLElement) {
 | 
				
			||||||
 | 
					  el.removeEventListener("pointerdown", rippleShow);
 | 
				
			||||||
 | 
					  el.removeEventListener("pointerup", rippleHide);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function mounted(el: HTMLElement, binding: RippleDirectiveBinding) {
 | 
				
			||||||
 | 
					  updateRipple(el, binding, false);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function unmounted(el: HTMLElement) {
 | 
				
			||||||
 | 
					  delete el._ripple;
 | 
				
			||||||
 | 
					  removeListeners(el);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function updated(el: HTMLElement, binding: RippleDirectiveBinding) {
 | 
				
			||||||
 | 
					  if (binding.value === binding.oldValue) {
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const wasEnabled = isRippleEnabled(binding.oldValue);
 | 
				
			||||||
 | 
					  updateRipple(el, binding, wasEnabled);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @description 指令 v-ripple
 | 
				
			||||||
 | 
					 * @use 用法如下
 | 
				
			||||||
 | 
					 * 1. v-ripple 代表启用基本的 ripple 功能
 | 
				
			||||||
 | 
					 * 2. v-ripple="{ class: 'text-red' }" 代表自定义 ripple 颜色,支持 tailwindcss,生效样式是 color
 | 
				
			||||||
 | 
					 * 3. v-ripple.center 代表从中心扩散
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export const Ripple: Directive = {
 | 
				
			||||||
 | 
					  mounted,
 | 
				
			||||||
 | 
					  unmounted,
 | 
				
			||||||
 | 
					  updated
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -42,6 +42,15 @@ export default {
 | 
				
			|||||||
        title: $t("menus.hsExcel")
 | 
					        title: $t("menus.hsExcel")
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      path: "/components/ripple",
 | 
				
			||||||
 | 
					      name: "Ripple",
 | 
				
			||||||
 | 
					      component: () => import("@/views/able/ripple.vue"),
 | 
				
			||||||
 | 
					      meta: {
 | 
				
			||||||
 | 
					        title: $t("menus.hsRipple"),
 | 
				
			||||||
 | 
					        extraIcon: "IF-pure-iconfont-new svg"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      path: "/able/debounce",
 | 
					      path: "/able/debounce",
 | 
				
			||||||
      name: "Debounce",
 | 
					      name: "Debounce",
 | 
				
			||||||
 | 
				
			|||||||
@ -64,7 +64,7 @@
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* 全局覆盖element-plus的el-dialog、el-drawer、el-message-box、el-notification组件右上角关闭图标和el-upload上传文件列表右侧关闭图标的样式,表现更鲜明 */
 | 
					/* 全局覆盖element-plus的el-tour、el-dialog、el-drawer、el-message-box、el-notification组件右上角关闭图标和el-upload上传文件列表右侧关闭图标的样式,表现更鲜明 */
 | 
				
			||||||
.el-dialog__headerbtn,
 | 
					.el-dialog__headerbtn,
 | 
				
			||||||
.el-message-box__headerbtn {
 | 
					.el-message-box__headerbtn {
 | 
				
			||||||
  &:hover {
 | 
					  &:hover {
 | 
				
			||||||
@ -75,6 +75,7 @@
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.el-icon {
 | 
					.el-icon {
 | 
				
			||||||
 | 
					  &.el-tour__close,
 | 
				
			||||||
  &.el-dialog__close,
 | 
					  &.el-dialog__close,
 | 
				
			||||||
  &.el-drawer__close,
 | 
					  &.el-drawer__close,
 | 
				
			||||||
  &.el-message-box__close,
 | 
					  &.el-message-box__close,
 | 
				
			||||||
 | 
				
			|||||||
@ -21,7 +21,7 @@ const source =
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const handleDocumentRender = () => {
 | 
					const handleDocumentRender = () => {
 | 
				
			||||||
  loading.value = false;
 | 
					  loading.value = false;
 | 
				
			||||||
  pageCount.value = pdfRef.value.pageCount;
 | 
					  pageCount.value = pdfRef.value.doc.numPages;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const showAllPagesChange = () => {
 | 
					const showAllPagesChange = () => {
 | 
				
			||||||
@ -29,6 +29,7 @@ const showAllPagesChange = () => {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const onPrint = () => {
 | 
					const onPrint = () => {
 | 
				
			||||||
 | 
					  // 如果在打印时,打印页面是本身的两倍,在打印配置 页面 设置 仅限页码为奇数的页面 即可
 | 
				
			||||||
  pdfRef.value.print();
 | 
					  pdfRef.value.print();
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										71
									
								
								src/views/able/ripple.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								src/views/able/ripple.vue
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,71 @@
 | 
				
			|||||||
 | 
					<script setup lang="ts">
 | 
				
			||||||
 | 
					defineOptions({
 | 
				
			||||||
 | 
					  name: "Ripple"
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<template>
 | 
				
			||||||
 | 
					  <el-card shadow="never">
 | 
				
			||||||
 | 
					    <template #header>
 | 
				
			||||||
 | 
					      <div class="font-medium">波纹(Ripple)</div>
 | 
				
			||||||
 | 
					    </template>
 | 
				
			||||||
 | 
					    <div class="mb-5">组件中的波纹</div>
 | 
				
			||||||
 | 
					    <el-alert
 | 
				
			||||||
 | 
					      title="v-ripple在某些组件中使用波纹特效会异常,这是因为v-ripple指令只能作用于当前元素,某些组件有多层元素嵌套,且目标元素没在顶层,所以会导致特效异常"
 | 
				
			||||||
 | 
					      type="warning"
 | 
				
			||||||
 | 
					      :closable="false"
 | 
				
			||||||
 | 
					    />
 | 
				
			||||||
 | 
					    <el-space wrap class="my-5">
 | 
				
			||||||
 | 
					      <el-button v-ripple>Default</el-button>
 | 
				
			||||||
 | 
					      <el-button v-ripple type="primary">Primary</el-button>
 | 
				
			||||||
 | 
					      <el-button v-ripple type="success">Success</el-button>
 | 
				
			||||||
 | 
					      <el-button v-ripple type="info">Info</el-button>
 | 
				
			||||||
 | 
					      <el-button v-ripple type="warning">Warning</el-button>
 | 
				
			||||||
 | 
					      <el-button v-ripple type="danger">Danger</el-button>
 | 
				
			||||||
 | 
					    </el-space>
 | 
				
			||||||
 | 
					    <el-card v-ripple class="mb-5 w-[510px] select-none" shadow="hover">
 | 
				
			||||||
 | 
					      卡片
 | 
				
			||||||
 | 
					    </el-card>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <div class="mb-5">
 | 
				
			||||||
 | 
					      只要在组件或HTML元素上使用v-ripple指令,就可以启用基本的ripple功能
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					    <div
 | 
				
			||||||
 | 
					      v-ripple
 | 
				
			||||||
 | 
					      class="mb-5 text-center shadow-md rounded-md p-8 text-lg select-none"
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
 | 
					      HTML元素
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					    <span
 | 
				
			||||||
 | 
					      v-ripple
 | 
				
			||||||
 | 
					      class="inline-block shadow-md rounded-md p-8 text-lg select-none"
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
 | 
					      行内元素需要添加display: block或display: inline-block才能生效
 | 
				
			||||||
 | 
					    </span>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <div class="my-5">
 | 
				
			||||||
 | 
					      当使用v-ripple.center时,将始终从目标的中心处产生波纹
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					    <div
 | 
				
			||||||
 | 
					      v-ripple.center
 | 
				
			||||||
 | 
					      class="mb-5 text-center shadow-md rounded-md p-8 text-lg select-none"
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
 | 
					      始终从中心触发波纹
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <div class="mb-5">
 | 
				
			||||||
 | 
					      使用v-ripple="{ class: '' }"添加类来自定义波纹颜色,支持tailwindcss
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					    <el-alert
 | 
				
			||||||
 | 
					      title="自定义样式生效为文字颜色,例如:color: 'red';"
 | 
				
			||||||
 | 
					      type="warning"
 | 
				
			||||||
 | 
					      :closable="false"
 | 
				
			||||||
 | 
					    />
 | 
				
			||||||
 | 
					    <div
 | 
				
			||||||
 | 
					      v-ripple="{ class: 'text-red-500' }"
 | 
				
			||||||
 | 
					      class="my-5 text-center shadow-md rounded-md p-4 text-lg select-none"
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
 | 
					      自定义波纹颜色
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  </el-card>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
@ -75,7 +75,9 @@ Object.keys(devDependencies).forEach(key => {
 | 
				
			|||||||
          <span class="font-medium">平台信息</span>
 | 
					          <span class="font-medium">平台信息</span>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
      </template>
 | 
					      </template>
 | 
				
			||||||
      <PureDescriptions border :columns="columns" :column="4" />
 | 
					      <el-scrollbar>
 | 
				
			||||||
 | 
					        <PureDescriptions border :columns="columns" :column="4" />
 | 
				
			||||||
 | 
					      </el-scrollbar>
 | 
				
			||||||
    </el-card>
 | 
					    </el-card>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <el-card class="m-4 box-card" shadow="never">
 | 
					    <el-card class="m-4 box-card" shadow="never">
 | 
				
			||||||
@ -84,28 +86,30 @@ Object.keys(devDependencies).forEach(key => {
 | 
				
			|||||||
          <span class="font-medium">生产环境依赖</span>
 | 
					          <span class="font-medium">生产环境依赖</span>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
      </template>
 | 
					      </template>
 | 
				
			||||||
      <el-descriptions border size="small" :column="6">
 | 
					      <el-scrollbar>
 | 
				
			||||||
        <el-descriptions-item
 | 
					        <el-descriptions border size="small" :column="6">
 | 
				
			||||||
          v-for="(item, index) in schema"
 | 
					          <el-descriptions-item
 | 
				
			||||||
          :key="index"
 | 
					            v-for="(item, index) in schema"
 | 
				
			||||||
          :label="item.label"
 | 
					            :key="index"
 | 
				
			||||||
          :label-class-name="getMainLabel(item.label)"
 | 
					            :label="item.label"
 | 
				
			||||||
          class-name="pure-version"
 | 
					            :label-class-name="getMainLabel(item.label)"
 | 
				
			||||||
          label-align="right"
 | 
					            class-name="pure-version"
 | 
				
			||||||
        >
 | 
					            label-align="right"
 | 
				
			||||||
          <a
 | 
					 | 
				
			||||||
            :href="'https://www.npmjs.com/package/' + item.label"
 | 
					 | 
				
			||||||
            target="_blank"
 | 
					 | 
				
			||||||
          >
 | 
					          >
 | 
				
			||||||
            <span
 | 
					            <a
 | 
				
			||||||
              :class="getMainLabel(item.label)"
 | 
					              :href="'https://www.npmjs.com/package/' + item.label"
 | 
				
			||||||
              style="color: var(--el-color-primary)"
 | 
					              target="_blank"
 | 
				
			||||||
            >
 | 
					            >
 | 
				
			||||||
              {{ item.field }}
 | 
					              <span
 | 
				
			||||||
            </span>
 | 
					                :class="getMainLabel(item.label)"
 | 
				
			||||||
          </a>
 | 
					                style="color: var(--el-color-primary)"
 | 
				
			||||||
        </el-descriptions-item>
 | 
					              >
 | 
				
			||||||
      </el-descriptions>
 | 
					                {{ item.field }}
 | 
				
			||||||
 | 
					              </span>
 | 
				
			||||||
 | 
					            </a>
 | 
				
			||||||
 | 
					          </el-descriptions-item>
 | 
				
			||||||
 | 
					        </el-descriptions>
 | 
				
			||||||
 | 
					      </el-scrollbar>
 | 
				
			||||||
    </el-card>
 | 
					    </el-card>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <el-card class="m-4 box-card" shadow="never">
 | 
					    <el-card class="m-4 box-card" shadow="never">
 | 
				
			||||||
@ -114,28 +118,30 @@ Object.keys(devDependencies).forEach(key => {
 | 
				
			|||||||
          <span class="font-medium">开发环境依赖</span>
 | 
					          <span class="font-medium">开发环境依赖</span>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
      </template>
 | 
					      </template>
 | 
				
			||||||
      <el-descriptions border size="small" :column="5">
 | 
					      <el-scrollbar>
 | 
				
			||||||
        <el-descriptions-item
 | 
					        <el-descriptions border size="small" :column="5">
 | 
				
			||||||
          v-for="(item, index) in devSchema"
 | 
					          <el-descriptions-item
 | 
				
			||||||
          :key="index"
 | 
					            v-for="(item, index) in devSchema"
 | 
				
			||||||
          :label="item.label"
 | 
					            :key="index"
 | 
				
			||||||
          :label-class-name="getMainLabel(item.label)"
 | 
					            :label="item.label"
 | 
				
			||||||
          class-name="pure-version"
 | 
					            :label-class-name="getMainLabel(item.label)"
 | 
				
			||||||
          label-align="right"
 | 
					            class-name="pure-version"
 | 
				
			||||||
        >
 | 
					            label-align="right"
 | 
				
			||||||
          <a
 | 
					 | 
				
			||||||
            :href="'https://www.npmjs.com/package/' + item.label"
 | 
					 | 
				
			||||||
            target="_blank"
 | 
					 | 
				
			||||||
          >
 | 
					          >
 | 
				
			||||||
            <span
 | 
					            <a
 | 
				
			||||||
              :class="getMainLabel(item.label)"
 | 
					              :href="'https://www.npmjs.com/package/' + item.label"
 | 
				
			||||||
              style="color: var(--el-color-primary)"
 | 
					              target="_blank"
 | 
				
			||||||
            >
 | 
					            >
 | 
				
			||||||
              {{ item.field }}
 | 
					              <span
 | 
				
			||||||
            </span>
 | 
					                :class="getMainLabel(item.label)"
 | 
				
			||||||
          </a>
 | 
					                style="color: var(--el-color-primary)"
 | 
				
			||||||
        </el-descriptions-item>
 | 
					              >
 | 
				
			||||||
      </el-descriptions>
 | 
					                {{ item.field }}
 | 
				
			||||||
 | 
					              </span>
 | 
				
			||||||
 | 
					            </a>
 | 
				
			||||||
 | 
					          </el-descriptions-item>
 | 
				
			||||||
 | 
					        </el-descriptions>
 | 
				
			||||||
 | 
					      </el-scrollbar>
 | 
				
			||||||
    </el-card>
 | 
					    </el-card>
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
				
			|||||||
@ -1,63 +1,75 @@
 | 
				
			|||||||
<script setup lang="ts">
 | 
					<script setup lang="ts">
 | 
				
			||||||
 | 
					import { ref } from "vue";
 | 
				
			||||||
import intro from "intro.js";
 | 
					import intro from "intro.js";
 | 
				
			||||||
import "intro.js/minified/introjs.min.css";
 | 
					import "intro.js/minified/introjs.min.css";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type GuideStep = {
 | 
				
			||||||
 | 
					  element: string | HTMLElement;
 | 
				
			||||||
 | 
					  title: string;
 | 
				
			||||||
 | 
					  intro: string;
 | 
				
			||||||
 | 
					  position: "left" | "right" | "top" | "bottom";
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
defineOptions({
 | 
					defineOptions({
 | 
				
			||||||
  name: "Guide"
 | 
					  name: "Guide"
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const GUIDE_STEPS = [
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    element: document.querySelector(".sidebar-logo-container") as
 | 
				
			||||||
 | 
					      | string
 | 
				
			||||||
 | 
					      | HTMLElement,
 | 
				
			||||||
 | 
					    title: "项目名称和Logo",
 | 
				
			||||||
 | 
					    intro: "您可以在这里设置项目名称和Logo",
 | 
				
			||||||
 | 
					    position: "left"
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    element: document.querySelector("#header-search") as string | HTMLElement,
 | 
				
			||||||
 | 
					    title: "搜索菜单",
 | 
				
			||||||
 | 
					    intro: "您可以在这里搜索想要查看的菜单",
 | 
				
			||||||
 | 
					    position: "left"
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    element: document.querySelector("#header-notice") as string | HTMLElement,
 | 
				
			||||||
 | 
					    title: "消息通知",
 | 
				
			||||||
 | 
					    intro: "您可以在这里查看管理员发送的消息",
 | 
				
			||||||
 | 
					    position: "left"
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    element: document.querySelector("#header-translation") as
 | 
				
			||||||
 | 
					      | string
 | 
				
			||||||
 | 
					      | HTMLElement,
 | 
				
			||||||
 | 
					    title: "国际化",
 | 
				
			||||||
 | 
					    intro: "您可以在这里进行语言切换",
 | 
				
			||||||
 | 
					    position: "left"
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    element: document.querySelector(".set-icon") as string | HTMLElement,
 | 
				
			||||||
 | 
					    title: "项目配置",
 | 
				
			||||||
 | 
					    intro: "您可以在这里查看项目配置",
 | 
				
			||||||
 | 
					    position: "left"
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    element: document.querySelector(".tags-view") as string | HTMLElement,
 | 
				
			||||||
 | 
					    title: "多标签页",
 | 
				
			||||||
 | 
					    intro: "这里是您访问过的页面的历史",
 | 
				
			||||||
 | 
					    position: "bottom"
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					] as Partial<GuideStep>[];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const tourOpen = ref(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const onGuide = () => {
 | 
					const onGuide = () => {
 | 
				
			||||||
  intro()
 | 
					  intro()
 | 
				
			||||||
    .setOptions({
 | 
					    .setOptions({
 | 
				
			||||||
      steps: [
 | 
					      steps: GUIDE_STEPS
 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
          element: document.querySelector(".sidebar-logo-container") as
 | 
					 | 
				
			||||||
            | string
 | 
					 | 
				
			||||||
            | HTMLElement,
 | 
					 | 
				
			||||||
          title: "项目名称和Logo",
 | 
					 | 
				
			||||||
          intro: "您可以在这里设置项目名称和Logo",
 | 
					 | 
				
			||||||
          position: "left"
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
          element: document.querySelector("#header-search") as
 | 
					 | 
				
			||||||
            | string
 | 
					 | 
				
			||||||
            | HTMLElement,
 | 
					 | 
				
			||||||
          title: "搜索菜单",
 | 
					 | 
				
			||||||
          intro: "您可以在这里搜索想要查看的菜单",
 | 
					 | 
				
			||||||
          position: "left"
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
          element: document.querySelector("#header-notice") as
 | 
					 | 
				
			||||||
            | string
 | 
					 | 
				
			||||||
            | HTMLElement,
 | 
					 | 
				
			||||||
          title: "消息通知",
 | 
					 | 
				
			||||||
          intro: "您可以在这里查看管理员发送的消息",
 | 
					 | 
				
			||||||
          position: "left"
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
          element: document.querySelector("#header-translation") as
 | 
					 | 
				
			||||||
            | string
 | 
					 | 
				
			||||||
            | HTMLElement,
 | 
					 | 
				
			||||||
          title: "国际化",
 | 
					 | 
				
			||||||
          intro: "您可以在这里进行语言切换",
 | 
					 | 
				
			||||||
          position: "left"
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
          element: document.querySelector(".set-icon") as string | HTMLElement,
 | 
					 | 
				
			||||||
          title: "项目配置",
 | 
					 | 
				
			||||||
          intro: "您可以在这里查看项目配置",
 | 
					 | 
				
			||||||
          position: "left"
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
          element: document.querySelector(".tags-view") as string | HTMLElement,
 | 
					 | 
				
			||||||
          title: "多标签页",
 | 
					 | 
				
			||||||
          intro: "这里是您访问过的页面的历史",
 | 
					 | 
				
			||||||
          position: "bottom"
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      ]
 | 
					 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
    .start();
 | 
					    .start();
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const onTour = () => {
 | 
				
			||||||
 | 
					  tourOpen.value = true;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<template>
 | 
					<template>
 | 
				
			||||||
@ -69,6 +81,18 @@ const onGuide = () => {
 | 
				
			|||||||
        </span>
 | 
					        </span>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
    </template>
 | 
					    </template>
 | 
				
			||||||
    <el-button @click="onGuide"> 打开引导页 </el-button>
 | 
					    <el-button @click="onGuide"> 打开引导页 (intro.js) </el-button>
 | 
				
			||||||
 | 
					    <el-button @click="onTour"> 打开引导页 (el-tour) </el-button>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <el-tour v-model="tourOpen">
 | 
				
			||||||
 | 
					      <el-tour-step
 | 
				
			||||||
 | 
					        v-for="step in GUIDE_STEPS"
 | 
				
			||||||
 | 
					        :key="step.title"
 | 
				
			||||||
 | 
					        :target="() => step.element"
 | 
				
			||||||
 | 
					        :title="step.title"
 | 
				
			||||||
 | 
					        :description="step.intro"
 | 
				
			||||||
 | 
					        :placement="step.position"
 | 
				
			||||||
 | 
					      />
 | 
				
			||||||
 | 
					    </el-tour>
 | 
				
			||||||
  </el-card>
 | 
					  </el-card>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										14
									
								
								types/global.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										14
									
								
								types/global.d.ts
									
									
									
									
										vendored
									
									
								
							@ -180,4 +180,18 @@ declare global {
 | 
				
			|||||||
    $storage: ResponsiveStorage;
 | 
					    $storage: ResponsiveStorage;
 | 
				
			||||||
    $config: PlatformConfigs;
 | 
					    $config: PlatformConfigs;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * 扩展 `Elemet`
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  interface Element {
 | 
				
			||||||
 | 
					    // v-ripple 作用于 src/directives/ripple/index.ts 文件
 | 
				
			||||||
 | 
					    _ripple?: {
 | 
				
			||||||
 | 
					      enabled?: boolean;
 | 
				
			||||||
 | 
					      centered?: boolean;
 | 
				
			||||||
 | 
					      class?: string;
 | 
				
			||||||
 | 
					      circle?: boolean;
 | 
				
			||||||
 | 
					      touched?: boolean;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user