浏览代码

feat:添加水印组件

ai0182 4 月之前
父节点
当前提交
7707c57d7c
共有 5 个文件被更改,包括 184 次插入11 次删除
  1. 2 2
      public/app.config.js
  2. 22 0
      src/App.vue
  3. 1 8
      src/components/Nav.vue
  4. 156 0
      src/components/Waterwrapper.vue
  5. 3 1
      src/main.ts

+ 2 - 2
public/app.config.js

@@ -5,9 +5,9 @@ window.__PRODUCTION__SKYEYEADMIN__CONF__ = {
   // 接口前缀
   VITE_GLOB_API_URL_PREFIX: './safety_api/api',
 
-  VITE_GLOB_SKYEYE_PLATFORM: "https://wwww.baidu.com",
+  VITE_GLOB_SKYEYE_PLATFORM: "http://wwww.baidu.com",
 
-  VITE_GLOB_TIANSUO_PLATFORM: "https://www.bing.com"
+  VITE_GLOB_TIANSUO_PLATFORM: "http://www.bing.com"
 
 };
 

+ 22 - 0
src/App.vue

@@ -1,5 +1,15 @@
 <template>
   <div id="app">
+     <WatermarkWrapper 
+     v-if="username"
+      :isFixedScreen="isFixedScreen"
+      position="fixed"
+      width="100vw"
+      height="100vh"
+      :zIndex="999"
+      :username="username"
+      :realname="realname"
+    />
     <Nav v-if="!isFixedScreen" />
     <div class="content" :class="{ 'fixed-screen': isFixedScreen }">
       <router-view />
@@ -11,7 +21,19 @@
   import { useRoute } from 'vue-router';
   import { computed } from 'vue';
   import Nav from '@/components/Nav.vue';
+  import WatermarkWrapper from '@/components/Waterwrapper.vue'
 
+import { storeToRefs } from 'pinia';
+import { useUserStore } from '@/store/modules/user';
+
+const userStore = useUserStore();
+const { getUserInfo } = storeToRefs(userStore);
+
+const username = computed(() => getUserInfo.value.username);
+const realname = computed(() => getUserInfo.value.realname);
+
+
+  
   const route = useRoute();
   const isFixedScreen = computed(
     () => route.matched.some((r) => r.meta?.fixedScreen === true) || route.path.startsWith('/institute-safety'),

+ 1 - 8
src/components/Nav.vue

@@ -11,13 +11,6 @@
 
     <SwitchTenant v-if="userStore.info.tenantId === SYS_TENANT_ID" />
     <div class="platform__right">
-      <!-- <div class="platform__right__search">
-        <el-input v-model="searchValue" placeholder="搜索您想了解的" class="input-with-icon" clearable>
-          <template #prepend>
-            <img :src="searchIcon" alt="search" class="search-icon" @click="handleSearch" />
-          </template>
-</el-input>
-</div> -->
       <div class="platform__right__login">
         <span @click="userStore.showLogin = true" v-if="!userStore.info?.id">登录</span>
         <UserInfo v-else />
@@ -59,7 +52,7 @@ const handleSearch = () => {
 const currentRoute = useRoute();
 const { title } = useGlobSetting();
 
-const handleNavClick = (item: { name: string; path: string; isRedrect: boolean }) => {
+const handleNavClick = (item: { name: string; path: string; isRedrect?: boolean }) => {
 
   if (!item.path) {
     router.replace({ name: 'StayTune' });

+ 156 - 0
src/components/Waterwrapper.vue

@@ -0,0 +1,156 @@
+<template>
+  <!-- 水印容器:根据传入的 props 适配全局/局部水印 -->
+  <div 
+    class="watermark-wrapper"
+    :style="{
+      position: position,
+      top: 0,
+      left: 0,
+      width: width,
+      height: height,
+      zIndex: zIndex,
+      pointerEvents: 'none' // 核心:不遮挡交互
+    }"
+  ></div>
+</template>
+
+<script setup>
+import { ref, onMounted, onUnmounted, watch } from 'vue';
+// import {useUserInfoHook} from '@/hooks/useUserInfoHook'
+
+// 定义组件 props
+const props = defineProps({
+  // 定位方式:fixed(全局)/ absolute(局部)
+  position: {
+    type: String,
+    default: 'fixed',
+    validator: (val) => ['fixed', 'absolute'].includes(val)
+  },
+  // 宽度:全局用 100vw,局部用 100%
+  width: {
+    type: String,
+    default: '100vw'
+  },
+  // 高度:全局用 100vh,局部用 100%
+  height: {
+    type: String,
+    default: '100vh'
+  },
+  // 层级:默认 999(低于 el-dialog 的 2000)
+  zIndex: {
+    type: Number,
+    default: 999
+  },
+  // 是否固定屏幕模式(适配你的业务逻辑)
+  isFixedScreen: {
+    type: Boolean,
+    default: false
+  },
+  username:{
+    type: String,
+  },
+    realname:{
+    type: String,
+  }
+});
+
+// 移除水印的方法引用
+let removeWatermarkFn = null;
+
+// 获取用户仓库
+
+// const {realname,staffNo} = useUserInfoHook();
+// 生成水印的核心方法
+const createWatermark = () => {
+  
+  // 未登录/无用户信息时不生成水印
+  if (!props.username || !props.realname) return;
+
+  // 拼接水印文本
+  const watermarkText = `${props.username}-${props.realname}`;
+
+  // 1. 创建 Canvas 绘制水印
+  const canvas = document.createElement('canvas');
+  const ctx = canvas.getContext('2d');
+  if (!ctx) return;
+
+  // 配置水印样式
+  const font = '16px Microsoft YaHei';
+  const color = 'rgba(64, 158, 255, 0.15)';
+  const rotate = -15;
+
+  // 计算文本尺寸
+  ctx.font = font;
+  const textWidth = ctx.measureText(watermarkText).width;
+  canvas.width = textWidth + 120; // 水平间距
+  canvas.height = textWidth + 80; // 垂直间距
+
+  // 绘制水印
+  ctx.font = font;
+  ctx.fillStyle = color;
+  ctx.rotate((rotate * Math.PI) / 180); // 角度转弧度
+  ctx.fillText(watermarkText, 0, canvas.height / 2);
+
+  // 2. 生成 Base64 图片
+  const watermarkBase64 = canvas.toDataURL('image/png');
+
+  // 3. 给水印容器设置背景
+  const wrapper = document.querySelector('.watermark-wrapper');
+  if (wrapper) {
+    wrapper.style.backgroundImage = `url(${watermarkBase64})`;
+    wrapper.style.backgroundRepeat = 'repeat';
+    wrapper.style.backgroundSize = `${canvas.width}px ${canvas.height}px`;
+  }
+};
+
+// 移除水印
+const removeWatermark = () => {
+  const wrapper = document.querySelector('.watermark-wrapper');
+  if (wrapper) {
+    wrapper.style.backgroundImage = 'none';
+  }
+};
+
+// 监听用户信息变化(登录/退出时重新生成水印)
+// watch(
+//   () => userId,
+//   () => {
+//     removeWatermark();
+//     createWatermark();
+//   },
+//   { immediate: true, deep: true }
+// );
+
+// 监听 isFixedScreen 变化,适配布局
+// watch(
+//   () => props.isFixedScreen,
+//   () => {
+//     removeWatermark();
+//     createWatermark();
+//   }
+// );
+
+// 页面挂载时生成水印
+onMounted(() => {
+  createWatermark();
+});
+
+// 页面销毁时移除水印
+onUnmounted(() => {
+  removeWatermark();
+  if (removeWatermarkFn) {
+    removeWatermarkFn();
+  }
+});
+</script>
+
+<style scoped>
+.watermark-wrapper {
+    width: 100vw;
+    height: 100vh;
+  margin: 0;
+  padding: 0;
+  border: none;
+  background: transparent;
+}
+</style>

+ 3 - 1
src/main.ts

@@ -18,10 +18,12 @@ dayjs.locale('zh-cn');
 
 async function bootstrap() {
   const app = createApp(App);
+  
   app.use(notivue);
-
+   
   // 全局完整引入 element 组件
   setupElement(app);
+
   app.component('BreadcrumbBack', BreadcrumbBack); //全局注册面包屑返回按钮
 
   // 注册全局自定义指令,如:v-permission权限指令