#
Junjie
昨天 ce0cabc072420dc6dc6c3f8957ec73455a8fd04b
src/main/webapp/views/index.html
@@ -1,6 +1,5 @@
<!DOCTYPE html>
<html lang="en">
<html lang="zh-CN">
<head>
  <meta charset="utf-8">
  <title>浙江中扬 - 自动化立体仓库 - WCS</title>
@@ -8,43 +7,417 @@
  <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/layui/css/layui.css" media="all">
  <link rel="stylesheet" href="../static/css/admin.css?v=318" media="all">
  <link rel="stylesheet" href="../static/css/loader.css" media="all">
  <link rel="stylesheet" href="../static/vue/element/element.css">
  <style>
    .layui-logo img {
      width: 25px;
    [v-cloak] {
      display: none;
    }
    .layui-logo cite {
      font-size: 18px;
      font-weight: 400;
      /*margin-left: 5px;*/
    }
    /* 弹窗样式 */
    .popup {
      position: fixed;
      top: 0;
      left: 0;
    html,
    body,
    #app {
      width: 100%;
      height: 100%;
      background-color: rgba(0, 0, 0, 0.5);
      display: none;
      justify-content: center;
      align-items: center;
      z-index: 9999;
      margin: 0;
      overflow: hidden;
    }
    .popup-content {
      background-color: #fff;
      padding: 20px;
      border-radius: 5px;
      box-shadow: 0px 0px 20px rgba(0, 0, 0, 0.3);
    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;
    }
    /* AI助手抽屉动画 */
    .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-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);
@@ -79,405 +452,1020 @@
    .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>
<body class="layui-layout-body">
<div class="layui-layout layui-layout-admin">
  <!-- 头部 -->
  <div class="layui-header">
    <div class="layui-logo">
      <img src="../static/images/zy-logo-dark.png" style="display: inline-block; width: 60%;height: auto">
      <!--          <span style="margin-top: 0; letter-spacing: 10px">中扬立库</span>-->
      <!--          <img src="../static/image/logo.svg"/>-->
      <!--          <cite>中扬 - Zoneyung</cite>-->
    </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>
    <ul class="layui-nav layui-layout-left">
      <li class="layui-nav-item" lay-unselect>
        <a ew-event="flexible" title="侧边伸缩"><i class="layui-icon layui-icon-shrink-right"></i></a>
      </li>
      <li class="layui-nav-item" lay-unselect>
        <a ew-event="refresh" title="刷新"><i class="layui-icon layui-icon-refresh-3"></i></a>
      </li>
    </ul>
    <ul class="layui-nav layui-layout-right">
      <!--      <li class="layui-nav-item" lay-unselect>-->
      <!--        <a ew-event="note" title="便签"><i class="layui-icon layui-icon-note"></i></a>-->
      <!--      </li>-->
      <li class="layui-nav-item" lay-unselect id="fakeShow"
          style="display: none;user-select: none;margin-right: 10px;">
        <div style="color: red;" id="fakeShowText">仿真模拟运行中</div>
      </li>
      <li class="layui-nav-item" lay-unselect id="licenseShow" style="display: none;user-select: none;">
        <div style="color: red;">临时许可证有效期:<span id="licenseDays">29</span>天</div>
      </li>
      <li class="layui-nav-item layui-hide-xs" lay-unselect>
        <a ew-event="fullScreen" title="全屏"><i class="layui-icon layui-icon-screen-full"></i></a>
      </li>
      <li class="layui-nav-item" lay-unselect>
        <a>
          <cite id="username" style="margin-right: 5px">管理员</cite>
        </a>
        <dl class="layui-nav-child">
          <dd lay-unselect><a ew-href="detail.html?resourceId=8">基本资料</a></dd>
          <hr>
          <dd lay-unselect><a id="logout">退出</a></dd>
        </dl>
      </li>
      <li class="layui-nav-item" lay-unselect>
        <a ew-event="theme" title="主题"><i class="layui-icon layui-icon-more-vertical"></i></a>
      </li>
    </ul>
      <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-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="licenseVisible" size="mini" type="warning" 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 class="layui-side">
    <div class="layui-side-scroll">
      <ul id="menu-main" class="layui-nav layui-nav-tree arrow2" lay-filter="admin-side-nav" lay-shrink="_all">
      </ul>
    </div>
  </div>
  <!-- 主体部分 -->
  <div class="layui-body"></div>
  <!-- 底部 -->
  <div class="layui-footer layui-text">
    copyright © 2026 浙江中扬立库技术有限公司 all rights reserved.
    <span class="pull-right" id="system-version">Version loading...</span>
  </div>
</div>
<!--初始化加载层-->
<div class="layuimini-loader">
  <div class="layuimini-loader-inner"></div>
</div>
<!-- 弹窗内容 -->
<div class="popup" id="popup">
  <div class="popup-content">
    <h2 style="font-size: 28px;margin-bottom: 10px;">许可证即将过期</h2>
    <div id="popup-text" style="font-size: 28px;color: red"></div>
    <button
            style="background-color: #007bff;color: #fff;border: none;padding: 10px 20px;border-radius: 5px;cursor: pointer;font-size: 16px;"
            onclick="hidePopup()">关闭</button>
  </div>
</div>
<!-- 右下角SVG动画 -->
<div id="ai-assistant-btn" style="position: fixed; bottom: 40px; right: 20px; z-index: 9999; cursor: pointer;">
</div>
<script type="text/javascript" src="../static/js/jquery/jquery-3.3.1.min.js"></script>
<script type="text/javascript" src="../static/layui/layui.js"></script>
<script type="text/javascript" src="../static/js/handlebars/handlebars-v4.5.3.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 systemVersion = '...';
  var systemVersionType = '';
  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";
  // 加载系统版本信息
  function loadSystemVersion() {
    $.ajax({
      url: baseUrl + "/openapi/getSystemVersion",
      headers: { 'token': localStorage.getItem('token') },
      method: 'GET',
      success: function (res) {
        if (res.code === 200) {
          systemVersion = res.data.version;
          systemVersionType = res.data.versionType;
          var versionTypeLabel = systemVersionType === 'prd' ? '' : ' (' + systemVersionType + ')';
          var versionTypeColor = systemVersionType === 'prd' ? 'rgb(25,190,107)' : 'rgb(245,166,35)';
  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;
          // 更新页脚版本显示
          $('#system-version').html('Version ' + systemVersion + '<span style="margin-left:5px;padding:1px 6px;font-size:12px;border-radius:3px;background-color:' + versionTypeColor + ';color:#fff;">' + systemVersionType + '</span>');
          // 控制台输出版本信息
          console.log('%c 中扬立库平台 %c ' + systemVersion + ' %c ' + systemVersionType + ' ', 'background-color:rgb(53,73,94);color: #fff;border-radius:2px 0 0 2px;padding:2px 4px;', 'background-color:rgb(25,190,107);color: #fff;padding:2px 4px;font: 9pt "Apercu Regular", Georgia, "Times New Roman", Times, serif;', 'background-color:' + versionTypeColor + ';color: #fff;border-radius:0 2px 2px 0;padding:2px 4px;font: 9pt "Apercu Regular", Georgia, "Times New Roman", Times, serif;');
        if (!keyword) {
          return this.menus;
        }
      }
    });
  }
  $(function () {
    // 注入AI助手图标
    $('#ai-assistant-btn').html(getAiIconHtml(60, 60));
        for (i = 0; i < this.menus.length; i++) {
          group = this.menus[i];
          subMenu = [];
          groupMatched = (group.menu || "").toLowerCase().indexOf(keyword) > -1;
          items = group.subMenu || [];
    if ("" === localStorage.getItem('token')) {
      top.location.href = baseUrl + "/login";
    }
    // 加载版本信息
    loadSystemVersion();
  });
  // 显示弹窗
  function showPopup(res) {
    document.getElementById('popup').style.display = 'block';
    // 获取弹出窗口内容的容器元素
    var popupText = document.getElementById('popup-text');
    // 假设后台返回的字符串为 responseString
    if (res !== "") {
      // 获取当前日期
      const currentDate = new Date();
      // 创建新日期对象并添加天数
      const newDate = new Date();
      newDate.setDate(currentDate.getDate() + res + 1);
      // 将字符串设置为弹窗内容的文本
      popupText.textContent = "许可证将于" + new Intl.DateTimeFormat('zh-CN').format(newDate) + "过期,剩余有效期:" + res + "天!";
    } else {
      document.getElementById('popup').style.display = 'none';
    }
  }
  // 隐藏弹窗
  function hidePopup() {
    document.getElementById('popup').style.display = 'none';
  }
  layui.config({
    base: baseUrl + "/static/layui/lay/modules/"
  }).extend({
    notice: 'notice/notice',
  }).use(['index', 'element', 'layer', 'admin', 'notice'], function () {
    var $ = layui.jquery;
    var index = layui.index;
    var element = layui.element;
    var layer = layui.layer;
    var admin = layui.admin;
    var notice = layui.notice;
    var easywebIframeMsg = localStorage.getItem("easyweb-iframe");
    if (!isEmpty(easywebIframeMsg)) {
      var easywebIframeObj = JSON.parse(easywebIframeMsg);
      if (easywebIframeObj.defaultTheme === undefined) {
        admin.changeTheme("theme-colorful");
      }
    }
    let fakeRunning = false
    let fakeStatusInterval = null
    function checkFakeStatus() {
      $.ajax({
        url: baseUrl + "/openapi/getFakeSystemRunStatus",
        headers: { 'token': localStorage.getItem('token') },
        method: 'GET',
        success: function (res) {
          if (res.code === 200) {
            if (res.data.isFake) {
              $("#fakeShow").show()
              let running = res.data.running
              if (running) {
                $("#fakeShowText").text("仿真模拟运行中")
              } else {
                $("#fakeShowText").text("仿真模拟未运行")
              }
              fakeRunning = running
              if (!fakeStatusInterval) {
                fakeStatusInterval = setInterval(checkFakeStatus, 1000);
              }
            } else {
              $("#fakeShow").hide()
              if (fakeStatusInterval) {
                clearInterval(fakeStatusInterval);
                fakeStatusInterval = null;
              }
          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);
            }
          } else {
            top.location.href = baseUrl + "/login";
          }
          if (subMenu.length > 0) {
            result.push({
              menuId: group.menuId,
              menu: group.menu,
              menuCode: group.menuCode,
              subMenu: subMenu
            });
          }
        }
      });
    }
    checkFakeStatus();
    $("#fakeShow").on("click", function () {
      if (fakeRunning) {
        layer.confirm('确定要停止仿真模拟吗?', function (index) {
          layer.close(index);
          $.ajax({
            url: baseUrl + "/openapi/stopFakeSystem",
            headers: { 'token': localStorage.getItem('token') },
            method: 'POST',
            success: function (res) {
              if (res.code === 200) {
                layer.msg("仿真模拟已停止", { icon: 1 });
                $("#fakeShowText").text("仿真模拟未运行")
              } else {
                layer.msg(res.msg, { icon: 2 });
              }
            }
          });
        });
      } else {
        layer.confirm('确定要启动仿真模拟吗?', function (index) {
          layer.close(index);
          $.ajax({
            url: baseUrl + "/openapi/startFakeSystem",
            headers: { 'token': localStorage.getItem('token') },
            method: 'POST',
            success: function (res) {
              if (res.code === 200) {
                layer.msg("仿真模拟已启动", { icon: 1 });
                $("#fakeShowText").text("仿真模拟运行中")
              } else {
                layer.msg(res.msg, { icon: 2 });
              }
            }
          });
        });
      }
    });
    $.ajax({
      url: baseUrl + "/menu/auth",
      headers: { 'token': localStorage.getItem('token') },
      method: 'POST',
      // async: false,
      success: function (res) {
        // 关闭加载动画
        $('.layuimini-loader').fadeOut();
        if (res.code === 200) {
          var tpl = $('#menuTpl').html();
          var template = Handlebars.compile(tpl);
          var html = template(res);
          $("#menu-main").html(html);
          element.init();
        } else if (res.code === 403) {
          top.location.href = baseUrl + "/login";
        } else {
          layer.msg(res.msg, { icon: 2 });
        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...";
        }
      }
    });
    $.ajax({
      url: baseUrl + "/license/getLicenseDays",
      headers: { 'token': localStorage.getItem('token') },
      method: 'POST',
      success: function (res) {
        if (res.code == 200) {
          let days = res.data
          if (days <= 30) {
            $("#licenseShow").show()
            $("#licenseDays").html(days)
          }
          if (days <= 15) {
            showPopup(days)
          }
          if (days < 0) {
            top.location.href = baseUrl + "/login";
          }
        } else {
          top.location.href = baseUrl + "/login";
        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;
      },
      userShortName: function () {
        return (this.userName || "管理员").substring(0, 1);
      }
    });
    // 默认加载主页
    index.loadHome({
      menuPath: baseUrl + '/views/watch/console.html',
      menuName: '<i class="layui-icon layui-icon-home"></i>'
    });
    $('#username').text(localStorage.getItem('username'));
    $(document).on('click', '#logout', function () {
      window.location.href = "login.html";
      localStorage.removeItem('token');
      localStorage.removeItem('username');
      admin.closeAllTabs();
    });
    // 替换退出按钮变量
    var logout = document.getElementById('logout');
    var url = logout.getAttribute('href');
    logout.setAttribute('href', baseUrl + "/login");
    // AI助手弹窗索引
    var aiLayerIndex = null;
    // AI助手图标悬浮提示
    $('#ai-assistant-btn').on('mouseenter', function () {
      this.index = layer.tips('AI助手', this, {
        tips: [1, '#333'], // 上方显示,深色背景
        time: -1 // 不自动关闭
      });
    }).on('mouseleave', function () {
      layer.close(this.index);
    }).on('click', function () {
      // 如果已经打开过且未销毁,直接显示
      if (aiLayerIndex !== null && $('#layui-layer' + aiLayerIndex).length > 0) {
        var $layero = $('#layui-layer' + aiLayerIndex);
        var $shade = $('#layui-layer-shade' + 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');
    },
    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;
      }
      layer.open({
        type: 2,
        title: false, // 隐藏默认标题栏,更简洁
        closeBtn: 0, // 隐藏关闭按钮,点击遮罩关闭
        shadeClose: false, // 改为手动控制关闭,以便播放动画
        shade: 0.1,
        area: ['600px', '100%'],
        offset: 'r', // 右侧悬浮
        anim: -1, // 禁用默认动画,使用CSS动画
        isOutAnim: false,
        skin: 'ai-drawer-layer', // 自定义皮肤
        content: 'ai/diagnosis.html',
        success: function (layero, index) {
          aiLayerIndex = index; // 记录索引
      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;
          // 背景模糊效果
          var shadeId = layero.attr('id').replace('layui-layer', 'layui-layer-shade');
          var $shade = $('#' + shadeId);
          $shade.css({
            'backdrop-filter': 'blur(3px)',
            'transition': 'opacity 0.8s'
          });
        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 = "";
          }
        }
          // 点击遮罩关闭(带动画)
          $shade.on('click', function () {
            layero.addClass('ai-drawer-layer-close');
            $shade.css('opacity', 0);
            setTimeout(function () {
              // layer.close(index); // 不销毁,改为隐藏
              layero.hide();
              $shade.hide();
            }, 400);
        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>
<script type="text/html" id="menuTpl">
  {{#each data}}
  <li class="layui-nav-item">
    <a><i class="layui-icon {{this.menuIcon}}"></i>&emsp;<cite>{{this.menu}}</cite></a>
    <dl class="layui-nav-child">
      {{#each this.subMenu}}
      <dd><a lay-href="{{this.code}}?resourceId={{this.id}}">{{this.name}}</a></dd>
      {{/each}}
    </dl>
  </li>
  {{/each}}
</script>
</body>
</html>
</html>