|  |  | 
 |  |  | <script setup>
 | 
 |  |  | import { nextTick, ref, inject, onMounted } from 'vue';
 | 
 |  |  | import { nextTick, ref, inject, onMounted, h, reactive } from 'vue';
 | 
 |  |  | import { useRouter } from "vue-router";
 | 
 |  |  | import { get, post, postForm } from '@/utils/request.js'
 | 
 |  |  | import { logout } from '@/config.js';
 | 
 |  |  | import * as Icons from "@ant-design/icons-vue";
 | 
 |  |  | import { message } from 'ant-design-vue';
 | 
 |  |  | // import type { MenuMode, MenuTheme } from 'ant-design-vue';
 | 
 |  |  | // import { ItemType } from 'ant-design-vue';
 | 
 |  |  | 
 | 
 |  |  | import {
 | 
 |  |  |   MenuUnfoldOutlined,
 | 
 |  |  |   MenuFoldOutlined,
 | 
 |  |  | 
 |  |  |   ...Icons,
 | 
 |  |  | };
 | 
 |  |  | 
 | 
 |  |  | 
 | 
 |  |  | 
 | 
 |  |  | onMounted(() => {
 | 
 |  |  |   let name = router.currentRoute.value.name;
 | 
 |  |  |   let path = router.currentRoute.value.path;
 | 
 |  |  | 
 |  |  |   }
 | 
 |  |  | })
 | 
 |  |  | 
 | 
 |  |  | 
 | 
 |  |  | const state = reactive({
 | 
 |  |  |     rootSubmenuKeys: [],
 | 
 |  |  |     openKeys: ["/"],
 | 
 |  |  |     selectedKeys: [],
 | 
 |  |  | });
 | 
 |  |  | 
 | 
 |  |  | getMenu()
 | 
 |  |  | function getMenu() {
 | 
 |  |  |   get('/api/auth/menu', {}).then((result) => {
 | 
 |  |  |     menuCache.value = result.data.data;
 | 
 |  |  |     let routes = menuCache.value.map(item =>{
 | 
 |  |  |         return item.route
 | 
 |  |  |     })
 | 
 |  |  |       routes.unshift('/')
 | 
 |  |  |       state.rootSubmenuKeys = routes
 | 
 |  |  |       console.log(state.rootSubmenuKeys)
 | 
 |  |  |   })
 | 
 |  |  | }
 | 
 |  |  | 
 | 
 |  |  | 
 |  |  |   selectedKeys.value = [item.key]
 | 
 |  |  | 
 | 
 |  |  |   // open menu
 | 
 |  |  |   let arr = item.key.split("/");
 | 
 |  |  |   let key = '/' + arr[1];
 | 
 |  |  |   openKeys.value = [key]
 | 
 |  |  |   // let arr = item.key.split("/");
 | 
 |  |  |   // let key = '/' + arr[1];
 | 
 |  |  |   // openKeys.value = [key]
 | 
 |  |  | }
 | 
 |  |  | 
 | 
 |  |  | const switchLocale = async (locale) => {
 | 
 |  |  | 
 |  |  |   }
 | 
 |  |  | }
 | 
 |  |  | 
 | 
 |  |  | const onOpenChange = (openKeys) => {
 | 
 |  |  |     const latestOpenKey = openKeys.find(
 | 
 |  |  |         (key) => state.openKeys.indexOf(key) === -1
 | 
 |  |  |     );
 | 
 |  |  |     if (state.rootSubmenuKeys.indexOf(latestOpenKey) === -1) {
 | 
 |  |  |         state.openKeys = openKeys
 | 
 |  |  |     } else {
 | 
 |  |  |         state.openKeys = latestOpenKey ? [latestOpenKey] : [];
 | 
 |  |  |     }
 | 
 |  |  |     console.log(state.openKeys)
 | 
 |  |  | }
 | 
 |  |  | 
 | 
 |  |  | 
 | 
 |  |  | </script>
 | 
 |  |  | 
 | 
 |  |  | <template>
 | 
 |  |  |   <a-layout class="main">
 | 
 |  |  |     <a-layout-sider class="main-sider" v-model:collapsed="collapsed" :trigger="null" collapsible theme="dark">
 | 
 |  |  |       <div class="logo" />
 | 
 |  |  |       <a-menu v-model:openKeys="openKeys" v-model:selectedKeys="selectedKeys" @select="menuSelect" theme="dark"
 | 
 |  |  |         mode="inline">
 | 
 |  |  |         <div>
 | 
 |  |  |           <a-menu-item key="/" name="主页">
 | 
 |  |  |             <HomeOutlined /> {{ formatMessage('common.home', '主页') }}
 | 
 |  |  |           </a-menu-item>
 | 
 |  |  |         </div>
 | 
 |  |  |   <a-flex gap="middle" horizontal>
 | 
 |  |  |       <div class="sider-style">
 | 
 |  |  |         <a-layout-sider class="main-sider" v-model:collapsed="collapsed" :trigger="null"  theme="dark">
 | 
 |  |  |         <div class="logo" />
 | 
 |  |  |         <a-menu v-model:openKeys="state.openKeys" v-model:selectedKeys="state.selectedKeys"  @select="menuSelect"  theme="dark"
 | 
 |  |  |                 mode="inline" @openChange="onOpenChange">
 | 
 |  |  |           <div>
 | 
 |  |  |             <a-menu-item key="/" name="主页">
 | 
 |  |  |               <HomeOutlined /> {{ formatMessage('common.home', '主页') }}
 | 
 |  |  |             </a-menu-item>
 | 
 |  |  |           </div>
 | 
 |  |  | 
 | 
 |  |  |         <div v-for="(item, index) in menuCache" :key="index">
 | 
 |  |  |           <a-sub-menu :key="item.route" v-if="item.type == 0">
 | 
 |  |  |             <template #title>
 | 
 |  |  |           <div v-for="(item, index) in menuCache" :key="index">
 | 
 |  |  |             <a-sub-menu :key="item.route" v-if="item.type == 0">
 | 
 |  |  |               <template #title>
 | 
 |  |  |               <span>
 | 
 |  |  |                 <component :is="components[ref(item.icon).value]" />
 | 
 |  |  |                 {{ formatMessage(item.languageId, item.name) }}
 | 
 |  |  |               </span>
 | 
 |  |  |             </template>
 | 
 |  |  |             <div v-for="(child, idx) in item.children">
 | 
 |  |  |               <a-menu-item v-if="child.status == 1" :key="child.route" :name="child.name"
 | 
 |  |  |                 :languageId="child.languageId">
 | 
 |  |  |                 {{ formatMessage(child.languageId, child.name) }}
 | 
 |  |  |               </a-menu-item>
 | 
 |  |  |             </div>
 | 
 |  |  |           </a-sub-menu>
 | 
 |  |  |         </div>
 | 
 |  |  |       </a-menu>
 | 
 |  |  | 
 | 
 |  |  |     </a-layout-sider>
 | 
 |  |  |     <a-layout>
 | 
 |  |  |       <a-layout-header style="background: #fff; padding: 0;">
 | 
 |  |  |         <div class="header-top">
 | 
 |  |  |           <div class="header-top-left">
 | 
 |  |  |             <MenuUnfoldOutlined v-if="collapsed" class="trigger triggerLarge" @click="() => (collapsed = !collapsed)" />
 | 
 |  |  |             <MenuFoldOutlined v-else class="trigger" @click="() => (collapsed = !collapsed)" />
 | 
 |  |  |             <RedoOutlined class="trigger" @click="windowReload()" />
 | 
 |  |  |               </template>
 | 
 |  |  |               <div v-for="(child, idx) in item.children">
 | 
 |  |  |                 <a-menu-item v-if="child.status == 1" :key="child.route" :name="child.name"
 | 
 |  |  |                              :languageId="child.languageId">
 | 
 |  |  |                   {{ formatMessage(child.languageId, child.name) }}
 | 
 |  |  |                 </a-menu-item>
 | 
 |  |  |               </div>
 | 
 |  |  |             </a-sub-menu>
 | 
 |  |  |           </div>
 | 
 |  |  |           <div class="header-top-right">
 | 
 |  |  |             <div class="trigger" style="color: red;" v-if="licenseDays <= 30">
 | 
 |  |  |               许可证有效期:{{ licenseDays }}天
 | 
 |  |  |         </a-menu>
 | 
 |  |  |       </a-layout-sider>
 | 
 |  |  |       </div>
 | 
 |  |  |     <a-layout class="main">
 | 
 |  |  |       <a-layout>
 | 
 |  |  |         <a-layout-header style="background: #fff; padding: 0;">
 | 
 |  |  |           <div class="header-top">
 | 
 |  |  |             <div class="header-top-left">
 | 
 |  |  |               <MenuUnfoldOutlined v-if="collapsed" class="trigger triggerLarge" @click="() => (collapsed = !collapsed)" />
 | 
 |  |  |               <MenuFoldOutlined v-else class="trigger" @click="() => (collapsed = !collapsed)" />
 | 
 |  |  |               <RedoOutlined class="trigger" @click="windowReload()" />
 | 
 |  |  |             </div>
 | 
 |  |  |             <div class="trigger" v-if="globalState.currentHost">
 | 
 |  |  |               <a-dropdown>
 | 
 |  |  |                 <div>
 | 
 |  |  |                   <ApartmentOutlined />
 | 
 |  |  |                   {{ globalState.currentHost?.name }}
 | 
 |  |  |                 </div>
 | 
 |  |  |                 <template #overlay>
 | 
 |  |  |                   <a-menu>
 | 
 |  |  |                     <a-menu-item v-for="(item, index) in hostList" :key="index" @click="switchHost(item)"
 | 
 |  |  |                       :class="globalState.currentHost?.id == item.id ? 'active' : ''">{{ item.name }}</a-menu-item>
 | 
 |  |  |                   </a-menu>
 | 
 |  |  |                 </template>
 | 
 |  |  |               </a-dropdown>
 | 
 |  |  |             </div>
 | 
 |  |  |             <div class="trigger">
 | 
 |  |  |               <a-dropdown>
 | 
 |  |  |                 <div>
 | 
 |  |  |                   <TranslationOutlined />
 | 
 |  |  |                   {{ globalState.localeList[globalState.locale]?.desc }}
 | 
 |  |  |                 </div>
 | 
 |  |  |                 <template #overlay>
 | 
 |  |  |                   <a-menu>
 | 
 |  |  |                     <div v-for="(item, key) in globalState.localeList" :key="key">
 | 
 |  |  |                       <a-menu-item @click="switchLocale(key)" :class="globalState.locale == key ? 'active' : ''">{{
 | 
 |  |  |                         item.desc }}</a-menu-item>
 | 
 |  |  |                     </div>
 | 
 |  |  |                   </a-menu>
 | 
 |  |  |                 </template>
 | 
 |  |  |               </a-dropdown>
 | 
 |  |  |             </div>
 | 
 |  |  |             <div>
 | 
 |  |  |               <a-dropdown>
 | 
 |  |  |                 <a class="header-user" @click.prevent>
 | 
 |  |  |                   <UserOutlined />
 | 
 |  |  |                   <span>{{ globalState.user.username }}</span>
 | 
 |  |  |                 </a>
 | 
 |  |  |                 <template #overlay>
 | 
 |  |  |                   <a-menu @click="logout">
 | 
 |  |  |                     <a-menu-item key="logout">{{ formatMessage('common.account.logout', '退出') }}</a-menu-item>
 | 
 |  |  |                   </a-menu>
 | 
 |  |  |                 </template>
 | 
 |  |  |               </a-dropdown>
 | 
 |  |  |             </div>
 | 
 |  |  |           </div>
 | 
 |  |  |         </div>
 | 
 |  |  |       </a-layout-header>
 | 
 |  |  |       <a-layout-content class="content-view">
 | 
 |  |  |         <div class="tabs-fixed">
 | 
 |  |  |           <div class="tabs-arrow-left" @click="handleScroll('left')">
 | 
 |  |  |             <CaretLeftOutlined />
 | 
 |  |  |           </div>
 | 
 |  |  | 
 | 
 |  |  |           <div class="tabs-content" ref="tabsContent">
 | 
 |  |  |             <div class="tabs-content-item">
 | 
 |  |  |               <div v-for="(item, index) in routerCacheList" :key="index" @click="switchTabs(item)" class="tabs-item"
 | 
 |  |  |                 :class="currentCache == item.name ? 'tabs-item-active' : ''">
 | 
 |  |  |                 <div :class="currentCache == item.name ? '' : 'tabs-item-reload-none'" @click="reloadTabs" @click.stop>
 | 
 |  |  |                   <RedoOutlined />
 | 
 |  |  |                 </div>
 | 
 |  |  |                 <div>{{ formatMessage(item.languageId, item.name) }}</div>
 | 
 |  |  |                 <div @click="closeTabs(item)" @click.stop>
 | 
 |  |  |                   <CloseOutlined />
 | 
 |  |  |                 </div>
 | 
 |  |  |             <div class="header-top-right">
 | 
 |  |  |               <div class="trigger" style="color: red;" v-if="licenseDays <= 30">
 | 
 |  |  |                 许可证有效期:{{ licenseDays }}天
 | 
 |  |  |               </div>
 | 
 |  |  |               <div class="trigger" v-if="globalState.currentHost">
 | 
 |  |  |                 <a-dropdown>
 | 
 |  |  |                   <div>
 | 
 |  |  |                     <ApartmentOutlined />
 | 
 |  |  |                     {{ globalState.currentHost?.name }}
 | 
 |  |  |                   </div>
 | 
 |  |  |                   <template #overlay>
 | 
 |  |  |                     <a-menu>
 | 
 |  |  |                       <a-menu-item v-for="(item, index) in hostList" :key="index" @click="switchHost(item)"
 | 
 |  |  |                                    :class="globalState.currentHost?.id == item.id ? 'active' : ''">{{ item.name }}</a-menu-item>
 | 
 |  |  |                     </a-menu>
 | 
 |  |  |                   </template>
 | 
 |  |  |                 </a-dropdown>
 | 
 |  |  |               </div>
 | 
 |  |  |               <div class="trigger">
 | 
 |  |  |                 <a-dropdown>
 | 
 |  |  |                   <div>
 | 
 |  |  |                     <TranslationOutlined />
 | 
 |  |  |                     {{ globalState.localeList[globalState.locale]?.desc }}
 | 
 |  |  |                   </div>
 | 
 |  |  |                   <template #overlay>
 | 
 |  |  |                     <a-menu>
 | 
 |  |  |                       <div v-for="(item, key) in globalState.localeList" :key="key">
 | 
 |  |  |                         <a-menu-item @click="switchLocale(key)" :class="globalState.locale == key ? 'active' : ''">{{
 | 
 |  |  |                           item.desc }}</a-menu-item>
 | 
 |  |  |                       </div>
 | 
 |  |  |                     </a-menu>
 | 
 |  |  |                   </template>
 | 
 |  |  |                 </a-dropdown>
 | 
 |  |  |               </div>
 | 
 |  |  |               <div>
 | 
 |  |  |                 <a-dropdown>
 | 
 |  |  |                   <a class="header-user" @click.prevent>
 | 
 |  |  |                     <UserOutlined />
 | 
 |  |  |                     <span>{{ globalState.user.username }}</span>
 | 
 |  |  |                   </a>
 | 
 |  |  |                   <template #overlay>
 | 
 |  |  |                     <a-menu @click="logout">
 | 
 |  |  |                       <a-menu-item key="logout">{{ formatMessage('common.account.logout', '退出') }}</a-menu-item>
 | 
 |  |  |                     </a-menu>
 | 
 |  |  |                   </template>
 | 
 |  |  |                 </a-dropdown>
 | 
 |  |  |               </div>
 | 
 |  |  |             </div>
 | 
 |  |  |           </div>
 | 
 |  |  |         </a-layout-header>
 | 
 |  |  |         <a-layout-content class="content-view">
 | 
 |  |  |           <div class="tabs-fixed">
 | 
 |  |  |             <div class="tabs-arrow-left" @click="handleScroll('left')">
 | 
 |  |  |               <CaretLeftOutlined />
 | 
 |  |  |             </div>
 | 
 |  |  | 
 | 
 |  |  |           <div class="tabs-arrow-right" @click="handleScroll('right')">
 | 
 |  |  |             <CaretRightOutlined />
 | 
 |  |  |             <div class="tabs-content" ref="tabsContent">
 | 
 |  |  |               <div class="tabs-content-item">
 | 
 |  |  |                 <div v-for="(item, index) in routerCacheList" :key="index" @click="switchTabs(item)" class="tabs-item"
 | 
 |  |  |                      :class="currentCache == item.name ? 'tabs-item-active' : ''">
 | 
 |  |  |                   <div :class="currentCache == item.name ? '' : 'tabs-item-reload-none'" @click="reloadTabs" @click.stop>
 | 
 |  |  |                     <RedoOutlined />
 | 
 |  |  |                   </div>
 | 
 |  |  |                   <div>{{ formatMessage(item.languageId, item.name) }}</div>
 | 
 |  |  |                   <div @click="closeTabs(item)" @click.stop>
 | 
 |  |  |                     <CloseOutlined />
 | 
 |  |  |                   </div>
 | 
 |  |  |                 </div>
 | 
 |  |  |               </div>
 | 
 |  |  |             </div>
 | 
 |  |  | 
 | 
 |  |  |             <div class="tabs-arrow-right" @click="handleScroll('right')">
 | 
 |  |  |               <CaretRightOutlined />
 | 
 |  |  |             </div>
 | 
 |  |  |           </div>
 | 
 |  |  |         </div>
 | 
 |  |  | 
 | 
 |  |  |         <router-view v-slot="{ Component, route }" v-if="isRouterAlive">
 | 
 |  |  |           <keep-alive :include="routerCache">
 | 
 |  |  |             <component :is="Component" @pageReload="reloadTabs" />
 | 
 |  |  |           </keep-alive>
 | 
 |  |  |         </router-view>
 | 
 |  |  |       </a-layout-content>
 | 
 |  |  |           <router-view v-slot="{ Component, route }" v-if="isRouterAlive">
 | 
 |  |  |             <keep-alive :include="routerCache">
 | 
 |  |  |               <component :is="Component" @pageReload="reloadTabs" />
 | 
 |  |  |             </keep-alive>
 | 
 |  |  |           </router-view>
 | 
 |  |  |         </a-layout-content>
 | 
 |  |  |       </a-layout>
 | 
 |  |  |     </a-layout>
 | 
 |  |  |   </a-layout>
 | 
 |  |  | 
 | 
 |  |  |   <AiView />
 | 
 |  |  |   </a-flex>
 | 
 |  |  |   <!--<AiView />-->
 | 
 |  |  | </template>
 | 
 |  |  | 
 | 
 |  |  | <style scoped></style>
 | 
 |  |  | <style scoped>
 | 
 |  |  |   .ant-layout-sider ant-layout-sider-dark main-sider {
 | 
 |  |  |      min-height: 100vh;
 | 
 |  |  |     background: #01101E;
 | 
 |  |  |   }
 | 
 |  |  | 
 | 
 |  |  | </style>
 |