24 changed files with 703 additions and 157 deletions
			
			
		- 
					14index.html
 - 
					10package.json
 - 
					248pnpm-lock.yaml
 - 
					2public/serverConfig.json
 - 
					4src/layout/components/sidebar/sidebarItem.vue
 - 
					63src/layout/frameView.vue
 - 
					1src/layout/types.ts
 - 
					5src/main.ts
 - 
					11src/router/index.ts
 - 
					9src/router/modules/externalLink.ts
 - 
					7src/router/utils.ts
 - 
					2src/store/modules/multiTags.ts
 - 
					4src/style/index.scss
 - 
					4src/utils/http/index.ts
 - 
					4src/utils/http/types.d.ts
 - 
					3src/utils/is.ts
 - 
					3src/utils/link.ts
 - 
					54src/utils/loaders/index.ts
 - 
					15src/utils/operate/index.ts
 - 
					226src/utils/print.ts
 - 
					35src/utils/resize/index.ts
 - 
					116src/utils/watermark.ts
 - 
					9types/global.d.ts
 - 
					11vite.config.ts
 
@ -0,0 +1,63 @@ | 
			
		|||||
 | 
				<template> | 
			
		||||
 | 
				  <div class="frame" v-loading="loading"> | 
			
		||||
 | 
				    <iframe :src="frameSrc" class="frame-iframe" ref="frameRef"></iframe> | 
			
		||||
 | 
				  </div> | 
			
		||||
 | 
				</template> | 
			
		||||
 | 
				<script lang="ts" setup> | 
			
		||||
 | 
				import { useRoute } from "vue-router"; | 
			
		||||
 | 
				import { ref, unref, onMounted, nextTick } from "vue"; | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				const loading = ref(false); | 
			
		||||
 | 
				const currentRoute = useRoute(); | 
			
		||||
 | 
				const frameSrc = ref<string>(""); | 
			
		||||
 | 
				const frameRef = ref<HTMLElement | null>(null); | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				if (unref(currentRoute.meta)?.frameSrc) { | 
			
		||||
 | 
				  frameSrc.value = unref(currentRoute.meta)?.frameSrc as string; | 
			
		||||
 | 
				} | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				function hideLoading() { | 
			
		||||
 | 
				  loading.value = false; | 
			
		||||
 | 
				} | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				function init() { | 
			
		||||
 | 
				  nextTick(() => { | 
			
		||||
 | 
				    const iframe = unref(frameRef); | 
			
		||||
 | 
				    if (!iframe) return; | 
			
		||||
 | 
				    const _frame = iframe as any; | 
			
		||||
 | 
				    if (_frame.attachEvent) { | 
			
		||||
 | 
				      _frame.attachEvent("onload", () => { | 
			
		||||
 | 
				        hideLoading(); | 
			
		||||
 | 
				      }); | 
			
		||||
 | 
				    } else { | 
			
		||||
 | 
				      iframe.onload = () => { | 
			
		||||
 | 
				        hideLoading(); | 
			
		||||
 | 
				      }; | 
			
		||||
 | 
				    } | 
			
		||||
 | 
				  }); | 
			
		||||
 | 
				} | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				onMounted(() => { | 
			
		||||
 | 
				  loading.value = true; | 
			
		||||
 | 
				  init(); | 
			
		||||
 | 
				}); | 
			
		||||
 | 
				</script> | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				<style lang="scss" scoped> | 
			
		||||
 | 
				.frame { | 
			
		||||
 | 
				  height: 100vh; | 
			
		||||
 | 
				  z-index: 998; | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				  .frame-iframe { | 
			
		||||
 | 
				    width: 100%; | 
			
		||||
 | 
				    height: 100%; | 
			
		||||
 | 
				    overflow: hidden; | 
			
		||||
 | 
				    border: 0; | 
			
		||||
 | 
				    box-sizing: border-box; | 
			
		||||
 | 
				  } | 
			
		||||
 | 
				} | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				.main-content { | 
			
		||||
 | 
				  margin: 0 !important; | 
			
		||||
 | 
				} | 
			
		||||
 | 
				</style> | 
			
		||||
@ -0,0 +1,54 @@ | 
			
		|||||
 | 
				interface ProxyLoader { | 
			
		||||
 | 
				  loadCss(src: string): any; | 
			
		||||
 | 
				  loadScript(src: string): Promise<any>; | 
			
		||||
 | 
				  loadScriptConcurrent(src: Array<string>): Promise<any>; | 
			
		||||
 | 
				} | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				class loaderProxy implements ProxyLoader { | 
			
		||||
 | 
				  constructor() {} | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				  protected scriptLoaderCache: Array<string> = []; | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				  public loadCss = (src: string): any => { | 
			
		||||
 | 
				    const element: HTMLLinkElement = document.createElement("link"); | 
			
		||||
 | 
				    element.rel = "stylesheet"; | 
			
		||||
 | 
				    element.href = src; | 
			
		||||
 | 
				    document.body.appendChild(element); | 
			
		||||
 | 
				  }; | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				  public loadScript = async (src: string): Promise<any> => { | 
			
		||||
 | 
				    if (this.scriptLoaderCache.includes(src)) { | 
			
		||||
 | 
				      return src; | 
			
		||||
 | 
				    } else { | 
			
		||||
 | 
				      const element: HTMLScriptElement = document.createElement("script"); | 
			
		||||
 | 
				      element.src = src; | 
			
		||||
 | 
				      document.body.appendChild(element); | 
			
		||||
 | 
				      element.onload = () => { | 
			
		||||
 | 
				        return this.scriptLoaderCache.push(src); | 
			
		||||
 | 
				      }; | 
			
		||||
 | 
				    } | 
			
		||||
 | 
				  }; | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				  public loadScriptConcurrent = async ( | 
			
		||||
 | 
				    srcList: Array<string> | 
			
		||||
 | 
				  ): Promise<any> => { | 
			
		||||
 | 
				    if (Array.isArray(srcList)) { | 
			
		||||
 | 
				      const len: number = srcList.length; | 
			
		||||
 | 
				      if (len > 0) { | 
			
		||||
 | 
				        let count = 0; | 
			
		||||
 | 
				        srcList.map(src => { | 
			
		||||
 | 
				          if (src) { | 
			
		||||
 | 
				            this.loadScript(src).then(() => { | 
			
		||||
 | 
				              count++; | 
			
		||||
 | 
				              if (count === len) { | 
			
		||||
 | 
				                return; | 
			
		||||
 | 
				              } | 
			
		||||
 | 
				            }); | 
			
		||||
 | 
				          } | 
			
		||||
 | 
				        }); | 
			
		||||
 | 
				      } | 
			
		||||
 | 
				    } | 
			
		||||
 | 
				  }; | 
			
		||||
 | 
				} | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				export const loader = new loaderProxy(); | 
			
		||||
@ -0,0 +1,226 @@ | 
			
		|||||
 | 
				interface PrintFunction { | 
			
		||||
 | 
				  extendOptions: Function; | 
			
		||||
 | 
				  getStyle: Function; | 
			
		||||
 | 
				  setDomHeight: Function; | 
			
		||||
 | 
				  toPrint: Function; | 
			
		||||
 | 
				} | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				const Print = function (dom, options?: object): PrintFunction { | 
			
		||||
 | 
				  options = options || {}; | 
			
		||||
 | 
				  // @ts-expect-error
 | 
			
		||||
 | 
				  if (!(this instanceof Print)) return new Print(dom, options); | 
			
		||||
 | 
				  this.conf = { | 
			
		||||
 | 
				    styleStr: "", | 
			
		||||
 | 
				    // Elements that need to dynamically get and set the height
 | 
			
		||||
 | 
				    setDomHeightArr: [], | 
			
		||||
 | 
				    // Echart dom List
 | 
			
		||||
 | 
				    echartDomArr: [], | 
			
		||||
 | 
				    // Callback before printing
 | 
			
		||||
 | 
				    printBeforeFn: null, | 
			
		||||
 | 
				    // Callback after printing
 | 
			
		||||
 | 
				    printDoneCallBack: null | 
			
		||||
 | 
				  }; | 
			
		||||
 | 
				  for (const key in this.conf) { | 
			
		||||
 | 
				    // eslint-disable-next-line no-prototype-builtins
 | 
			
		||||
 | 
				    if (key && options.hasOwnProperty(key)) { | 
			
		||||
 | 
				      this.conf[key] = options[key]; | 
			
		||||
 | 
				    } | 
			
		||||
 | 
				  } | 
			
		||||
 | 
				  if (typeof dom === "string") { | 
			
		||||
 | 
				    this.dom = document.querySelector(dom); | 
			
		||||
 | 
				  } else { | 
			
		||||
 | 
				    this.dom = this.isDOM(dom) ? dom : dom.$el; | 
			
		||||
 | 
				  } | 
			
		||||
 | 
				  if (this.conf.setDomHeightArr && this.conf.setDomHeightArr.length) { | 
			
		||||
 | 
				    this.setDomHeight(this.conf.setDomHeightArr); | 
			
		||||
 | 
				  } | 
			
		||||
 | 
				  this.init(); | 
			
		||||
 | 
				}; | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				Print.prototype = { | 
			
		||||
 | 
				  /** | 
			
		||||
 | 
				   * init | 
			
		||||
 | 
				   */ | 
			
		||||
 | 
				  init: function (): void { | 
			
		||||
 | 
				    const content = this.getStyle() + this.getHtml(); | 
			
		||||
 | 
				    this.writeIframe(content); | 
			
		||||
 | 
				  }, | 
			
		||||
 | 
				  /** | 
			
		||||
 | 
				   * Configuration property extension | 
			
		||||
 | 
				   * @param {Object} obj | 
			
		||||
 | 
				   * @param {Object} obj2 | 
			
		||||
 | 
				   */ | 
			
		||||
 | 
				  extendOptions: function <T>(obj, obj2: T): T { | 
			
		||||
 | 
				    for (const k in obj2) { | 
			
		||||
 | 
				      obj[k] = obj2[k]; | 
			
		||||
 | 
				    } | 
			
		||||
 | 
				    return obj; | 
			
		||||
 | 
				  }, | 
			
		||||
 | 
				  /** | 
			
		||||
 | 
				    Copy all styles of the original page | 
			
		||||
 | 
				  */ | 
			
		||||
 | 
				  getStyle: function (): string { | 
			
		||||
 | 
				    let str = ""; | 
			
		||||
 | 
				    const styles: NodeListOf<Element> = document.querySelectorAll("style,link"); | 
			
		||||
 | 
				    for (let i = 0; i < styles.length; i++) { | 
			
		||||
 | 
				      str += styles[i].outerHTML; | 
			
		||||
 | 
				    } | 
			
		||||
 | 
				    str += `<style>.no-print{display:none;}${this.conf.styleStr}</style>`; | 
			
		||||
 | 
				    return str; | 
			
		||||
 | 
				  }, | 
			
		||||
 | 
				  // form assignment
 | 
			
		||||
 | 
				  getHtml: function (): Element { | 
			
		||||
 | 
				    const inputs = document.querySelectorAll("input"); | 
			
		||||
 | 
				    const selects = document.querySelectorAll("select"); | 
			
		||||
 | 
				    const textareas = document.querySelectorAll("textarea"); | 
			
		||||
 | 
				    for (let k = 0; k < inputs.length; k++) { | 
			
		||||
 | 
				      if (inputs[k].type == "checkbox" || inputs[k].type == "radio") { | 
			
		||||
 | 
				        if (inputs[k].checked == true) { | 
			
		||||
 | 
				          inputs[k].setAttribute("checked", "checked"); | 
			
		||||
 | 
				        } else { | 
			
		||||
 | 
				          inputs[k].removeAttribute("checked"); | 
			
		||||
 | 
				        } | 
			
		||||
 | 
				      } else if (inputs[k].type == "text") { | 
			
		||||
 | 
				        inputs[k].setAttribute("value", inputs[k].value); | 
			
		||||
 | 
				      } else { | 
			
		||||
 | 
				        inputs[k].setAttribute("value", inputs[k].value); | 
			
		||||
 | 
				      } | 
			
		||||
 | 
				    } | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				    for (let k2 = 0; k2 < textareas.length; k2++) { | 
			
		||||
 | 
				      if (textareas[k2].type == "textarea") { | 
			
		||||
 | 
				        textareas[k2].innerHTML = textareas[k2].value; | 
			
		||||
 | 
				      } | 
			
		||||
 | 
				    } | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				    for (let k3 = 0; k3 < selects.length; k3++) { | 
			
		||||
 | 
				      if (selects[k3].type == "select-one") { | 
			
		||||
 | 
				        const child = selects[k3].children; | 
			
		||||
 | 
				        for (const i in child) { | 
			
		||||
 | 
				          if (child[i].tagName == "OPTION") { | 
			
		||||
 | 
				            // @ts-ignore
 | 
			
		||||
 | 
				            if (child[i].selected == true) { | 
			
		||||
 | 
				              child[i].setAttribute("selected", "selected"); | 
			
		||||
 | 
				            } else { | 
			
		||||
 | 
				              child[i].removeAttribute("selected"); | 
			
		||||
 | 
				            } | 
			
		||||
 | 
				          } | 
			
		||||
 | 
				        } | 
			
		||||
 | 
				      } | 
			
		||||
 | 
				    } | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				    return this.dom.outerHTML; | 
			
		||||
 | 
				  }, | 
			
		||||
 | 
				  /** | 
			
		||||
 | 
				    create iframe | 
			
		||||
 | 
				  */ | 
			
		||||
 | 
				  writeIframe: function (content) { | 
			
		||||
 | 
				    let w: Document | Window; | 
			
		||||
 | 
				    let doc: Document; | 
			
		||||
 | 
				    const iframe: HTMLIFrameElement = document.createElement("iframe"); | 
			
		||||
 | 
				    const f: HTMLIFrameElement = document.body.appendChild(iframe); | 
			
		||||
 | 
				    iframe.id = "myIframe"; | 
			
		||||
 | 
				    iframe.setAttribute( | 
			
		||||
 | 
				      "style", | 
			
		||||
 | 
				      "position:absolute;width:0;height:0;top:-10px;left:-10px;" | 
			
		||||
 | 
				    ); | 
			
		||||
 | 
				    // eslint-disable-next-line prefer-const
 | 
			
		||||
 | 
				    w = f.contentWindow || f.contentDocument; | 
			
		||||
 | 
				    // eslint-disable-next-line prefer-const
 | 
			
		||||
 | 
				    doc = f.contentDocument || f.contentWindow.document; | 
			
		||||
 | 
				    doc.open(); | 
			
		||||
 | 
				    doc.write(content); | 
			
		||||
 | 
				    doc.close(); | 
			
		||||
 | 
				    // eslint-disable-next-line @typescript-eslint/no-this-alias
 | 
			
		||||
 | 
				    const _this = this; | 
			
		||||
 | 
				    iframe.onload = function (): void { | 
			
		||||
 | 
				      // Before popping, callback
 | 
			
		||||
 | 
				      if (_this.conf.printBeforeFn) { | 
			
		||||
 | 
				        _this.conf.printBeforeFn({ doc }); | 
			
		||||
 | 
				      } | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				      _this.drawEchartImg(doc).then(() => { | 
			
		||||
 | 
				        _this.toPrint(w); | 
			
		||||
 | 
				        setTimeout(function () { | 
			
		||||
 | 
				          document.body.removeChild(iframe); | 
			
		||||
 | 
				          // After popup, callback
 | 
			
		||||
 | 
				          if (_this.conf.printDoneCallBack) { | 
			
		||||
 | 
				            _this.conf.printDoneCallBack(); | 
			
		||||
 | 
				          } | 
			
		||||
 | 
				        }, 100); | 
			
		||||
 | 
				      }); | 
			
		||||
 | 
				    }; | 
			
		||||
 | 
				  }, | 
			
		||||
 | 
				  /** | 
			
		||||
 | 
				   * echarts printing | 
			
		||||
 | 
				   * @param {Object} doc iframe window | 
			
		||||
 | 
				   */ | 
			
		||||
 | 
				  drawEchartImg(doc): Promise<void> { | 
			
		||||
 | 
				    return new Promise<void>(resolve => { | 
			
		||||
 | 
				      if (this.conf.echartDomArr && this.conf.echartDomArr.length > 0) { | 
			
		||||
 | 
				        this.conf.echartDomArr.forEach(e => { | 
			
		||||
 | 
				          const dom = doc.querySelector("#" + e.$el.id); | 
			
		||||
 | 
				          const img = new Image(); | 
			
		||||
 | 
				          const w = dom.offsetWidth + "px"; | 
			
		||||
 | 
				          const H = dom.offsetHeight + "px"; | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				          img.style.width = w; | 
			
		||||
 | 
				          img.style.height = H; | 
			
		||||
 | 
				          img.src = e.imgSrc; | 
			
		||||
 | 
				          dom.innerHTML = ""; | 
			
		||||
 | 
				          dom.appendChild(img); | 
			
		||||
 | 
				        }); | 
			
		||||
 | 
				      } | 
			
		||||
 | 
				      resolve(); | 
			
		||||
 | 
				    }); | 
			
		||||
 | 
				  }, | 
			
		||||
 | 
				  /** | 
			
		||||
 | 
				    Print | 
			
		||||
 | 
				  */ | 
			
		||||
 | 
				  toPrint: function (frameWindow): void { | 
			
		||||
 | 
				    try { | 
			
		||||
 | 
				      setTimeout(function () { | 
			
		||||
 | 
				        frameWindow.focus(); | 
			
		||||
 | 
				        try { | 
			
		||||
 | 
				          if (!frameWindow.document.execCommand("print", false, null)) { | 
			
		||||
 | 
				            frameWindow.print(); | 
			
		||||
 | 
				          } | 
			
		||||
 | 
				        } catch (e) { | 
			
		||||
 | 
				          frameWindow.print(); | 
			
		||||
 | 
				        } | 
			
		||||
 | 
				        frameWindow.close(); | 
			
		||||
 | 
				      }, 10); | 
			
		||||
 | 
				    } catch (err) { | 
			
		||||
 | 
				      console.error(err); | 
			
		||||
 | 
				    } | 
			
		||||
 | 
				  }, | 
			
		||||
 | 
				  isDOM: | 
			
		||||
 | 
				    typeof HTMLElement === "object" | 
			
		||||
 | 
				      ? function (obj) { | 
			
		||||
 | 
				          return obj instanceof HTMLElement; | 
			
		||||
 | 
				        } | 
			
		||||
 | 
				      : function (obj) { | 
			
		||||
 | 
				          return ( | 
			
		||||
 | 
				            obj && | 
			
		||||
 | 
				            typeof obj === "object" && | 
			
		||||
 | 
				            obj.nodeType === 1 && | 
			
		||||
 | 
				            typeof obj.nodeName === "string" | 
			
		||||
 | 
				          ); | 
			
		||||
 | 
				        }, | 
			
		||||
 | 
				  /** | 
			
		||||
 | 
				   * Set the height of the specified dom element by getting the existing height of the dom element and setting | 
			
		||||
 | 
				   * @param {Array} arr | 
			
		||||
 | 
				   */ | 
			
		||||
 | 
				  setDomHeight(arr) { | 
			
		||||
 | 
				    if (arr && arr.length) { | 
			
		||||
 | 
				      arr.forEach(name => { | 
			
		||||
 | 
				        const domArr = document.querySelectorAll(name); | 
			
		||||
 | 
				        domArr.forEach(dom => { | 
			
		||||
 | 
				          dom.style.height = dom.offsetHeight + "px"; | 
			
		||||
 | 
				        }); | 
			
		||||
 | 
				      }); | 
			
		||||
 | 
				    } | 
			
		||||
 | 
				  } | 
			
		||||
 | 
				}; | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				export default Print; | 
			
		||||
@ -0,0 +1,35 @@ | 
			
		|||||
 | 
				import ResizeObserver from "resize-observer-polyfill"; | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				const isServer = typeof window === "undefined"; | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				const resizeHandler = (entries: any[]): void => { | 
			
		||||
 | 
				  for (const entry of entries) { | 
			
		||||
 | 
				    const listeners = entry.target.__resizeListeners__ || []; | 
			
		||||
 | 
				    if (listeners.length) { | 
			
		||||
 | 
				      listeners.forEach((fn: () => any) => { | 
			
		||||
 | 
				        fn(); | 
			
		||||
 | 
				      }); | 
			
		||||
 | 
				    } | 
			
		||||
 | 
				  } | 
			
		||||
 | 
				}; | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				export const addResizeListener = (element: any, fn: () => any): any => { | 
			
		||||
 | 
				  if (isServer) return; | 
			
		||||
 | 
				  if (!element.__resizeListeners__) { | 
			
		||||
 | 
				    element.__resizeListeners__ = []; | 
			
		||||
 | 
				    element.__ro__ = new ResizeObserver(resizeHandler); | 
			
		||||
 | 
				    element.__ro__.observe(element); | 
			
		||||
 | 
				  } | 
			
		||||
 | 
				  element.__resizeListeners__.push(fn); | 
			
		||||
 | 
				}; | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				export const removeResizeListener = (element: any, fn: () => any): any => { | 
			
		||||
 | 
				  if (!element || !element.__resizeListeners__) return; | 
			
		||||
 | 
				  element.__resizeListeners__.splice( | 
			
		||||
 | 
				    element.__resizeListeners__.indexOf(fn), | 
			
		||||
 | 
				    1 | 
			
		||||
 | 
				  ); | 
			
		||||
 | 
				  if (!element.__resizeListeners__.length) { | 
			
		||||
 | 
				    element.__ro__.disconnect(); | 
			
		||||
 | 
				  } | 
			
		||||
 | 
				}; | 
			
		||||
@ -0,0 +1,116 @@ | 
			
		|||||
 | 
				import { | 
			
		||||
 | 
				  ref, | 
			
		||||
 | 
				  Ref, | 
			
		||||
 | 
				  unref, | 
			
		||||
 | 
				  shallowRef, | 
			
		||||
 | 
				  onBeforeUnmount, | 
			
		||||
 | 
				  getCurrentInstance | 
			
		||||
 | 
				} from "vue"; | 
			
		||||
 | 
				import { isDef } from "/@/utils/is"; | 
			
		||||
 | 
				import { useRafThrottle } from "/@/utils/operate"; | 
			
		||||
 | 
				import { addResizeListener, removeResizeListener } from "/@/utils/resize"; | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				const domSymbol = Symbol("watermark-dom"); | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				type attr = { | 
			
		||||
 | 
				  font?: string; | 
			
		||||
 | 
				  fillStyle?: string; | 
			
		||||
 | 
				}; | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				export function useWatermark( | 
			
		||||
 | 
				  appendEl: Ref<HTMLElement | null> = ref(document.body) as Ref<HTMLElement> | 
			
		||||
 | 
				) { | 
			
		||||
 | 
				  const func = useRafThrottle(function () { | 
			
		||||
 | 
				    const el = unref(appendEl); | 
			
		||||
 | 
				    if (!el) return; | 
			
		||||
 | 
				    const { clientHeight: height, clientWidth: width } = el; | 
			
		||||
 | 
				    updateWatermark({ height, width }); | 
			
		||||
 | 
				  }); | 
			
		||||
 | 
				  const id = domSymbol.toString(); | 
			
		||||
 | 
				  const watermarkEl = shallowRef<HTMLElement>(); | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				  const clear = () => { | 
			
		||||
 | 
				    const domId = unref(watermarkEl); | 
			
		||||
 | 
				    watermarkEl.value = undefined; | 
			
		||||
 | 
				    const el = unref(appendEl); | 
			
		||||
 | 
				    if (!el) return; | 
			
		||||
 | 
				    domId && el.removeChild(domId); | 
			
		||||
 | 
				    removeResizeListener(el, func); | 
			
		||||
 | 
				  }; | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				  function createBase64(str: string, attr?: attr) { | 
			
		||||
 | 
				    const can = document.createElement("canvas"); | 
			
		||||
 | 
				    const width = 300; | 
			
		||||
 | 
				    const height = 240; | 
			
		||||
 | 
				    Object.assign(can, { width, height }); | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				    const cans = can.getContext("2d"); | 
			
		||||
 | 
				    if (cans) { | 
			
		||||
 | 
				      cans.rotate((-20 * Math.PI) / 120); | 
			
		||||
 | 
				      cans.font = attr?.font ?? "15px Reggae One"; | 
			
		||||
 | 
				      cans.fillStyle = attr?.fillStyle ?? "rgba(0, 0, 0, 0.15)"; | 
			
		||||
 | 
				      cans.textAlign = "left"; | 
			
		||||
 | 
				      cans.textBaseline = "middle"; | 
			
		||||
 | 
				      cans.fillText(str, width / 20, height); | 
			
		||||
 | 
				    } | 
			
		||||
 | 
				    return can.toDataURL("image/png"); | 
			
		||||
 | 
				  } | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				  function updateWatermark( | 
			
		||||
 | 
				    options: { | 
			
		||||
 | 
				      width?: number; | 
			
		||||
 | 
				      height?: number; | 
			
		||||
 | 
				      str?: string; | 
			
		||||
 | 
				      attr?: attr; | 
			
		||||
 | 
				    } = {} | 
			
		||||
 | 
				  ) { | 
			
		||||
 | 
				    const el = unref(watermarkEl); | 
			
		||||
 | 
				    if (!el) return; | 
			
		||||
 | 
				    if (isDef(options.width)) { | 
			
		||||
 | 
				      el.style.width = `${options.width}px`; | 
			
		||||
 | 
				    } | 
			
		||||
 | 
				    if (isDef(options.height)) { | 
			
		||||
 | 
				      el.style.height = `${options.height}px`; | 
			
		||||
 | 
				    } | 
			
		||||
 | 
				    if (isDef(options.str)) { | 
			
		||||
 | 
				      el.style.background = `url(${createBase64( | 
			
		||||
 | 
				        options.str, | 
			
		||||
 | 
				        options.attr | 
			
		||||
 | 
				      )}) left top repeat`;
 | 
			
		||||
 | 
				    } | 
			
		||||
 | 
				  } | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				  const createWatermark = (str: string, attr?: attr) => { | 
			
		||||
 | 
				    if (unref(watermarkEl)) { | 
			
		||||
 | 
				      updateWatermark({ str, attr }); | 
			
		||||
 | 
				      return id; | 
			
		||||
 | 
				    } | 
			
		||||
 | 
				    const div = document.createElement("div"); | 
			
		||||
 | 
				    watermarkEl.value = div; | 
			
		||||
 | 
				    div.id = id; | 
			
		||||
 | 
				    div.style.pointerEvents = "none"; | 
			
		||||
 | 
				    div.style.top = "0px"; | 
			
		||||
 | 
				    div.style.left = "0px"; | 
			
		||||
 | 
				    div.style.position = "absolute"; | 
			
		||||
 | 
				    div.style.zIndex = "100000"; | 
			
		||||
 | 
				    const el = unref(appendEl); | 
			
		||||
 | 
				    if (!el) return id; | 
			
		||||
 | 
				    const { clientHeight: height, clientWidth: width } = el; | 
			
		||||
 | 
				    updateWatermark({ str, width, height, attr }); | 
			
		||||
 | 
				    el.appendChild(div); | 
			
		||||
 | 
				    return id; | 
			
		||||
 | 
				  }; | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				  function setWatermark(str: string, attr?: attr) { | 
			
		||||
 | 
				    createWatermark(str, attr); | 
			
		||||
 | 
				    addResizeListener(document.documentElement, func); | 
			
		||||
 | 
				    const instance = getCurrentInstance(); | 
			
		||||
 | 
				    if (instance) { | 
			
		||||
 | 
				      onBeforeUnmount(() => { | 
			
		||||
 | 
				        clear(); | 
			
		||||
 | 
				      }); | 
			
		||||
 | 
				    } | 
			
		||||
 | 
				  } | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				  return { setWatermark, clear }; | 
			
		||||
 | 
				} | 
			
		||||
						Write
						Preview
					
					
					Loading…
					
					Cancel
						Save
					
		Reference in new issue