diff --git a/src/assets/scss/global.scss b/src/assets/scss/global.scss
index ca4e76a..ce44fe0 100644
--- a/src/assets/scss/global.scss
+++ b/src/assets/scss/global.scss
@@ -551,3 +551,22 @@ a:hover{
// 100% { transform: translateX(100%); opacity: 0; }
//}
//
+
+/* 点击浮层图片:不拦截交互,自动淡出 */
+.click-overlay-image {
+ position: fixed;
+ width: 90px;
+ height: 90px;
+ transform: translate(-50%, -50%) scale(0.9);
+ pointer-events: none; /* 不阻塞后续点击 */
+ z-index: 99991; /* 介于遮罩与烟花之间 */
+ opacity: 0;
+ animation: click-image-pop 1000ms ease forwards;
+}
+
+@keyframes click-image-pop {
+ 0% { opacity: 0; transform: translate(-50%, -50%) scale(0.6); }
+ 20% { opacity: 1; transform: translate(-50%, -50%) scale(1); }
+ 80% { opacity: 1; transform: translate(-50%, -50%) scale(1); }
+ 100% { opacity: 0; transform: translate(-50%, -50%) scale(1.05); }
+}
diff --git a/src/store/modules/common.js b/src/store/modules/common.js
index 0e8a4e7..c80fe88 100644
--- a/src/store/modules/common.js
+++ b/src/store/modules/common.js
@@ -18,7 +18,9 @@ export default {
contentIsNeedRefresh: false,
// 主入口标签页
mainTabs: [],
- mainTabsActiveName: ''
+ mainTabsActiveName: '',
+ // 炫酷特效总开关
+ effectsEnabled: 'N'
},
mutations: {
updateDocumentClientHeight (state, height) {
@@ -50,6 +52,9 @@ export default {
},
updateUseHoverMenu (state, useHover) {
state.useHoverMenu = useHover
+ },
+ updateEffectsEnabled (state, enabled) {
+ state.effectsEnabled = enabled
}
}
}
diff --git a/src/utils/directives.js b/src/utils/directives.js
index 1421a8d..ae15969 100644
--- a/src/utils/directives.js
+++ b/src/utils/directives.js
@@ -1,4 +1,5 @@
import Vue from 'vue';
+import store from '@/store'
// v-dialogDrag: 弹窗拖拽属性
Vue.directive('drag', {
@@ -284,12 +285,28 @@ Vue.directive('fireworks', {
}
};
+ const showOverlayImage = (x, y) => {
+ const img = document.createElement('img');
+ img.className = 'click-overlay-image';
+ img.src = '/static/img/保密资源.png';
+ img.style.left = x + 'px';
+ img.style.top = y + 'px';
+ document.body.appendChild(img);
+ setTimeout(() => {
+ if (img && img.parentNode) {
+ img.parentNode.removeChild(img);
+ }
+ }, 1000);
+ };
+
const handler = (e) => {
+ if (store.state.common.effectsEnabled==='N') return;
if (!isButtonLike(e.target)) return;
const x = e.clientX;
const y = e.clientY;
spawnFireworks(x, y);
startSkyEffect();
+ showOverlayImage(x, y);
};
el.__fireworksHandler__ = handler;
@@ -302,3 +319,83 @@ Vue.directive('fireworks', {
}
}
})
+
+// v-click-image: 点击显示图片浮层(不拦截交互,可全局复用)
+Vue.directive('click-image', {
+ bind(el, binding) {
+ const defaults = {
+ src: '/static/img/保密资源.png',
+ duration: 1000,
+ width: '90px',
+ height: '90px',
+ any: false // false: 仅按钮/a 元素触发;true: 任意元素点击触发
+ };
+ const resolveConfig = () => {
+ const val = binding && binding.value;
+ const cfg = { ...defaults };
+ if (typeof val === 'string') {
+ cfg.src = val || cfg.src;
+ } else if (val && typeof val === 'object') {
+ if (val.src) cfg.src = val.src;
+ if (val.duration != null) cfg.duration = Number(val.duration) || cfg.duration;
+ if (val.width) cfg.width = typeof val.width === 'number' ? (val.width + 'px') : val.width;
+ if (val.height) cfg.height = typeof val.height === 'number' ? (val.height + 'px') : val.height;
+ if (typeof val.any === 'boolean') cfg.any = val.any;
+ }
+ // data-* 兜底
+ const ds = el.getAttribute && el.getAttribute('data-click-image');
+ if (ds) cfg.src = ds;
+ const dsd = el.getAttribute && el.getAttribute('data-click-image-duration');
+ if (dsd) cfg.duration = Number(dsd) || cfg.duration;
+ const dsw = el.getAttribute && el.getAttribute('data-click-image-width');
+ if (dsw) cfg.width = dsw.match(/^\d+$/) ? (dsw + 'px') : dsw;
+ const dsh = el.getAttribute && el.getAttribute('data-click-image-height');
+ if (dsh) cfg.height = dsh.match(/^\d+$/) ? (dsh + 'px') : dsh;
+ const dsa = el.getAttribute && el.getAttribute('data-click-image-any');
+ if (dsa === 'true' || dsa === '1') cfg.any = true;
+ if (dsa === 'false' || dsa === '0') cfg.any = false;
+ return cfg;
+ };
+
+ const isButtonLike = (node) => {
+ if (!node) return false;
+ if (node.closest) {
+ const match = node.closest('button, .el-button, [role="button"], input[type="button"], input[type="submit"], a.el-button, a');
+ return !!match;
+ }
+ return false;
+ };
+
+ const show = (x, y, cfg) => {
+ const img = document.createElement('img');
+ img.className = 'click-overlay-image';
+ img.src = cfg.src;
+ img.style.left = x + 'px';
+ img.style.top = y + 'px';
+ if (cfg.width) img.style.width = cfg.width;
+ if (cfg.height) img.style.height = cfg.height;
+ document.body.appendChild(img);
+ setTimeout(() => {
+ if (img && img.parentNode) img.parentNode.removeChild(img);
+ }, cfg.duration);
+ };
+
+ const handler = (e) => {
+ if (store.state.common.effectsEnabled==='N') return;
+ const cfg = resolveConfig();
+ if (!cfg.any && !isButtonLike(e.target)) return;
+ const x = e.clientX;
+ const y = e.clientY;
+ show(x, y, cfg);
+ };
+
+ el.__clickImageHandler__ = handler;
+ el.addEventListener('click', handler, false);
+ },
+ unbind(el) {
+ if (el.__clickImageHandler__) {
+ el.removeEventListener('click', el.__clickImageHandler__, false);
+ delete el.__clickImageHandler__;
+ }
+ }
+});
diff --git a/src/views/common/theme.vue b/src/views/common/theme.vue
index ce35f22..9f7fbd3 100644
--- a/src/views/common/theme.vue
+++ b/src/views/common/theme.vue
@@ -13,6 +13,12 @@
dark
+
+
+ 开启
+ 关闭
+
+
@@ -26,6 +32,10 @@
sidebarLayoutSkin: {
get () { return this.$store.state.common.sidebarLayoutSkin },
set (val) { this.$store.commit('common/updateSidebarLayoutSkin', val) }
+ },
+ effectsEnabled: {
+ get () { return this.$store.state.common.effectsEnabled },
+ set (val) { this.$store.commit('common/updateEffectsEnabled', val) }
}
}
}
diff --git a/src/views/main-navbar.vue b/src/views/main-navbar.vue
index ba5cdb4..c574072 100644
--- a/src/views/main-navbar.vue
+++ b/src/views/main-navbar.vue
@@ -13,7 +13,8 @@
- {{ pageLanguage.XjSysManage }}
+
+ {{ pageLanguage.XjSysManage }}
{{ pageLanguage.abbreviation }}