<!DOCTYPE html>
|
<html lang="zh-CN">
|
<head>
|
<meta charset="utf-8">
|
<title>浙江中扬 - 自动化立体仓库 - WCS</title>
|
<meta name="renderer" content="webkit">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
<meta name="viewport"
|
content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0">
|
<link rel="stylesheet" href="../static/vue/element/element.css">
|
<style>
|
[v-cloak] {
|
display: none;
|
}
|
|
html,
|
body,
|
#app {
|
width: 100%;
|
height: 100%;
|
margin: 0;
|
overflow: hidden;
|
}
|
|
body {
|
font-family: "Helvetica Neue", "PingFang SC", "Microsoft YaHei", sans-serif;
|
background: linear-gradient(180deg, #f3f6fb 0%, #e9eef6 100%);
|
color: #1f2d3d;
|
}
|
|
.shell-container {
|
height: 100%;
|
padding: 12px;
|
box-sizing: border-box;
|
gap: 12px;
|
background: transparent;
|
}
|
|
.layout-aside {
|
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);
|
}
|
|
.layout-panel {
|
display: flex;
|
flex-direction: column;
|
min-width: 0;
|
height: 100%;
|
overflow: hidden;
|
border-radius: 16px;
|
background: #f5f7fa;
|
box-shadow: 0 14px 32px rgba(83, 104, 129, 0.12);
|
border: 1px solid #e4eaf2;
|
}
|
|
.aside-logo {
|
display: flex;
|
align-items: center;
|
justify-content: center;
|
min-height: 78px;
|
padding: 18px 16px 16px;
|
box-sizing: border-box;
|
color: #fff;
|
border-bottom: 1px solid rgba(255, 255, 255, 0.08);
|
}
|
|
.aside-logo-image {
|
display: block;
|
width: 100%;
|
max-width: 178px;
|
height: auto;
|
object-fit: contain;
|
}
|
|
.aside-logo.is-collapse {
|
min-height: 64px;
|
padding: 16px 10px 14px;
|
}
|
|
.aside-logo.is-collapse .aside-logo-image {
|
max-width: 42px;
|
}
|
|
.aside-search {
|
padding: 12px 12px 8px;
|
box-sizing: border-box;
|
}
|
|
.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;
|
}
|
|
.aside-search .el-input__inner::placeholder {
|
color: rgba(255, 255, 255, 0.48);
|
}
|
|
.aside-search .el-input__prefix {
|
color: rgba(255, 255, 255, 0.58);
|
}
|
|
.aside-scroll {
|
flex: 1;
|
min-height: 0;
|
}
|
|
.aside-scroll .el-scrollbar__wrap {
|
overflow-x: hidden;
|
}
|
|
.side-menu {
|
border-right: none;
|
background: transparent;
|
}
|
|
.side-menu .el-submenu__title,
|
.side-menu .el-menu-item {
|
height: 46px;
|
line-height: 46px;
|
margin: 0 10px 6px;
|
border-radius: 10px;
|
box-sizing: border-box;
|
}
|
|
.side-menu .el-submenu__title:hover,
|
.side-menu .el-menu-item:hover {
|
background: rgba(255, 255, 255, 0.08) !important;
|
color: #fff !important;
|
}
|
|
.side-menu .el-menu-item.is-active {
|
background: linear-gradient(90deg, #3a7afe 0%, #2867e0 100%) !important;
|
color: #fff !important;
|
box-shadow: 0 8px 18px rgba(40, 103, 224, 0.26);
|
}
|
|
.side-menu .el-submenu .el-menu {
|
background: transparent;
|
}
|
|
.side-menu.el-menu--collapse .el-submenu__title,
|
.side-menu.el-menu--collapse .el-menu-item {
|
display: flex;
|
align-items: center;
|
justify-content: center;
|
padding: 0 !important;
|
text-align: center;
|
}
|
|
.side-menu.el-menu--collapse .el-submenu__title > i:not(.el-submenu__icon-arrow),
|
.side-menu.el-menu--collapse .el-menu-item [class^="el-icon-"],
|
.side-menu.el-menu--collapse .el-menu-item [class*=" el-icon-"] {
|
display: flex;
|
align-items: center;
|
justify-content: center;
|
height: 100%;
|
margin: 0 !important;
|
width: 100%;
|
font-size: 22px;
|
line-height: 1;
|
text-align: center;
|
}
|
|
.side-menu.el-menu--collapse .el-submenu__icon-arrow {
|
display: none !important;
|
}
|
|
.el-menu--popup {
|
min-width: 188px;
|
padding: 8px;
|
border: none;
|
border-radius: 14px;
|
background: linear-gradient(180deg, #16324d 0%, #0d2237 100%) !important;
|
box-shadow: 0 16px 32px rgba(13, 34, 55, 0.28);
|
}
|
|
.el-menu--popup .el-menu-item,
|
.el-menu--popup .el-submenu__title {
|
height: 44px;
|
line-height: 44px;
|
margin: 0 0 6px;
|
border-radius: 10px;
|
color: #c6d1df;
|
background: transparent !important;
|
}
|
|
.el-menu--popup .el-menu-item:last-child,
|
.el-menu--popup .el-submenu__title:last-child {
|
margin-bottom: 0;
|
}
|
|
.el-menu--popup .el-menu-item:hover,
|
.el-menu--popup .el-submenu__title:hover {
|
color: #fff !important;
|
background: rgba(255, 255, 255, 0.08) !important;
|
}
|
|
.el-menu--popup .el-menu-item.is-active {
|
color: #fff !important;
|
background: linear-gradient(90deg, #3a7afe 0%, #2867e0 100%) !important;
|
box-shadow: 0 8px 18px rgba(40, 103, 224, 0.26);
|
}
|
|
.el-menu--popup .el-submenu__icon-arrow,
|
.el-menu--popup [class^="el-icon-"],
|
.el-menu--popup [class*=" el-icon-"] {
|
color: inherit;
|
}
|
|
.side-menu .el-submenu__icon-arrow,
|
.side-menu [class^="el-icon-"],
|
.side-menu [class*=" el-icon-"] {
|
color: inherit;
|
}
|
|
.aside-empty {
|
padding: 24px 12px;
|
}
|
|
.aside-empty .el-empty__description p {
|
color: rgba(255, 255, 255, 0.58);
|
}
|
|
.aside-footer {
|
padding: 14px 16px 16px;
|
border-top: 1px solid rgba(255, 255, 255, 0.08);
|
color: rgba(255, 255, 255, 0.72);
|
font-size: 12px;
|
line-height: 1.7;
|
}
|
|
.aside-footer-copy {
|
margin-bottom: 8px;
|
color: rgba(255, 255, 255, 0.62);
|
white-space: nowrap;
|
overflow: hidden;
|
text-overflow: ellipsis;
|
}
|
|
.aside-footer-version {
|
display: flex;
|
align-items: center;
|
gap: 8px;
|
color: #fff;
|
}
|
|
.aside-footer-version-text {
|
flex: 1;
|
min-width: 0;
|
font-size: 13px;
|
font-weight: 500;
|
white-space: nowrap;
|
overflow: hidden;
|
text-overflow: ellipsis;
|
}
|
|
.header-bar {
|
height: 60px !important;
|
display: flex;
|
align-items: center;
|
justify-content: space-between;
|
gap: 12px;
|
padding: 0 16px;
|
box-sizing: border-box;
|
background: #fff;
|
border-bottom: 1px solid #e8edf5;
|
}
|
|
.header-left {
|
min-width: 0;
|
display: flex;
|
align-items: center;
|
gap: 12px;
|
}
|
|
.header-title-group {
|
min-width: 0;
|
}
|
|
.header-title {
|
color: #303133;
|
font-size: 18px;
|
font-weight: 600;
|
line-height: 1.2;
|
white-space: nowrap;
|
overflow: hidden;
|
text-overflow: ellipsis;
|
}
|
|
.header-right {
|
display: flex;
|
align-items: center;
|
justify-content: flex-end;
|
gap: 8px;
|
flex-shrink: 0;
|
}
|
|
.header-right .el-tag {
|
border-radius: 999px;
|
}
|
|
.header-tag-clickable {
|
cursor: pointer;
|
}
|
|
.user-dropdown {
|
display: inline-flex;
|
align-items: center;
|
gap: 8px;
|
height: 38px;
|
padding: 0 10px 0 6px;
|
border: 1px solid #dce3ed;
|
border-radius: 999px;
|
background: #fff;
|
cursor: pointer;
|
user-select: none;
|
}
|
|
.user-name {
|
display: inline-block;
|
max-width: 96px;
|
overflow: hidden;
|
text-overflow: ellipsis;
|
white-space: nowrap;
|
color: #303133;
|
font-size: 13px;
|
}
|
|
.tabs-row {
|
display: flex;
|
align-items: flex-end;
|
gap: 10px;
|
flex-shrink: 0;
|
padding: 0 12px;
|
background: #fff;
|
border-bottom: 1px solid #e8edf5;
|
box-sizing: border-box;
|
}
|
|
.page-tabs {
|
flex: 1;
|
min-width: 0;
|
}
|
|
.page-tabs .el-tabs__header {
|
margin: 0;
|
}
|
|
.page-tabs .el-tabs__nav-wrap::after {
|
height: 0;
|
}
|
|
.page-tabs .el-tabs__item {
|
height: 38px;
|
line-height: 38px;
|
}
|
|
.tabs-tools {
|
display: flex;
|
align-items: center;
|
gap: 8px;
|
padding-bottom: 6px;
|
flex-shrink: 0;
|
}
|
|
.content-main {
|
display: flex;
|
flex: 1;
|
padding: 12px;
|
box-sizing: border-box;
|
background: #f5f7fa;
|
min-height: 0;
|
overflow: hidden;
|
}
|
|
.frame-wrapper {
|
flex: 1;
|
position: relative;
|
min-height: 0;
|
overflow: hidden;
|
border-radius: 12px;
|
border: 1px solid #e5ebf3;
|
background: #fff;
|
}
|
|
.page-frame {
|
width: 100%;
|
height: 100%;
|
border: 0;
|
display: block;
|
background: #fff;
|
}
|
|
.page-loading {
|
position: absolute;
|
top: 0;
|
right: 0;
|
bottom: 0;
|
left: 0;
|
z-index: 10;
|
display: flex;
|
align-items: center;
|
justify-content: center;
|
gap: 10px;
|
background: rgba(255, 255, 255, 0.92);
|
color: #606266;
|
font-size: 14px;
|
}
|
|
.page-loading i {
|
font-size: 18px;
|
color: #409eff;
|
}
|
|
.license-dialog-text {
|
color: #303133;
|
font-size: 15px;
|
line-height: 1.8;
|
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;
|
}
|
}
|
|
.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 {
|
position: fixed;
|
right: 20px;
|
bottom: 40px;
|
z-index: 9999;
|
cursor: pointer;
|
}
|
|
@media (max-width: 1440px) {
|
.user-name {
|
max-width: 72px;
|
}
|
}
|
|
@media (max-width: 1280px) {
|
.header-right .el-tag {
|
display: none;
|
}
|
}
|
</style>
|
</head>
|
<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 }">
|
<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="搜索菜单">
|
</el-input>
|
</div>
|
|
<el-scrollbar class="aside-scroll" v-loading="menuLoading">
|
<el-menu
|
ref="sideMenu"
|
class="side-menu"
|
:default-active="activeMenuKey"
|
:collapse="isCollapse"
|
:collapse-transition="false"
|
:default-openeds="defaultOpeneds"
|
unique-opened
|
background-color="transparent"
|
text-color="#c6d1df"
|
active-text-color="#ffffff">
|
<el-submenu
|
v-for="group in filteredMenus"
|
:key="'group-' + group.menuId"
|
:index="'group-' + group.menuId">
|
<template slot="title">
|
<i :class="resolveMenuIcon(group.menuCode)"></i>
|
<span>{{ group.menu }}</span>
|
</template>
|
<el-menu-item
|
v-for="item in group.subMenu"
|
:key="item.tabKey"
|
:index="item.tabKey"
|
@click="handleMenuSelect(group, item)">
|
{{ item.name }}
|
</el-menu-item>
|
</el-submenu>
|
</el-menu>
|
|
<div class="aside-empty" v-if="!menuLoading && filteredMenus.length === 0">
|
<el-empty
|
:image-size="80"
|
:description="menuKeyword ? '没有匹配菜单' : '当前账号没有可用菜单'">
|
</el-empty>
|
</div>
|
</el-scrollbar>
|
|
<div class="aside-footer" v-show="!isCollapse">
|
<div class="aside-footer-copy">© 2026 浙江中扬立库技术有限公司</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>
|
</el-aside>
|
|
<el-container class="layout-panel">
|
<el-header class="header-bar">
|
<div class="header-left">
|
<el-button
|
circle
|
size="mini"
|
:icon="isCollapse ? 'el-icon-s-unfold' : 'el-icon-s-fold'"
|
@click="toggleCollapse">
|
</el-button>
|
<div class="header-title-group">
|
<div class="header-title">{{ activeTabTitle }}</div>
|
</div>
|
</div>
|
|
<div class="header-right">
|
<el-tag
|
v-if="licenseDisplayVisible"
|
size="mini"
|
:type="licenseTagType"
|
effect="dark">
|
临时许可证有效期:{{ licenseDays }}天
|
</el-tag>
|
<el-tag
|
v-if="fakeVisible"
|
class="header-tag-clickable"
|
size="mini"
|
:type="fakeRunning ? 'danger' : 'info'"
|
effect="dark"
|
@click.native="toggleFakeSystem">
|
{{ fakeRunning ? '仿真运行中' : '仿真未运行' }}
|
</el-tag>
|
<el-button circle size="mini" icon="el-icon-refresh" @click="refreshActiveTab"></el-button>
|
<el-button circle size="mini" icon="el-icon-full-screen" @click="toggleFullScreen"></el-button>
|
|
<el-dropdown trigger="click" @command="handleUserCommand">
|
<span class="user-dropdown">
|
<el-avatar size="small">{{ userShortName }}</el-avatar>
|
<span class="user-name" id="person-username">{{ userName }}</span>
|
<i class="el-icon-arrow-down"></i>
|
</span>
|
<el-dropdown-menu slot="dropdown">
|
<el-dropdown-item command="profile">基本资料</el-dropdown-item>
|
<el-dropdown-item command="logout" divided>退出登录</el-dropdown-item>
|
</el-dropdown-menu>
|
</el-dropdown>
|
</div>
|
</el-header>
|
|
<div class="tabs-row">
|
<el-tabs
|
class="page-tabs"
|
v-model="activeTab"
|
type="card"
|
@tab-click="handleTabClick"
|
@tab-remove="removeTab">
|
<el-tab-pane
|
v-for="tab in tabs"
|
:key="tab.name"
|
:label="tab.title"
|
:name="tab.name"
|
:closable="!tab.home">
|
</el-tab-pane>
|
</el-tabs>
|
|
<div class="tabs-tools">
|
<el-tooltip content="关闭其他页签" placement="top">
|
<el-button size="mini" icon="el-icon-close" @click="closeOtherTabs"></el-button>
|
</el-tooltip>
|
<el-tooltip content="返回控制中心" placement="top">
|
<el-button size="mini" type="primary" icon="el-icon-house" @click="openHomeTab"></el-button>
|
</el-tooltip>
|
</div>
|
</div>
|
|
<el-main class="content-main">
|
<div class="frame-wrapper">
|
<div class="page-loading" v-if="pageLoading">
|
<i class="el-icon-loading"></i>
|
<span>{{ loadingText }}</span>
|
</div>
|
|
<iframe
|
v-for="tab in tabs"
|
:key="'frame-' + tab.name"
|
class="page-frame"
|
v-show="activeTab === tab.name"
|
:src="tab.currentSrc"
|
@load="handleFrameLoad(tab.name)">
|
</iframe>
|
</div>
|
</el-main>
|
</el-container>
|
</el-container>
|
|
<el-dialog
|
title="许可证即将过期"
|
:visible.sync="licenseDialogVisible"
|
width="420px"
|
:close-on-click-modal="false">
|
<div class="license-dialog-text">{{ licenseDialogText }}</div>
|
<span slot="footer">
|
<el-button type="primary" @click="licenseDialogVisible = false">知道了</el-button>
|
</span>
|
</el-dialog>
|
|
<div
|
id="ai-assistant-btn"
|
class="ai-assistant-btn"
|
@mouseenter="showAiTip"
|
@mouseleave="hideAiTip"
|
@click="openAiAssistant">
|
</div>
|
</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"></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>
|
var HOME_TAB_CONFIG = {
|
title: "控制中心",
|
url: baseUrl + "/views/watch/console.html",
|
home: true,
|
group: "实时监控",
|
menuKey: ""
|
};
|
var PROFILE_TAB_CONFIG = {
|
title: "基本资料",
|
url: baseUrl + "/views/detail.html?resourceId=8",
|
home: false,
|
group: "账户中心",
|
menuKey: ""
|
};
|
var TAB_STORAGE_KEY = "wcs-element-home-tabs";
|
var USER_STORAGE_KEY = "username";
|
|
new Vue({
|
el: "#app",
|
data: function () {
|
return {
|
isCollapse: false,
|
menuLoading: false,
|
pageLoading: true,
|
loadingText: "正在加载页面...",
|
menuKeyword: "",
|
menus: [],
|
defaultOpeneds: [],
|
activeMenuKey: "",
|
tabs: [],
|
activeTab: HOME_TAB_CONFIG.url,
|
version: "",
|
versionType: "",
|
licenseDays: null,
|
licenseDialogVisible: false,
|
licenseDialogText: "",
|
fakeVisible: false,
|
fakeRunning: false,
|
fakeStatusInterval: null,
|
userName: localStorage.getItem(USER_STORAGE_KEY) || "管理员",
|
aiLayerIndex: null,
|
aiTipIndex: null
|
};
|
},
|
computed: {
|
asideWidth: function () {
|
return this.isCollapse ? "72px" : "248px";
|
},
|
filteredMenus: function () {
|
var keyword = (this.menuKeyword || "").toLowerCase();
|
var result = [];
|
var i;
|
var j;
|
var group;
|
var items;
|
var item;
|
var subMenu;
|
var groupMatched;
|
var text;
|
|
if (!keyword) {
|
return this.menus;
|
}
|
|
for (i = 0; i < this.menus.length; i++) {
|
group = this.menus[i];
|
subMenu = [];
|
groupMatched = (group.menu || "").toLowerCase().indexOf(keyword) > -1;
|
items = group.subMenu || [];
|
|
for (j = 0; j < items.length; j++) {
|
item = items[j];
|
text = ((item.name || "") + " " + (item.code || "")).toLowerCase();
|
if (groupMatched || text.indexOf(keyword) > -1) {
|
subMenu.push(item);
|
}
|
}
|
|
if (subMenu.length > 0) {
|
result.push({
|
menuId: group.menuId,
|
menu: group.menu,
|
menuCode: group.menuCode,
|
subMenu: subMenu
|
});
|
}
|
}
|
|
return result;
|
},
|
activeTabMeta: function () {
|
return this.getTabByName(this.activeTab) || this.createTab(HOME_TAB_CONFIG);
|
},
|
activeTabTitle: function () {
|
return this.activeTabMeta.title;
|
},
|
activeTabUrl: function () {
|
return this.activeTabMeta.url;
|
},
|
versionText: function () {
|
if (!this.version) {
|
return "Version loading...";
|
}
|
return "Version " + this.version;
|
},
|
versionTypeTag: function () {
|
return (this.versionType || "").toUpperCase();
|
},
|
versionTagType: function () {
|
if (this.versionType === "prd") {
|
return "success";
|
}
|
if (this.versionType === "dev") {
|
return "warning";
|
}
|
return "info";
|
},
|
licenseVisible: function () {
|
return this.licenseDays !== null && this.licenseDays <= 30;
|
},
|
licenseDisplayVisible: function () {
|
return this.licenseVisible && this.licenseDays >= 0;
|
},
|
licenseTagType: function () {
|
if (this.licenseDays !== null && this.licenseDays <= 15) {
|
return "danger";
|
}
|
if (this.licenseDays !== null && this.licenseDays <= 30) {
|
return "warning";
|
}
|
return "info";
|
},
|
userShortName: function () {
|
return (this.userName || "管理员").substring(0, 1);
|
}
|
},
|
watch: {
|
activeTab: function () {
|
var tab = this.getTabByName(this.activeTab);
|
this.activeMenuKey = tab ? (tab.menuKey || this.findMenuKeyByUrl(tab.url)) : "";
|
this.pageLoading = !!(tab && !tab.loaded);
|
if (this.pageLoading) {
|
this.loadingText = "正在加载 “" + tab.title + "” ...";
|
}
|
document.title = (tab ? tab.title : HOME_TAB_CONFIG.title) + " - 浙江中扬 - 自动化立体仓库 - WCS";
|
this.persistTabs();
|
}
|
},
|
created: function () {
|
if (!localStorage.getItem("token")) {
|
top.location.href = baseUrl + "/login";
|
return;
|
}
|
|
this.restoreTabs();
|
this.installCompatBridge();
|
this.loadSystemVersion();
|
this.loadMenu();
|
this.loadLicenseDays();
|
this.checkFakeStatus();
|
this.startUserSync();
|
},
|
mounted: function () {
|
$("#ai-assistant-btn").html(getAiIconHtml(60, 60));
|
document.title = this.activeTabTitle + " - 浙江中扬 - 自动化立体仓库 - WCS";
|
},
|
beforeDestroy: function () {
|
if (this.fakeStatusInterval) {
|
clearInterval(this.fakeStatusInterval);
|
this.fakeStatusInterval = null;
|
}
|
if (this.userSyncTimer) {
|
clearInterval(this.userSyncTimer);
|
this.userSyncTimer = null;
|
}
|
if (this.aiTipIndex) {
|
layer.close(this.aiTipIndex);
|
this.aiTipIndex = null;
|
}
|
},
|
methods: {
|
resolveMenuIcon: function (code) {
|
var iconMap = {
|
index: "el-icon-s-home",
|
system: "el-icon-setting",
|
set: "el-icon-s-tools",
|
merchant: "el-icon-user",
|
develop: "el-icon-monitor",
|
stock: "el-icon-box",
|
logReport: "el-icon-document",
|
ioWork: "el-icon-s-operation",
|
workFlow: "el-icon-connection",
|
base: "el-icon-collection-tag",
|
erp: "el-icon-s-order",
|
sensor: "el-icon-cpu"
|
};
|
return iconMap[code] || "el-icon-menu";
|
},
|
createTab: function (config) {
|
return {
|
title: config.title,
|
name: config.url,
|
url: config.url,
|
currentSrc: config.url,
|
home: !!config.home,
|
group: config.group || "",
|
menuKey: config.menuKey || "",
|
loaded: false
|
};
|
},
|
normalizeStoredTab: function (tab) {
|
var created = this.createTab({
|
title: tab.title,
|
url: this.resolveViewSrc(tab.url),
|
home: !!tab.home,
|
group: tab.group || "",
|
menuKey: tab.menuKey || ""
|
});
|
created.loaded = false;
|
return created;
|
},
|
restoreTabs: function () {
|
var homeTab = this.createTab(HOME_TAB_CONFIG);
|
var raw = localStorage.getItem(TAB_STORAGE_KEY);
|
var parsed;
|
var tabs = [];
|
var active;
|
var i;
|
var exists;
|
|
if (raw) {
|
try {
|
parsed = JSON.parse(raw);
|
if (parsed && parsed.tabs && parsed.tabs.length) {
|
for (i = 0; i < parsed.tabs.length; i++) {
|
tabs.push(this.normalizeStoredTab(parsed.tabs[i]));
|
}
|
}
|
active = parsed ? parsed.activeTab : "";
|
} catch (e) {
|
tabs = [];
|
active = "";
|
}
|
}
|
|
exists = false;
|
for (i = 0; i < tabs.length; i++) {
|
if (tabs[i].name === homeTab.name) {
|
tabs[i].home = true;
|
tabs[i].title = homeTab.title;
|
exists = true;
|
break;
|
}
|
}
|
if (!exists) {
|
tabs.unshift(homeTab);
|
}
|
|
if (tabs.length === 0) {
|
tabs = [homeTab];
|
}
|
|
this.tabs = tabs;
|
this.activeTab = this.hasTab(active) ? active : homeTab.name;
|
this.loadingText = "正在加载 “" + this.activeTabTitle + "” ...";
|
this.pageLoading = true;
|
document.title = this.activeTabTitle + " - 浙江中扬 - 自动化立体仓库 - WCS";
|
},
|
persistTabs: function () {
|
var tabs = [];
|
var i;
|
for (i = 0; i < this.tabs.length; i++) {
|
tabs.push({
|
title: this.tabs[i].title,
|
url: this.tabs[i].url,
|
home: this.tabs[i].home,
|
group: this.tabs[i].group,
|
menuKey: this.tabs[i].menuKey
|
});
|
}
|
localStorage.setItem(TAB_STORAGE_KEY, JSON.stringify({
|
tabs: tabs,
|
activeTab: this.activeTab
|
}));
|
},
|
hasTab: function (name) {
|
return !!this.getTabByName(name);
|
},
|
getTabByName: function (name) {
|
var i;
|
for (i = 0; i < this.tabs.length; i++) {
|
if (this.tabs[i].name === name) {
|
return this.tabs[i];
|
}
|
}
|
return null;
|
},
|
addOrActivateTab: function (config) {
|
var url = this.resolveViewSrc(config.url);
|
var tab = this.getTabByName(url);
|
|
if (!tab) {
|
tab = this.createTab({
|
title: config.title,
|
url: url,
|
home: !!config.home,
|
group: config.group,
|
menuKey: config.menuKey || this.findMenuKeyByUrl(url)
|
});
|
this.tabs.push(tab);
|
} else {
|
tab.title = config.title || tab.title;
|
tab.group = config.group || tab.group;
|
tab.menuKey = config.menuKey || tab.menuKey;
|
if (config.home) {
|
tab.home = true;
|
}
|
}
|
|
this.loadingText = "正在加载 “" + tab.title + "” ...";
|
this.pageLoading = !tab.loaded;
|
this.activeTab = tab.name;
|
this.activeMenuKey = tab.menuKey || this.findMenuKeyByUrl(tab.url);
|
},
|
openHomeTab: function () {
|
this.addOrActivateTab(HOME_TAB_CONFIG);
|
},
|
openProfileTab: function () {
|
this.addOrActivateTab(PROFILE_TAB_CONFIG);
|
},
|
closeAllTabs: function () {
|
this.tabs = [this.createTab(HOME_TAB_CONFIG)];
|
this.activeTab = HOME_TAB_CONFIG.url;
|
this.activeMenuKey = "";
|
this.pageLoading = true;
|
this.loadingText = "正在加载 “控制中心” ...";
|
this.persistTabs();
|
},
|
closeOtherTabs: function () {
|
var active = this.getTabByName(this.activeTab);
|
var homeTab = this.createTab(HOME_TAB_CONFIG);
|
var result = [homeTab];
|
|
if (active && active.name !== homeTab.name) {
|
result.push(active);
|
}
|
|
this.tabs = result;
|
this.persistTabs();
|
},
|
removeTab: function (name) {
|
var i;
|
var nextTabName = HOME_TAB_CONFIG.url;
|
|
for (i = 0; i < this.tabs.length; i++) {
|
if (this.tabs[i].name === name) {
|
if (this.activeTab === name) {
|
if (this.tabs[i + 1]) {
|
nextTabName = this.tabs[i + 1].name;
|
} else if (this.tabs[i - 1]) {
|
nextTabName = this.tabs[i - 1].name;
|
}
|
}
|
this.tabs.splice(i, 1);
|
break;
|
}
|
}
|
|
if (this.tabs.length === 0) {
|
this.tabs.push(this.createTab(HOME_TAB_CONFIG));
|
nextTabName = HOME_TAB_CONFIG.url;
|
}
|
|
this.activeTab = nextTabName;
|
this.persistTabs();
|
},
|
handleTabClick: function () {
|
this.activeMenuKey = this.findMenuKeyByUrl(this.activeTabUrl);
|
},
|
handleFrameLoad: function (name) {
|
var tab = this.getTabByName(name);
|
if (tab) {
|
tab.loaded = true;
|
}
|
if (this.activeTab === name) {
|
this.pageLoading = false;
|
}
|
},
|
refreshActiveTab: function () {
|
var tab = this.getTabByName(this.activeTab);
|
if (!tab) {
|
return;
|
}
|
tab.loaded = false;
|
tab.currentSrc = this.addNonce(tab.url);
|
this.loadingText = "正在刷新 “" + tab.title + "” ...";
|
this.pageLoading = true;
|
},
|
addNonce: function (url) {
|
return url + (url.indexOf("?") === -1 ? "?" : "&") + "_t=" + new Date().getTime();
|
},
|
toggleCollapse: function () {
|
this.isCollapse = !this.isCollapse;
|
},
|
handleMenuSelect: function (group, item) {
|
this.addOrActivateTab({
|
title: item.name,
|
url: item.url,
|
home: false,
|
group: group.menu,
|
menuKey: item.tabKey
|
});
|
},
|
findMenuKeyByUrl: function (url) {
|
var normalized = this.resolveViewSrc(url);
|
var i;
|
var j;
|
var group;
|
var item;
|
|
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 (item.url === normalized) {
|
return item.tabKey;
|
}
|
}
|
}
|
return "";
|
},
|
normalizeMenuData: function (data) {
|
var result = [];
|
var i;
|
var j;
|
var group;
|
var item;
|
var subMenu;
|
|
for (i = 0; i < data.length; i++) {
|
group = data[i];
|
subMenu = [];
|
|
for (j = 0; j < (group.subMenu || []).length; j++) {
|
item = group.subMenu[j];
|
subMenu.push({
|
id: item.id,
|
name: item.name || item.code || "未命名页面",
|
code: item.code || "",
|
url: this.buildMenuSrc(item.code, item.id),
|
tabKey: this.buildMenuSrc(item.code, item.id)
|
});
|
}
|
|
result.push({
|
menuId: group.menuId,
|
menu: group.menu || "未命名分组",
|
menuCode: group.menuCode || "",
|
subMenu: subMenu
|
});
|
}
|
|
return result;
|
},
|
buildMenuSrc: function (code, resourceId) {
|
var normalized = code || "";
|
var hash = "";
|
var hashIndex = normalized.indexOf("#");
|
var resolved;
|
|
if (hashIndex > -1) {
|
hash = normalized.substring(hashIndex);
|
normalized = normalized.substring(0, hashIndex);
|
}
|
|
resolved = this.resolveViewSrc(normalized);
|
if (resourceId && resolved.indexOf("resourceId=") === -1) {
|
resolved += (resolved.indexOf("?") === -1 ? "?" : "&") + "resourceId=" + encodeURIComponent(resourceId);
|
}
|
return resolved + hash;
|
},
|
resolveViewSrc: function (path) {
|
if (!path) {
|
return HOME_TAB_CONFIG.url;
|
}
|
if (/^https?:\/\//.test(path) || path.indexOf(baseUrl) === 0) {
|
return path;
|
}
|
if (path.indexOf("/views/") === 0) {
|
return baseUrl + path;
|
}
|
if (path.indexOf("views/") === 0) {
|
return baseUrl + "/" + path;
|
}
|
return baseUrl + "/views/" + path.replace(/^\/+/, "");
|
},
|
stripTags: function (value) {
|
var div = document.createElement("div");
|
div.innerHTML = value || "";
|
return (div.textContent || div.innerText || "").trim();
|
},
|
collapseAllMenus: function () {
|
var menu = this.$refs.sideMenu;
|
var openedMenus;
|
var i;
|
|
if (!menu || !menu.openedMenus || !menu.openedMenus.length) {
|
return;
|
}
|
|
openedMenus = menu.openedMenus.slice();
|
for (i = 0; i < openedMenus.length; i++) {
|
menu.close(openedMenus[i]);
|
}
|
},
|
loadMenu: function () {
|
var that = this;
|
this.menuLoading = true;
|
$.ajax({
|
url: baseUrl + "/menu/auth",
|
headers: { token: localStorage.getItem("token") },
|
method: "POST",
|
success: function (res) {
|
that.menuLoading = false;
|
if (res.code === 200) {
|
that.menus = that.normalizeMenuData(res.data || []);
|
that.defaultOpeneds = [];
|
that.activeMenuKey = that.findMenuKeyByUrl(that.activeTabUrl);
|
that.$nextTick(function () {
|
that.collapseAllMenus();
|
});
|
} else if (res.code === 403) {
|
top.location.href = baseUrl + "/login";
|
} else {
|
that.$message.error(res.msg || "菜单加载失败");
|
}
|
},
|
error: function () {
|
that.menuLoading = false;
|
that.$message.error("菜单加载失败,请检查接口状态");
|
}
|
});
|
},
|
loadSystemVersion: function () {
|
var that = this;
|
$.ajax({
|
url: baseUrl + "/openapi/getSystemVersion",
|
headers: { token: localStorage.getItem("token") },
|
method: "GET",
|
success: function (res) {
|
if (res.code === 200) {
|
that.version = res.data.version || "";
|
that.versionType = res.data.versionType || "";
|
}
|
}
|
});
|
},
|
loadLicenseDays: function () {
|
var that = this;
|
$.ajax({
|
url: baseUrl + "/license/getLicenseDays",
|
headers: { token: localStorage.getItem("token") },
|
method: "POST",
|
success: function (res) {
|
var days;
|
if (res.code !== 200) {
|
top.location.href = baseUrl + "/login";
|
return;
|
}
|
|
days = Number(res.data);
|
that.licenseDays = days;
|
|
if (days <= 15) {
|
that.showPopup(days);
|
}
|
|
if (days < 0) {
|
top.location.href = baseUrl + "/login";
|
}
|
}
|
});
|
},
|
showPopup: function (days) {
|
var currentDate;
|
var expiryDate;
|
|
if (days === "" || days === null || typeof days === "undefined") {
|
this.hidePopup();
|
return;
|
}
|
|
currentDate = new Date();
|
expiryDate = new Date();
|
expiryDate.setDate(currentDate.getDate() + Number(days) + 1);
|
this.licenseDialogText = "许可证将于 " + new Intl.DateTimeFormat("zh-CN").format(expiryDate) +
|
" 过期,剩余有效期:" + days + " 天。";
|
this.licenseDialogVisible = true;
|
},
|
hidePopup: function () {
|
this.licenseDialogVisible = false;
|
},
|
checkFakeStatus: function () {
|
var that = this;
|
$.ajax({
|
url: baseUrl + "/openapi/getFakeSystemRunStatus",
|
headers: { token: localStorage.getItem("token") },
|
method: "GET",
|
success: function (res) {
|
if (res.code !== 200) {
|
top.location.href = baseUrl + "/login";
|
return;
|
}
|
|
if (res.data.isFake) {
|
that.fakeVisible = true;
|
that.fakeRunning = !!res.data.running;
|
if (!that.fakeStatusInterval) {
|
that.fakeStatusInterval = setInterval(function () {
|
that.checkFakeStatus();
|
}, 1000);
|
}
|
} else {
|
that.fakeVisible = false;
|
if (that.fakeStatusInterval) {
|
clearInterval(that.fakeStatusInterval);
|
that.fakeStatusInterval = null;
|
}
|
}
|
}
|
});
|
},
|
toggleFakeSystem: function () {
|
var that = this;
|
var url;
|
var text;
|
var successMsg;
|
var running;
|
|
if (!this.fakeVisible) {
|
return;
|
}
|
|
if (this.fakeRunning) {
|
url = baseUrl + "/openapi/stopFakeSystem";
|
text = "确定要停止仿真模拟吗?";
|
successMsg = "仿真模拟已停止";
|
running = false;
|
} else {
|
url = baseUrl + "/openapi/startFakeSystem";
|
text = "确定要启动仿真模拟吗?";
|
successMsg = "仿真模拟已启动";
|
running = true;
|
}
|
|
this.$confirm(text, "提示", {
|
type: "warning"
|
}).then(function () {
|
$.ajax({
|
url: url,
|
headers: { token: localStorage.getItem("token") },
|
method: "POST",
|
success: function (res) {
|
if (res.code === 200) {
|
that.fakeRunning = running;
|
that.$message.success(successMsg);
|
} else {
|
that.$message.error(res.msg || "操作失败");
|
}
|
}
|
});
|
}).catch(function () {});
|
},
|
toggleFullScreen: function () {
|
if (!document.fullscreenElement) {
|
document.documentElement.requestFullscreen();
|
} else {
|
document.exitFullscreen();
|
}
|
},
|
showAiTip: function () {
|
this.hideAiTip();
|
this.aiTipIndex = layer.tips("AI助手", "#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;
|
}
|
|
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);
|
});
|
}
|
});
|
},
|
handleUserCommand: function (command) {
|
if (command === "profile") {
|
this.openProfileTab();
|
} else if (command === "logout") {
|
this.logout();
|
}
|
},
|
logout: function () {
|
localStorage.removeItem("token");
|
localStorage.removeItem(USER_STORAGE_KEY);
|
localStorage.removeItem(TAB_STORAGE_KEY);
|
window.location.href = baseUrl + "/login";
|
},
|
startUserSync: function () {
|
var that = this;
|
this.userSyncTimer = setInterval(function () {
|
that.userName = localStorage.getItem(USER_STORAGE_KEY) || "管理员";
|
}, 1000);
|
},
|
installCompatBridge: function () {
|
var that = this;
|
|
window.admin = window.admin || {};
|
window.admin.closeAllTabs = function () {
|
that.closeAllTabs();
|
};
|
window.admin.changeTheme = window.admin.changeTheme || function () {};
|
window.admin.activeNav = function (url) {
|
that.activeMenuKey = that.findMenuKeyByUrl(that.resolveViewSrc(url));
|
};
|
|
window.index = window.index || {};
|
window.index.loadView = function (param) {
|
var url;
|
if (!param || !param.menuPath) {
|
return;
|
}
|
url = that.resolveViewSrc(param.menuPath);
|
that.addOrActivateTab({
|
title: that.stripTags(param.menuName) || "工作页面",
|
url: url,
|
home: false,
|
group: "业务页面",
|
menuKey: that.findMenuKeyByUrl(url)
|
});
|
};
|
window.index.loadHome = function (param) {
|
var url;
|
if (!param || !param.menuPath) {
|
that.openHomeTab();
|
return;
|
}
|
url = that.resolveViewSrc(param.menuPath);
|
that.addOrActivateTab({
|
title: that.stripTags(param.menuName) || HOME_TAB_CONFIG.title,
|
url: url,
|
home: true,
|
group: HOME_TAB_CONFIG.group,
|
menuKey: that.findMenuKeyByUrl(url)
|
});
|
};
|
|
window.showPopup = function (days) {
|
that.showPopup(days);
|
};
|
window.hidePopup = function () {
|
that.hidePopup();
|
};
|
}
|
}
|
});
|
</script>
|
</body>
|
</html>
|