From be1cd9e5b30097ca427a9c2b7b054b28854e410a Mon Sep 17 00:00:00 2001
From: Junjie <fallin.jie@qq.com>
Date: 星期三, 11 三月 2026 13:21:36 +0800
Subject: [PATCH] #
---
src/main/webapp/views/index.html | 472 ++++++++++++++++++++++++++++++++++++++++------------------
1 files changed, 321 insertions(+), 151 deletions(-)
diff --git a/src/main/webapp/views/index.html b/src/main/webapp/views/index.html
index 9a51064..37d8d39 100644
--- a/src/main/webapp/views/index.html
+++ b/src/main/webapp/views/index.html
@@ -37,12 +37,25 @@
}
.layout-aside {
+ position: relative;
+ flex-shrink: 0;
display: flex;
flex-direction: column;
overflow: hidden;
border-radius: 16px;
background: linear-gradient(180deg, #16324d 0%, #0d2237 100%);
box-shadow: 0 14px 32px rgba(22, 50, 77, 0.18);
+ transform: translateZ(0);
+ backface-visibility: hidden;
+ will-change: width;
+ transition: width 0.22s cubic-bezier(0.22, 1, 0.36, 1),
+ box-shadow 0.22s ease;
+ -webkit-user-select: none;
+ user-select: none;
+ }
+
+ .layout-aside.is-animating {
+ pointer-events: none;
}
.layout-panel {
@@ -55,6 +68,8 @@
background: #f5f7fa;
box-shadow: 0 14px 32px rgba(83, 104, 129, 0.12);
border: 1px solid #e4eaf2;
+ transform: translateZ(0);
+ backface-visibility: hidden;
}
.aside-logo {
@@ -66,6 +81,8 @@
box-sizing: border-box;
color: #fff;
border-bottom: 1px solid rgba(255, 255, 255, 0.08);
+ transition: min-height 0.22s cubic-bezier(0.22, 1, 0.36, 1),
+ padding 0.22s cubic-bezier(0.22, 1, 0.36, 1);
}
.aside-logo-image {
@@ -74,6 +91,8 @@
max-width: 178px;
height: auto;
object-fit: contain;
+ transform: translateZ(0);
+ transition: max-width 0.22s cubic-bezier(0.22, 1, 0.36, 1);
}
.aside-logo.is-collapse {
@@ -90,12 +109,25 @@
box-sizing: border-box;
}
+ .aside-fade-enter-active,
+ .aside-fade-leave-active {
+ transition: opacity 0.14s ease, transform 0.18s ease;
+ }
+
+ .aside-fade-enter,
+ .aside-fade-leave-to {
+ opacity: 0;
+ transform: translate3d(-10px, 0, 0);
+ }
+
.aside-search .el-input__inner {
height: 36px;
line-height: 36px;
border: 1px solid rgba(255, 255, 255, 0.10);
background: rgba(255, 255, 255, 0.08);
color: #fff;
+ -webkit-user-select: text;
+ user-select: text;
}
.aside-search .el-input__inner::placeholder {
@@ -109,6 +141,7 @@
.aside-scroll {
flex: 1;
min-height: 0;
+ transform: translateZ(0);
}
.aside-scroll .el-scrollbar__wrap {
@@ -118,6 +151,7 @@
.side-menu {
border-right: none;
background: transparent;
+ transform: translateZ(0);
}
.side-menu .el-submenu__title,
@@ -127,6 +161,7 @@
margin: 0 10px 6px;
border-radius: 10px;
box-sizing: border-box;
+ backface-visibility: hidden;
}
.side-menu .el-submenu__title:hover,
@@ -384,6 +419,8 @@
background: #fff;
border-bottom: 1px solid #e8edf5;
box-sizing: border-box;
+ -webkit-user-select: none;
+ user-select: none;
}
.page-tabs {
@@ -402,6 +439,8 @@
.page-tabs .el-tabs__item {
height: 38px;
line-height: 38px;
+ -webkit-user-select: none;
+ user-select: none;
}
.tabs-tools {
@@ -410,6 +449,8 @@
gap: 8px;
padding-bottom: 6px;
flex-shrink: 0;
+ -webkit-user-select: none;
+ user-select: none;
}
.content-main {
@@ -468,45 +509,10 @@
word-break: break-word;
}
- @keyframes slideInRight {
- from {
- transform: translate3d(100%, 0, 0);
- opacity: 0;
- }
-
- to {
- transform: translate3d(0, 0, 0);
- opacity: 1;
- }
- }
-
- @keyframes slideOutRight {
- from {
- transform: translate3d(0, 0, 0);
- opacity: 1;
- }
-
- to {
- transform: translate3d(100%, 0, 0);
- opacity: 0;
- }
- }
-
@keyframes asideSkeletonShimmer {
100% {
transform: translateX(100%);
}
- }
-
- .ai-drawer-layer {
- box-shadow: -8px 0 24px rgba(0, 0, 0, 0.15) !important;
- border-radius: 8px 0 0 8px !important;
- overflow: hidden;
- animation: slideInRight 0.5s cubic-bezier(0.16, 1, 0.3, 1);
- }
-
- .ai-drawer-layer-close {
- animation: slideOutRight 0.4s cubic-bezier(0.16, 1, 0.3, 1) forwards !important;
}
.ai-assistant-btn {
@@ -515,6 +521,87 @@
bottom: 40px;
z-index: 9999;
cursor: pointer;
+ }
+
+ .ai-assistant-mask {
+ position: fixed;
+ inset: 0;
+ z-index: 9997;
+ background: rgba(15, 23, 42, 0.10);
+ backdrop-filter: blur(3px);
+ }
+
+ .ai-assistant-drawer {
+ position: fixed;
+ top: 0;
+ right: 0;
+ z-index: 9998;
+ width: min(600px, 100vw);
+ height: 100vh;
+ display: flex;
+ flex-direction: column;
+ background: #fff;
+ border-radius: 12px 0 0 12px;
+ box-shadow: -10px 0 28px rgba(15, 23, 42, 0.18);
+ overflow: hidden;
+ }
+
+ .ai-drawer-header {
+ height: 54px;
+ padding: 0 16px 0 20px;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ border-bottom: 1px solid rgba(226, 232, 240, 0.92);
+ background: rgba(248, 251, 255, 0.96);
+ color: #243447;
+ font-size: 15px;
+ font-weight: 700;
+ box-sizing: border-box;
+ }
+
+ .ai-drawer-close {
+ width: 32px;
+ height: 32px;
+ border: none;
+ border-radius: 10px;
+ background: transparent;
+ color: #5f7084;
+ cursor: pointer;
+ font-size: 16px;
+ }
+
+ .ai-drawer-close:hover {
+ background: rgba(236, 243, 249, 0.92);
+ color: #24405c;
+ }
+
+ .ai-drawer-frame {
+ flex: 1;
+ width: 100%;
+ border: none;
+ background: #fff;
+ }
+
+ .ai-mask-enter-active,
+ .ai-mask-leave-active {
+ transition: opacity .22s ease;
+ }
+
+ .ai-mask-enter,
+ .ai-mask-leave-to {
+ opacity: 0;
+ }
+
+ .ai-panel-enter-active,
+ .ai-panel-leave-active {
+ transition: transform .28s cubic-bezier(0.22, 1, 0.36, 1), opacity .22s ease;
+ }
+
+ .ai-panel-enter,
+ .ai-panel-leave-to {
+ transform: translate3d(100%, 0, 0);
+ opacity: 0;
}
@media (max-width: 1440px) {
@@ -533,20 +620,25 @@
<body>
<div id="app" v-cloak>
<el-container class="shell-container">
- <el-aside class="layout-aside" :width="asideWidth">
- <div class="aside-logo" :class="{ 'is-collapse': isCollapse }">
+ <el-aside
+ class="layout-aside"
+ :class="{ 'is-animating': collapseAnimating }"
+ :width="asideWidth">
+ <div class="aside-logo" :class="{ 'is-collapse': asideCompact }">
<img class="aside-logo-image" src="../static/images/zy-logo.png" alt="娴欐睙涓壃">
</div>
- <div class="aside-search" v-show="!isCollapse">
- <el-input
- v-model.trim="menuKeyword"
- size="small"
- clearable
- prefix-icon="el-icon-search"
- :placeholder="t('index.searchMenu')">
- </el-input>
- </div>
+ <transition name="aside-fade">
+ <div class="aside-search" v-show="showAsideExtras">
+ <el-input
+ v-model.trim="menuKeyword"
+ size="small"
+ clearable
+ prefix-icon="el-icon-search"
+ :placeholder="t('index.searchMenu')">
+ </el-input>
+ </div>
+ </transition>
<el-scrollbar class="aside-scroll">
<div v-if="menuLoading" class="aside-loading" aria-hidden="true">
@@ -562,7 +654,7 @@
ref="sideMenu"
class="side-menu"
:default-active="activeMenuKey"
- :collapse="isCollapse"
+ :collapse="menuCollapse"
:collapse-transition="false"
:default-openeds="defaultOpeneds"
unique-opened
@@ -596,19 +688,21 @@
</template>
</el-scrollbar>
- <div class="aside-footer" v-show="!isCollapse">
- <div class="aside-footer-copy">漏 2026 {{ t('app.company') }}</div>
- <div class="aside-footer-version">
- <span class="aside-footer-version-text">{{ versionText }}</span>
- <el-tag
- v-if="versionType"
- size="mini"
- :type="versionTagType"
- effect="dark">
- {{ versionTypeTag }}
- </el-tag>
+ <transition name="aside-fade">
+ <div class="aside-footer" v-show="showAsideExtras">
+ <div class="aside-footer-copy">漏 2026 {{ t('app.company') }}</div>
+ <div class="aside-footer-version">
+ <span class="aside-footer-version-text">{{ versionText }}</span>
+ <el-tag
+ v-if="versionType"
+ size="mini"
+ :type="versionTagType"
+ effect="dark">
+ {{ versionTypeTag }}
+ </el-tag>
+ </div>
</div>
- </div>
+ </transition>
</el-aside>
<el-container class="layout-panel">
@@ -728,18 +822,43 @@
</span>
</el-dialog>
- <div
- id="ai-assistant-btn"
- class="ai-assistant-btn"
- @mouseenter="showAiTip"
- @mouseleave="hideAiTip"
- @click="openAiAssistant">
- </div>
+ <el-tooltip :content="t('common.aiAssistant')" placement="left">
+ <div
+ id="ai-assistant-btn"
+ class="ai-assistant-btn"
+ @click="openAiAssistant">
+ </div>
+ </el-tooltip>
+
+ <transition name="ai-mask">
+ <div
+ v-if="aiAssistantVisible"
+ class="ai-assistant-mask"
+ @click="closeAiAssistant">
+ </div>
+ </transition>
+
+ <transition name="ai-panel">
+ <div
+ v-if="aiAssistantVisible"
+ class="ai-assistant-drawer">
+ <div class="ai-drawer-header">
+ <span>{{ t('common.aiAssistant') }}</span>
+ <button type="button" class="ai-drawer-close" @click="closeAiAssistant">
+ <i class="el-icon-close"></i>
+ </button>
+ </div>
+ <iframe
+ v-if="aiAssistantMounted"
+ class="ai-drawer-frame"
+ :src="aiAssistantSrc">
+ </iframe>
+ </div>
+ </transition>
</div>
<script type="text/javascript" src="../static/js/jquery/jquery-3.3.1.min.js"></script>
-<script type="text/javascript" src="../static/js/layer/layer.js"></script>
-<script type="text/javascript" src="../static/js/common.js?v=20260309_i18n_fix1"></script>
+<script type="text/javascript" src="../static/js/common.js"></script>
<script type="text/javascript" src="../static/vue/js/vue.min.js"></script>
<script type="text/javascript" src="../static/vue/element/element.js"></script>
<script>
@@ -757,6 +876,8 @@
group: "璐︽埛涓績",
menuKey: ""
};
+ var SIDEBAR_TRANSITION_MS = 220;
+ var SIDEBAR_EXPAND_CONTENT_DELAY = 180;
var TAB_STORAGE_KEY = "wcs-element-home-tabs";
var USER_STORAGE_KEY = "username";
var INDEX_I18N_FALLBACKS = {
@@ -800,6 +921,11 @@
data: function () {
return {
isCollapse: false,
+ asideCompact: false,
+ menuCollapse: false,
+ showAsideExtras: true,
+ collapseAnimating: false,
+ collapseTimer: null,
menuLoading: true,
pageLoading: true,
loadingText: window.WCS_I18N ? window.WCS_I18N.tl("姝e湪鍔犺浇椤甸潰...") : "姝e湪鍔犺浇椤甸潰...",
@@ -822,13 +948,14 @@
menuSyncVersion: 0,
menuSyncTimer: null,
userName: localStorage.getItem(USER_STORAGE_KEY) || (window.WCS_I18N ? window.WCS_I18N.tl("绠$悊鍛�") : "绠$悊鍛�"),
- aiLayerIndex: null,
- aiTipIndex: null
+ aiAssistantVisible: false,
+ aiAssistantMounted: false,
+ aiAssistantSrc: baseUrl + "/views/ai/diagnosis.html"
};
},
computed: {
asideWidth: function () {
- return this.isCollapse ? "72px" : "248px";
+ return this.asideCompact ? "72px" : "248px";
},
filteredMenus: function () {
var keyword = (this.menuKeyword || "").toLowerCase();
@@ -962,9 +1089,9 @@
clearTimeout(this.menuSyncTimer);
this.menuSyncTimer = null;
}
- if (this.aiTipIndex) {
- layer.close(this.aiTipIndex);
- this.aiTipIndex = null;
+ if (this.collapseTimer) {
+ clearTimeout(this.collapseTimer);
+ this.collapseTimer = null;
}
},
methods: {
@@ -1009,17 +1136,7 @@
PROFILE_TAB_CONFIG.title = profileConfig.title;
PROFILE_TAB_CONFIG.group = profileConfig.group;
for (i = 0; i < this.tabs.length; i++) {
- if (this.isHomeTabUrl(this.tabs[i].url)) {
- this.tabs[i].title = homeConfig.title;
- this.tabs[i].group = homeConfig.group;
- this.tabs[i].home = true;
- } else if (this.resolveViewSrc(this.tabs[i].url) === this.resolveViewSrc(profileConfig.url)) {
- this.tabs[i].title = profileConfig.title;
- this.tabs[i].group = profileConfig.group;
- } else {
- this.tabs[i].title = this.translateTabTitle(this.tabs[i].title);
- this.tabs[i].group = this.tl(this.tabs[i].group);
- }
+ this.syncTabMeta(this.tabs[i], homeConfig, profileConfig);
}
this.updateDocumentTitle(this.activeTabTitle);
this.persistTabs();
@@ -1056,6 +1173,56 @@
},
translateTabTitle: function (title) {
return this.tl(title);
+ },
+ findMenuMeta: function (tab) {
+ var normalizedUrl;
+ var i;
+ var j;
+ var group;
+ var item;
+ if (!tab) {
+ return null;
+ }
+ normalizedUrl = this.resolveViewSrc(tab.url);
+ for (i = 0; i < this.menus.length; i++) {
+ group = this.menus[i];
+ for (j = 0; j < group.subMenu.length; j++) {
+ item = group.subMenu[j];
+ if ((tab.menuKey && item.tabKey === tab.menuKey) || item.url === normalizedUrl) {
+ return {
+ group: group,
+ item: item
+ };
+ }
+ }
+ }
+ return null;
+ },
+ syncTabMeta: function (tab, homeConfig, profileConfig) {
+ var menuMeta;
+ if (!tab) {
+ return;
+ }
+ if (this.isHomeTabUrl(tab.url)) {
+ tab.title = homeConfig.title;
+ tab.group = homeConfig.group;
+ tab.home = true;
+ return;
+ }
+ if (this.resolveViewSrc(tab.url) === this.resolveViewSrc(profileConfig.url)) {
+ tab.title = profileConfig.title;
+ tab.group = profileConfig.group;
+ return;
+ }
+ menuMeta = this.findMenuMeta(tab);
+ if (menuMeta) {
+ tab.title = menuMeta.item.name;
+ tab.group = menuMeta.group.menu;
+ tab.menuKey = menuMeta.item.tabKey || tab.menuKey;
+ return;
+ }
+ tab.title = this.translateTabTitle(tab.title);
+ tab.group = this.tl(tab.group);
},
updateDocumentTitle: function (title) {
document.title = title + " - " + this.t("app.title");
@@ -1346,7 +1513,7 @@
script = frameDocument.createElement("script");
script.id = "wcs-i18n-bridge-script";
script.type = "text/javascript";
- script.src = baseUrl + "/static/js/common.js?v=20260309_i18n_fix1";
+ script.src = baseUrl + "/static/js/common.js";
script.onload = applyFrameI18n;
frameDocument.head.appendChild(script);
},
@@ -1356,8 +1523,65 @@
this.syncFrameI18n(this.tabs[i].name);
}
},
+ clearCollapseTimer: function () {
+ if (this.collapseTimer) {
+ clearTimeout(this.collapseTimer);
+ this.collapseTimer = null;
+ }
+ },
+ nextFrame: function (callback) {
+ if (window.requestAnimationFrame) {
+ window.requestAnimationFrame(function () {
+ callback();
+ });
+ return;
+ }
+ setTimeout(callback, 16);
+ },
+ finishCollapseStage: function (callback, delay) {
+ var that = this;
+ this.clearCollapseTimer();
+ this.collapseTimer = setTimeout(function () {
+ that.collapseTimer = null;
+ callback();
+ }, delay);
+ },
toggleCollapse: function () {
- this.isCollapse = !this.isCollapse;
+ var that = this;
+
+ if (this.collapseAnimating) {
+ return;
+ }
+
+ this.collapseAnimating = true;
+
+ if (this.isCollapse) {
+ this.isCollapse = false;
+ this.asideCompact = false;
+ this.nextFrame(function () {
+ that.finishCollapseStage(function () {
+ that.menuCollapse = false;
+ that.showAsideExtras = true;
+ that.collapseAnimating = false;
+ that.$nextTick(function () {
+ that.syncMenuStateByUrl(that.activeTabUrl);
+ });
+ }, SIDEBAR_EXPAND_CONTENT_DELAY);
+ });
+ return;
+ }
+
+ this.isCollapse = true;
+ this.showAsideExtras = false;
+ this.menuCollapse = true;
+ this.$nextTick(function () {
+ that.nextFrame(function () {
+ that.asideCompact = true;
+ that.finishCollapseStage(function () {
+ that.collapseAnimating = false;
+ }, SIDEBAR_TRANSITION_MS);
+ });
+ });
},
handleMenuSelect: function (group, item) {
this.addOrActivateTab({
@@ -1516,6 +1740,9 @@
if (!menu) {
return;
}
+ if (that.menuCollapse) {
+ return;
+ }
openedMenus = menu.openedMenus ? menu.openedMenus.slice() : [];
if (!groupIndex) {
if (openedMenus.length) {
@@ -1555,6 +1782,7 @@
that.menuLoading = false;
if (res.code === 200) {
that.menus = that.normalizeMenuData(res.data || []);
+ that.refreshI18nState();
that.syncMenuStateByUrl(that.activeTabUrl);
} else if (res.code === 403) {
top.location.href = baseUrl + "/login";
@@ -1712,72 +1940,14 @@
document.exitFullscreen();
}
},
- showAiTip: function () {
- this.hideAiTip();
- this.aiTipIndex = layer.tips(this.t("common.aiAssistant"), "#ai-assistant-btn", {
- tips: [1, "#333"],
- time: -1
- });
- },
- hideAiTip: function () {
- if (this.aiTipIndex) {
- layer.close(this.aiTipIndex);
- this.aiTipIndex = null;
- }
- },
openAiAssistant: function () {
- var that = this;
- var $layero;
- var $shade;
-
- this.hideAiTip();
-
- if (this.aiLayerIndex !== null && $("#layui-layer" + this.aiLayerIndex).length > 0) {
- $layero = $("#layui-layer" + this.aiLayerIndex);
- $shade = $("#layui-layer-shade" + this.aiLayerIndex);
-
- $shade.show().css("opacity", 0.1);
- $layero.show();
- $layero.removeClass("ai-drawer-layer-close");
- $layero.removeClass("ai-drawer-layer");
- void $layero.get(0).offsetWidth;
- $layero.addClass("ai-drawer-layer");
- return;
+ if (!this.aiAssistantMounted) {
+ this.aiAssistantMounted = true;
}
-
- layer.open({
- type: 2,
- title: false,
- closeBtn: 0,
- shadeClose: false,
- shade: 0.1,
- area: ["600px", "100%"],
- offset: "r",
- anim: -1,
- isOutAnim: false,
- skin: "ai-drawer-layer",
- content: "ai/diagnosis.html",
- success: function (layero, index) {
- var shadeId;
- var $shadeEl;
-
- that.aiLayerIndex = index;
- shadeId = layero.attr("id").replace("layui-layer", "layui-layer-shade");
- $shadeEl = $("#" + shadeId);
- $shadeEl.css({
- "backdrop-filter": "blur(3px)",
- transition: "opacity 0.8s"
- });
- $shadeEl.off("click.aiAssistant").on("click.aiAssistant", function () {
- layero.addClass("ai-drawer-layer-close");
- $shadeEl.css("opacity", 0);
- setTimeout(function () {
- layero.hide();
- $shadeEl.hide();
- }, 400);
- });
- }
- });
+ this.aiAssistantVisible = true;
+ },
+ closeAiAssistant: function () {
+ this.aiAssistantVisible = false;
},
handleUserCommand: function (command) {
if (command === "profile") {
--
Gitblit v1.9.1