ソースを参照

新主题更改

duy 1 年間 前
コミット
6e42e340be

+ 15 - 15
package.json

@@ -13,34 +13,34 @@
         "lint:fix": "eslint . --fix"
     },
     "dependencies": {
-        "axios": "^1.4.0",
-        "crypto-js": "^4.1.1",
+        "axios": "^1.6.0",
+        "crypto-js": "^4.2.0",
         "dayjs": "^1.11.9",
         "echarts": "^5.4.2",
         "element-plus": "2.3.14",
-        "hc-vue3-ui": "^2.0.9",
+        "hc-vue3-ui": "^2.3.4",
         "js-base64": "^3.7.5",
         "js-cookie": "^3.0.5",
         "js-fast-way": "^0.2.9",
-        "js-md5": "^0.7.3",
+        "js-md5": "^0.8.3",
         "nprogress": "^0.2.0",
-        "pinia": "^2.1.4",
+        "pinia": "^2.1.7",
         "split.js": "^1.6.5",
-        "vue": "^3.3.4",
-        "vue-router": "^4.2.4"
+        "vue": "^3.3.7",
+        "vue-router": "^4.2.5"
     },
     "devDependencies": {
-        "@vitejs/plugin-vue": "^4.2.3",
-        "@vue/compiler-sfc": "^3.3.4",
+        "@vitejs/plugin-vue": "^4.4.0",
+        "@vue/compiler-sfc": "^3.3.7",
         "archiver": "^6.0.1",
         "autoprefixer": "^10.4.16",
         "cssnano": "^6.0.1",
-        "eslint": "^8.44.0",
-        "eslint-plugin-vue": "^9.15.1",
-        "postcss": "^8.4.26",
-        "sass": "^1.63.6",
-        "tailwindcss": "3.3.3",
-        "vite": "^4.4.4",
+        "eslint": "^8.52.0",
+        "eslint-plugin-vue": "^9.18.1",
+        "postcss": "^8.4.31",
+        "sass": "^1.69.5",
+        "tailwindcss": "3.3.5",
+        "vite": "^4.5.0",
         "z-element-plus": "^1.1.3"
     }
 }

+ 9 - 0
src/api/modules/other.js

@@ -76,3 +76,12 @@ export const getDictInfo = (code) => httpApi({
     },
 }, false)
 
+
+//获取租户详情
+export const getTenantDetail = (id) => httpApi({
+    url: '/api/blade-system/tenant/detail',
+    method: 'get',
+    params: {
+        tenantId: id,
+    },
+}, true)

+ 9 - 6
src/config/theme.js

@@ -1,10 +1,13 @@
 //主题配置
 export default {
     color: [
-        {name: 'green', color: '#1ECC95', label: '森绿'}, {name: 'blue', color: '#0081ff', label: '海蓝'},
-        {name: 'cyan', color: '#37c0fe', label: '天青'}, {name: 'purple', color: '#8044de', label: '姹紫'},
-        {name: 'mauve', color: '#b745cb', label: '木槿'}, {name: 'pink', color: '#e03997', label: '桃粉'},
-        {name: 'red', color: '#e54d42', label: '嫣红'}, {name: 'orange', color: '#f37b1d', label: '橘橙'},
-        {name: 'yellow', color: '#fbbd08', label: '明黄'}, {name: 'brown', color: '#a5673f', label: '棕褐'}
-    ]
+        // {name: 'green', color: '#1ECC95', label: '森绿'}, {name: 'blue', color: '#0081ff', label: '海蓝'},
+        // {name: 'cyan', color: '#37c0fe', label: '天青'}, {name: 'purple', color: '#8044de', label: '姹紫'},
+        // {name: 'mauve', color: '#b745cb', label: '木槿'}, {name: 'pink', color: '#e03997', label: '桃粉'},
+        // {name: 'red', color: '#e54d42', label: '嫣红'}, {name: 'orange', color: '#f37b1d', label: '橘橙'},
+        // {name: 'yellow', color: '#fbbd08', label: '明黄'}, {name: 'brown', color: '#a5673f', label: '棕褐'}
+        { name: 'blue', color: '#204DA0', label: '深蓝' },
+        { name: 'light-blue', color: '#409eff', label: '浅蓝' },
+        { name: 'black1', color: '#2c3643', label: '黑色' },
+    ],
 }

+ 2 - 2
src/global/components/tree-data/index.vue

@@ -23,7 +23,7 @@
     <!-- 右键菜单 -->
     <HcContextMenu v-if="isMenus" ref="contextMenuRef" :datas="treeMenu" @closed="handleMenuClosed" @item-click="handleMenuSelect" />
     <!-- 新增/编辑 -->
-    <HcDialog is-to-body bg-color="white" :show="rowModal" :title="formModel.id ? '编辑区域' : '新增区域'" widths="30rem" :loading="submitLoading" @save="rowModalSave" @close="rowModalClose">
+    <hc-new-dialog is-to-body bg-color="white" :show="rowModal" :title="formModel.id ? '编辑区域' : '新增区域'" widths="30rem" :loading="submitLoading" @save="rowModalSave" @close="rowModalClose">
         <el-form ref="formRef" :model="formModel" :rules="formRules" label-position="top" size="large">
             <el-form-item label="区域名称:" prop="key">
                 <el-input v-model="formModel.areaName" />
@@ -40,7 +40,7 @@
                 <el-input v-model="formModel.remark" type="textarea" :autosize="{ minRows: 3, maxRows: 5 }" />
             </el-form-item>
         </el-form>
-    </HcDialog>
+    </hc-new-dialog>
 </template>
 
 <script setup>

+ 460 - 0
src/layout/index.scss

@@ -0,0 +1,460 @@
+.hc-layout-box {
+    position: relative;
+    height: 100vh;
+    width: 100%;
+    .hc-layout-header {
+        position: relative;
+        display: flex;
+        align-items: center;
+        flex-direction: row;
+        --el-header-padding: 0;
+        --el-header-height: 44px;
+        background: var(--el-color-primary);
+        color: white;
+        .hc-layout-header-logo {
+            position: relative;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            transition: opacity 0.3s;
+            cursor: pointer;
+            height: 100%;
+            box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.4);
+            z-index: 222;
+            #logo-icon {
+                height: 28px;
+                width: 28px;
+                filter: invert(85%) sepia(91%) saturate(0%) hue-rotate(233deg) brightness(114%) contrast(101%) !important
+            }
+            #logo-name {
+                height: 32px;
+                margin-left: 4px;
+                filter: invert(85%) sepia(91%) saturate(0%) hue-rotate(233deg) brightness(114%) contrast(101%)
+            }
+            &:hover {
+                opacity: .8;
+            }
+        }
+        .header-top-collapse-bar {
+            position: relative;
+            height: 100%;
+            font-size: 20px;
+            display: flex;
+            justify-content: center;
+            align-items: center;
+            padding: 0 10px;
+            cursor: pointer;
+            transition: opacity .2s;
+            &:hover {
+                opacity: 0.7;
+            }
+        }
+        .header-top-menu-bar {
+            position: relative;
+            padding: 0 4px;
+            height: 100%;
+            flex: 1;
+            .el-scrollbar__view {
+                height: 100%;
+            }
+        }
+        .header-content-bar {
+            position: absolute;
+            right: 0;
+            // position: relative;
+            padding: 0 20px;
+            height: 100%;
+            display: flex;
+            align-items: center;
+            .header-icon-bar {
+                position: relative;
+                height: 100%;
+                display: flex;
+                justify-content: center;
+                align-items: center;
+                cursor: pointer;
+                font-size: 25px;
+                margin-right: 8px;
+                color: #efefef;
+                transition: color .2s;
+                &:hover {
+                    color: white;
+                }
+            }
+        }
+    }
+    .hc-layout-container {
+        position: relative;
+        .hc-layout-aside {
+            position: relative;
+            color: white;
+            padding: 8px 0;
+            background: var(--el-color-primary);
+        }
+        .hc-layout-main {
+            position: relative;
+            overflow: hidden;
+            height: 100%;
+            --el-main-padding: 0;
+            .hc-router-menu-bar {
+                position: relative;
+                height: 36px;
+                padding: 0 10px;
+                background: white;
+                box-shadow: 0 2px 6px 0 rgba(0, 0, 0, .1);
+                z-index: 222;
+            }
+            .hc-main-page {
+                position: relative;
+                height: calc(100% - 36px);
+                overflow: hidden;
+                .hc-main-body {
+                    position: absolute;
+                    padding: 12px;
+                    inset: 0;
+                }
+            }
+        }
+    }
+}
+
+//左侧菜单
+.hc-layout-box .hc-layout-container .hc-layout-aside .el-menu {
+    --el-menu-bg-color: transparent;
+    --el-menu-text-color: #ffffff;
+    --el-menu-active-color: var(--el-menu-text-color);
+    --el-menu-hover-text-color: var(--el-menu-text-color);
+    --el-menu-hover-bg-color: var(--el-color-primary);
+    --el-menu-item-font-size: 16px;
+    --el-menu-item-height: 48px;
+    border-right: 0;
+    &.el-menu--vertical:not(.el-menu--collapse):not(.el-menu--popup-container) .el-menu-item,
+    &.el-menu--vertical:not(.el-menu--collapse):not(.el-menu--popup-container) .el-menu-item-group__title,
+    &.el-menu--vertical:not(.el-menu--collapse):not(.el-menu--popup-container) .el-sub-menu__title {
+        white-space: nowrap;
+        padding-left: 0;
+    }
+    &.el-menu--vertical:not(.el-menu--collapse):not(.el-menu--popup-container) .el-sub-menu__title {
+        padding-right: 1px;
+        border: 0;
+    }
+    .el-sub-menu__title {
+        padding: 0;
+    }
+    .el-menu-item, .el-sub-menu {
+        min-width: initial;
+        transition: 0.2s;
+        .hc-aside-menu-item {
+            flex: 1;
+            position: relative;
+            padding: 0 20px;
+            display: flex;
+            align-items: center;
+            transition: 0.2s;
+            .menu---item {
+                display: contents;
+            }
+            .hc-menu-icon {
+                position: relative;
+                font-size: 18px;
+                margin-right: 8px;
+                line-height: initial;
+            }
+            .name {
+                flex: 1;
+                width: 0;
+            }
+            .el-badge {
+                position: absolute;
+                top: -22px;
+                right: 0;
+                vertical-align: initial;
+            }
+        }
+    }
+    .el-sub-menu .el-menu .el-menu-item {
+        padding-left: 24px !important;
+        padding-right: 1px;
+        font-size: 14px;
+        height: 46px;
+        line-height: initial;
+        .hc-aside-menu-item .hc-menu-icon {
+            margin-right: 6px;
+            font-size: 14px;
+        }
+    }
+    .el-sub-menu .el-icon {
+        display: none;
+    }
+    .el-sub-menu .el-icon.hc-icon-i {
+        position: relative;
+        display: inline-block;
+        font-size: 16px;
+        right: 15px;
+        top: initial;
+        height: initial;
+        width: initial;
+        margin-top: 0;
+        vertical-align: initial;
+    }
+    .el-sub-menu.is-active > .el-sub-menu__title {
+        background-color: var(--el-color-primary-light-3);
+    }
+    .el-menu-item.is-active {
+        background-color: var(--el-color-primary-dark-2);
+        &::after {
+            content: '';
+            position: absolute;
+            right: 0;
+            top: 0;
+            width: 3px;
+            height: 100%;
+            background-color: white;
+        }
+    }
+    .el-sub-menu .el-sub-menu__title:hover,
+    .el-menu-item:not(.is-active):hover {
+        background-color: var(--el-color-primary-dark-2);
+    }
+    //折叠状态
+    &.el-menu--collapse {
+        margin-left: 0;
+        width: 90px;
+        .el-sub-menu__title {
+            height: inherit;
+            line-height: initial;
+            width: 90px;
+            justify-content: center;
+            transition: 0.2s;
+        }
+        .el-menu-item, .el-sub-menu {
+            padding: 0 !important;
+            height: 60px;
+            line-height: initial;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            width: 90px;
+            transition: 0.2s;
+            .hc-aside-menu-item {
+                display: inline-flex;
+                align-items: center;
+                justify-content: center;
+                width: 60px;
+                height: 60px;
+                text-align: center;
+                border-radius: 10px;
+                padding: 5px;
+                flex: initial;
+                transition: 0.2s;
+                .menu---item {
+                    position: relative;
+                    display: block;
+                }
+                .hc-menu-icon {
+                    margin-right: 0;
+                }
+                .name {
+                    flex: initial;
+                    width: 100%;
+                }
+                .el-badge, .el-badge .el-badge__content {
+                    vertical-align: initial;
+                }
+                .el-badge {
+                    position: absolute;
+                    top: -20px;
+                    right: -24px;
+                }
+            }
+        }
+        .el-sub-menu .el-icon.hc-icon-i {
+            display: none;
+        }
+        .el-menu-item + .el-menu-item,
+        .el-menu-item + .el-sub-menu,
+        .el-sub-menu + .el-menu-item,
+        .el-sub-menu + .el-sub-menu {
+            margin-top: 12px;
+        }
+        .el-sub-menu.is-active > .el-sub-menu__title {
+            background-color: initial;
+        }
+        .el-menu-item.is-active {
+            background-color: initial;
+        }
+        .el-sub-menu .el-sub-menu__title:hover,
+        .el-menu-item:not(.is-active):hover {
+            background-color: initial;
+        }
+        .el-sub-menu:not(.is-active):hover,
+        .el-menu-item:not(.is-active):hover {
+            .hc-aside-menu-item {
+                background-color: var(--el-color-primary-light-9);
+                color: var(--el-color-primary);
+            }
+        }
+        .el-menu-item.is-active, .el-sub-menu.is-active {
+            .hc-aside-menu-item {
+                color: #ffffff !important;
+                background: var(--el-color-primary-dark-2);
+            }
+        }
+    }
+}
+
+//菜单路由
+.hc-layout-box .hc-layout-container .hc-layout-main .hc-router-menu-bar {
+    .el-scrollbar__view {
+        height: 100%;
+    }
+    .hc-router-tab-box {
+        position: relative;
+        display: flex;
+        align-items: center;
+        white-space: nowrap;
+        height: 100%;
+        font-size: 14px;
+    }
+    .hc-router-tab-item {
+        position: relative;
+        height: 100%;
+        padding: 0 8px;
+        display: inline-flex;
+        align-items: center;
+        cursor: pointer;
+        color: #8F8F8F;
+        user-select: none;
+        transition: .3s;
+        .close-icon {
+            height: 30px;
+            width: 18px;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            margin-left: 6px;
+            font-size: 16px;
+            cursor: pointer;
+            transition: color 0.3s;
+            &:hover {
+                color: var(--el-color-primary);
+            }
+        }
+        &::after{
+            content: '';
+            left: 0;
+            bottom: 0;
+            height: 2.5px;
+            width: 100%;
+            position: absolute;
+            background-size: 200%;
+        }
+        &:hover:not([class*='cur']) {
+            color: var(--el-color-primary);
+        }
+        &.cur {
+            color: var(--el-color-primary-dark-2);
+            &::after {
+                background: linear-gradient(to right, var(--el-color-primary-light-5), var(--el-color-primary), var(--el-color-primary-dark-2));
+            }
+        }
+    }
+    .el-scrollbar__bar.is-horizontal {
+        bottom: -10px;
+    }
+    .el-scrollbar__bar.is-vertical {
+        display: none;
+    }
+}
+
+
+.aside-menu-popper.el-popper.is-light {
+    background: initial !important;
+    border: 0 !important;
+    outline: none;
+}
+.aside-menu-popper.el-popper .el-menu--vertical .el-menu {
+    --el-menu-bg-color: #f1f5f8;
+    --el-menu-text-color: #838791;
+    --el-menu-active-color: #ffffff;
+    --el-menu-hover-bg-color: initial;
+    --el-menu-item-font-size: 16px;
+    background-color: #f1f5f8;
+    color: #838791;
+    .el-sub-menu__title {
+        padding: 0;
+        justify-content: center;
+        transition: 0.2s;
+    }
+    .el-menu-item, .el-sub-menu {
+        color: inherit;
+        padding: 0;
+        transition: 0.2s;
+        .hc-aside-menu-item {
+            flex: 1;
+            position: relative;
+            padding: 0 16px;
+            display: flex;
+            align-items: center;
+            transition: 0.2s;
+            .menu---item {
+                display: contents;
+            }
+            .hc-menu-icon {
+                font-size: 22px;
+                margin-right: 10px;
+                line-height: initial;
+            }
+            .name {
+                flex: 1;
+                width: 0;
+            }
+            .el-badge, .el-badge .el-badge__content {
+                vertical-align: initial;
+            }
+        }
+        &.is-active {
+            color: white;
+        }
+    }
+    .el-sub-menu .el-icon {
+        display: none;
+    }
+    .el-sub-menu .el-icon.hc-icon-i {
+        position: relative;
+        display: inline-block;
+        font-size: 16px;
+        right: 10px;
+        top: initial;
+        height: initial;
+        width: initial;
+        margin-top: 0;
+        vertical-align: initial;
+    }
+    .el-sub-menu:not(.is-active) .el-sub-menu__title:hover {
+        background-color: var(--el-color-primary-light-9);
+        color: var(--el-color-primary);
+    }
+    .el-menu-item:not(.is-active):hover {
+        .hc-aside-menu-item {
+            background-color: var(--el-color-primary-light-9);
+            color: var(--el-color-primary);
+        }
+    }
+    .el-menu-item.is-active {
+        .hc-aside-menu-item {
+            background-color: var(--el-color-primary);
+        }
+    }
+    .el-sub-menu.is-active .el-sub-menu__title {
+        background-color: var(--el-color-primary-light-9);
+        color: var(--el-color-primary);
+    }
+}
+
+.aside-menu-popper.el-popper .el-menu--vertical.home-index .el-menu {
+    --el-menu-bg-color: initial;
+    --el-menu-text-color: initial;
+    color: white;
+    background-color: var(--el-color-primary-dark-2);
+}

+ 101 - 109
src/layout/index.vue

@@ -1,74 +1,67 @@
 <template>
     <el-container class="hc-layout-box">
-        <el-aside :class="[isCollapse?'is-collapse':'']" :width="isCollapse?'90px':'250px'"
-                  class="hc-aside-box">
-            <div class="hc-aside-logo-box" @click="logoClick">
-                <img :src="logoIcon" alt="" id="logo-icon">
-                <img :src="logoName" alt="" id="logo-name" v-if="!isCollapse">
+        <el-header class="hc-layout-header">
+            <div class="hc-layout-header-logo" :style="`width: ${isCollapse ? '90px' : '200px'};`" @click="logoClick">
+                <img id="logo-icon" :src="logoIcon" alt="">
+                <img v-show="!isCollapse" id="logo-name" :src="logoName" alt="">
             </div>
-            <div class="hc-aside-menu-box">
-                <el-scrollbar>
-                    <MenuBar :collapse="isCollapse" :cur="MenuBarKey" :datas="MenuBarData" @change="MenuBarChange"/>
-                </el-scrollbar>
+            <div class="header-top-collapse-bar" @click="collapseChange">
+                <HcIcon v-if="isCollapse" name="menu-unfold" />
+                <HcIcon v-else name="menu-fold" />
             </div>
-            <div class="hc-aside-bar-box">
-                <div :class="isCollapse?'':'active'" @click="collapseChange(false)">
-                    <HcIcon name="menu-unfold"/>
-                </div>
-                <div v-show="!isCollapse" :class="isCollapse?'active':''" @click="collapseChange(true)">
-                    <HcIcon name="menu-fold"/>
-                </div>
+            <div class="header-top-menu-bar">
+                <HcTopMenuBar @load="topMenuLoad" @change="topMenuChange" />
             </div>
-        </el-aside>
-        <el-container class="hc-container-view">
-            <el-header class="hc-header-view">
-                <div id="hc-header-page-name" class="hc-header-page-name">{{ RoutesTitle }}</div>
-                <div class="hc-header-top-menu-bar">
-                    <TopMenuBar/>
+
+            <div class="header-content-bar">
+                <HcCascader @send="cascaderSend" @change="cascaderChange" />
+                <HelpInfoBar />
+                <ConfigBar />
+                <UserInfoBar />
+            </div>
+        </el-header>
+        <el-container class="hc-layout-container">
+            <el-aside class="hc-layout-aside" :class="[isCollapse ? 'is-collapse' : '']" :width="isCollapse ? '90px' : '200px'">
+                <MenuBar :collapse="isCollapse" :cur="MenuBarKey" :datas="MenuBarData" @change="MenuBarChange" />
+            </el-aside>
+            <el-main class="hc-layout-main">
+                <div class="hc-router-menu-bar">
+                    <TopMenuBar />
                 </div>
-                <div class="hc-header-content">
-                    <div class="hc-header-cascader-box">
-                        <div class="project-name-box">{{ projectInfo.projectAlias }} / {{ contractInfo.name }}</div>
-                        <el-cascader ref="ElCascaderRef" v-model="projectValue"
-                                     :clearable="userInfo?.role_id === '1123598816738675201'"
-                                     :filterable="userInfo?.role_id === '1123598816738675201'"
-                                     :options="projectContract"
-                                     :props="projectProps" placeholder="请选择项目"
-                                     @change="projectContractChange"/>
+                <div id="hc-main-box" class="hc-main-page">
+                    <div class="hc-main-body">
+                        <router-view v-if="reloadRouter" v-slot="{ Component }">
+                            <transition name="fade-transform">
+                                <keep-alive :max="10">
+                                    <component :is="Component" />
+                                </keep-alive>
+                            </transition>
+                        </router-view>
                     </div>
-                    <HelpInfoBar></HelpInfoBar>
-                    <ConfigBar></ConfigBar>
-                    <UserInfoBar></UserInfoBar>
                 </div>
-            </el-header>
-            <el-main id="hc-main-box" class="hc-main-box">
-                <router-view v-if="reloadRouter" v-slot="{ Component }">
-                    <transition name="fade-transform">
-                        <keep-alive :max="10" exclude="home">
-                            <component :is="Component"/>
-                        </keep-alive>
-                    </transition>
-                </router-view>
             </el-main>
         </el-container>
     </el-container>
 </template>
 
 <script setup>
-import {onMounted, ref, nextTick, watch} from "vue";
-import {useRouter, useRoute} from 'vue-router'
-import {useAppStore} from "~src/store";
-import MenuBar from "./modules/MenuBar.vue"
-import HelpInfoBar from "./modules/HelpInfoBar.vue"
-import UserInfoBar from "./modules/UserInfoBar.vue"
-import ConfigBar from "./modules/ConfigBar.vue"
-import TopMenuBar from "./modules/TopMenuBar.vue"
-import logoIcon from "~src/assets/logo/icon.png";
-import logoName from "~src/assets/logo/name.png";
-import {initButtons, initProjectContract} from "~sto/app";
+import { nextTick, onMounted, ref, watch } from 'vue'
+import { useRoute, useRouter } from 'vue-router'
+import { useAppStore } from '~src/store'
+import MenuBar from './modules/MenuBar.vue'
+import HelpInfoBar from './modules/HelpInfoBar.vue'
+import UserInfoBar from './modules/UserInfoBar.vue'
+import ConfigBar from './modules/ConfigBar.vue'
+import TopMenuBar from './modules/TopMenuBar.vue'
+import logoIcon from '~src/assets/logo/icon.png'
+import logoName from '~src/assets/logo/name.png'
+import { initButtons, initProjectContract } from '~sto/app'
 import website from '~src/config/index'
-import {setImageColorStyle} from "js-fast-way";
-import {setAppName} from "~uti/tools";
+import { isNullES, setImageColorStyle } from 'js-fast-way'
+import { setAppName } from '~uti/tools'
+import HcCascader from './modules/Cascader.vue'
+import HcSocket from '~src/plugins/HcSocket'
+import HcTopMenuBar from './modules/HcTopMenu.vue'
 
 //初始组合式
 const router = useRouter()
@@ -76,10 +69,10 @@ const useRoutes = useRoute()
 const useAppState = useAppStore()
 
 //路由参数
-const routerQuery = useRoutes?.query;
+const routerQuery = useRoutes?.query
 const reloadRouter = ref(true)
-const BarMenuKey = useRoutes?.name ?? 'home-index';
-const BarMenuTitle = useRoutes?.meta?.title ?? '';
+const BarMenuKey = useRoutes?.name ?? 'home-index'
+const BarMenuTitle = useRoutes?.meta?.title ?? ''
 
 //系统信息
 const appTitle = ref(useAppState.getTitle)
@@ -87,20 +80,20 @@ const appLogoIcon = ref(useAppState.getLogoIcon)
 const appLogoName = ref(useAppState.getLogoName)
 
 //主题和色调变量
-const AppColor = ref(useAppState.getColor);
+const AppColor = ref(useAppState.getColor)
 
 //顶部菜单数据和相关处理
-const MenuBarKey = ref(BarMenuKey);
-const RoutesTitle = ref(BarMenuTitle);
+const MenuBarKey = ref(BarMenuKey)
+const RoutesTitle = ref(BarMenuTitle)
 const MenuBarData = ref(useAppState.getMenus)
 const isCollapse = ref(useAppState.getCollapse)
-const userInfo = ref(useAppState.getUserInfo);
+const userInfo = ref(useAppState.getUserInfo)
 
 //项目合同段
-const projectInfo = ref({});
-const contractInfo = ref({});
+const projectInfo = ref({})
+const contractInfo = ref({})
 const projectContract = ref([])
-const projectValue = ref(null);
+const projectValue = ref(null)
 const projectProps = ref({
     value: 'id',
     label: 'projectAlias',
@@ -112,7 +105,7 @@ onMounted(() => {
     initButtons()
     initProjectContract()
     const info = useAppState.getProjectContract || []
-    projectContractData(info);
+    projectContractData(info)
     useAppState.barMenuName = BarMenuTitle
     setLogoImageColor()
 })
@@ -129,7 +122,7 @@ watch(() => [
     MenuBarKey.value = RouteName ?? 'home-index'
     RoutesTitle.value = RouteTitle ?? ''
     isCollapse.value = collapse
-    projectContractData(projectContractArr || []);
+    projectContractData(projectContractArr || [])
     useAppState.barMenuName = RouteTitle ?? ''
     setAppName(appTitle.value)
 })
@@ -154,10 +147,24 @@ const setLogoImageColor = () => {
 }
 
 //是否折叠
-const collapseChange = (bool) => {
+const collapseChange = () => {
+    const bool = !isCollapse.value
     isCollapse.value = bool
+ 
     useAppState.setCollapse(bool)
 }
+//顶部菜单导航
+const isAsideMenu = ref(true)
+const topMenuLoad = () => {
+    isAsideMenu.value = false
+}
+//顶部菜单导航被点击
+const topMenuChange = (data) => {
+    if (!isNullES(data)) {
+        MenuBarData.value = data
+        isAsideMenu.value = true
+    }
+}
 
 //处理项目合同段数据
 const projectContractData = (projectContractData) => {
@@ -171,8 +178,8 @@ const projectContractData = (projectContractData) => {
         })
         //处理其他数据
         projectContract.value = projectContractData
-        const projectId = useAppState.getProjectId     //项目ID
-        const contractId = useAppState.getContractId   //合同段ID
+        const projectId = useAppState.getProjectId //项目ID
+        const contractId = useAppState.getContractId //合同段ID
         const UserProjectInfo = useAppState.getProjectInfo
         const UserContractInfo = useAppState.getContractInfo
         //查询缓存的选中ID是否存在
@@ -182,9 +189,9 @@ const projectContractData = (projectContractData) => {
         //如果缓存的选中ID不存在
         if (cid === -1) {
             //取项目数组中的第一个数据
-            let letProjectInfo = projectContractData[0];
+            let letProjectInfo = projectContractData[0]
             let contractInfoList = letProjectInfo?.contractInfoList || []
-            let letContractInfo = contractInfoList[0] || {};
+            let letContractInfo = contractInfoList[0] || {}
             projectValue.value = letContractInfo?.id
             projectInfo.value = letProjectInfo
             contractInfo.value = letContractInfo
@@ -210,9 +217,9 @@ const projectContractData = (projectContractData) => {
 const ElCascaderRef = ref(null)
 const projectContractChange = (val) => {
     if (val) {
-        const Nodes = ElCascaderRef.value.getCheckedNodes();
-        const UserProjectInfo = Nodes[0].parent.data;
-        const UserContractInfo = Nodes[0].data;
+        const Nodes = ElCascaderRef.value.getCheckedNodes()
+        const UserProjectInfo = Nodes[0].parent.data
+        const UserContractInfo = Nodes[0].data
         //缓存项目数据
         useAppState.setProjectId(val[0])
         useAppState.setContractId(val[1])
@@ -221,7 +228,7 @@ const projectContractChange = (val) => {
         //更改界面更新
         projectInfo.value = UserProjectInfo
         contractInfo.value = UserContractInfo
-        window.$message?.info('切换了项目,数据更新中');
+        window.$message?.info('切换了项目,数据更新中')
         //刷新路由
         reloadRouter.value = false
         nextTick(() => {
@@ -232,48 +239,33 @@ const projectContractChange = (val) => {
 
 //菜单被点击
 const MenuBarChange = (item) => {
-    MenuBarKey.value = item?.code;
-    router.push({name: item?.code});
+    MenuBarKey.value = item?.code
+    router.push({ name: item?.code })
 }
 
 //首页
 const logoClick = () => {
     router.push({
-        name: useAppState.homeUrl
-    });
+        name: useAppState.homeUrl,
+    })
+}
+// 项目切换
+const cascaderChange = () => {
+    reloadRouter.value = false
+    nextTick(() => {
+        reloadRouter.value = true
+    })
+}
+//项目合同段的ID
+const cascaderSend = ({ projectId, contractId }) => {
+    HcSocket.send(projectId + ',' + contractId)
 }
 </script>
 
 <style lang="scss" scoped>
-@import "./layout.scss";
+
 </style>
 
 <style lang="scss">
-.hc-layout-box .hc-container-view {
-    .hc-header-view .hc-header-content .hc-header-cascader-box {
-        .el-cascader {
-            width: 100%;
-            top: -10px;
-        }
-        .el-cascader .el-input .el-input__wrapper {
-            padding: 4px 15px;
-            border: 1px solid #00000000;
-            border-radius: 100px;
-            background: #f1f5f8;
-            color: #202532;
-            box-shadow: var(--hc-shadow);
-            .el-input__inner, .el-input__suffix {
-                color: #202532;
-            }
-        }
-        .el-cascader .el-input.is-focus .el-input__wrapper {
-            box-shadow: 4px 4px 8px 0 rgba(54, 92, 167, 0.15), -4px -4px 8px 0px #ffffff;
-        }
-        .el-cascader .el-input .icon-arrow-down {
-            font-size: 18px;
-            font-weight: bold;
-        }
-    }
-}
-
+@import "./index.scss";
 </style>

+ 279 - 0
src/layout/index_bak.vue

@@ -0,0 +1,279 @@
+<template>
+    <el-container class="hc-layout-box">
+        <el-aside :class="[isCollapse?'is-collapse':'']" :width="isCollapse?'90px':'250px'"
+                  class="hc-aside-box">
+            <div class="hc-aside-logo-box" @click="logoClick">
+                <img :src="logoIcon" alt="" id="logo-icon">
+                <img :src="logoName" alt="" id="logo-name" v-if="!isCollapse">
+            </div>
+            <div class="hc-aside-menu-box">
+                <el-scrollbar>
+                    <MenuBar :collapse="isCollapse" :cur="MenuBarKey" :datas="MenuBarData" @change="MenuBarChange"/>
+                </el-scrollbar>
+            </div>
+            <div class="hc-aside-bar-box">
+                <div :class="isCollapse?'':'active'" @click="collapseChange(false)">
+                    <HcIcon name="menu-unfold"/>
+                </div>
+                <div v-show="!isCollapse" :class="isCollapse?'active':''" @click="collapseChange(true)">
+                    <HcIcon name="menu-fold"/>
+                </div>
+            </div>
+        </el-aside>
+        <el-container class="hc-container-view">
+            <el-header class="hc-header-view">
+                <div id="hc-header-page-name" class="hc-header-page-name">{{ RoutesTitle }}</div>
+                <div class="hc-header-top-menu-bar">
+                    <TopMenuBar/>
+                </div>
+                <div class="hc-header-content">
+                    <div class="hc-header-cascader-box">
+                        <div class="project-name-box">{{ projectInfo.projectAlias }} / {{ contractInfo.name }}</div>
+                        <el-cascader ref="ElCascaderRef" v-model="projectValue"
+                                     :clearable="userInfo?.role_id === '1123598816738675201'"
+                                     :filterable="userInfo?.role_id === '1123598816738675201'"
+                                     :options="projectContract"
+                                     :props="projectProps" placeholder="请选择项目"
+                                     @change="projectContractChange"/>
+                    </div>
+                    <HelpInfoBar></HelpInfoBar>
+                    <ConfigBar></ConfigBar>
+                    <UserInfoBar></UserInfoBar>
+                </div>
+            </el-header>
+            <el-main id="hc-main-box" class="hc-main-box">
+                <router-view v-if="reloadRouter" v-slot="{ Component }">
+                    <transition name="fade-transform">
+                        <keep-alive :max="10" exclude="home">
+                            <component :is="Component"/>
+                        </keep-alive>
+                    </transition>
+                </router-view>
+            </el-main>
+        </el-container>
+    </el-container>
+</template>
+
+<script setup>
+import {onMounted, ref, nextTick, watch} from "vue";
+import {useRouter, useRoute} from 'vue-router'
+import {useAppStore} from "~src/store";
+import MenuBar from "./modules/MenuBar.vue"
+import HelpInfoBar from "./modules/HelpInfoBar.vue"
+import UserInfoBar from "./modules/UserInfoBar.vue"
+import ConfigBar from "./modules/ConfigBar.vue"
+import TopMenuBar from "./modules/TopMenuBar.vue"
+import logoIcon from "~src/assets/logo/icon.png";
+import logoName from "~src/assets/logo/name.png";
+import {initButtons, initProjectContract} from "~sto/app";
+import website from '~src/config/index'
+import {setImageColorStyle} from "js-fast-way";
+import {setAppName} from "~uti/tools";
+
+//初始组合式
+const router = useRouter()
+const useRoutes = useRoute()
+const useAppState = useAppStore()
+
+//路由参数
+const routerQuery = useRoutes?.query;
+const reloadRouter = ref(true)
+const BarMenuKey = useRoutes?.name ?? 'home-index';
+const BarMenuTitle = useRoutes?.meta?.title ?? '';
+
+//系统信息
+const appTitle = ref(useAppState.getTitle)
+const appLogoIcon = ref(useAppState.getLogoIcon)
+const appLogoName = ref(useAppState.getLogoName)
+
+//主题和色调变量
+const AppColor = ref(useAppState.getColor);
+
+//顶部菜单数据和相关处理
+const MenuBarKey = ref(BarMenuKey);
+const RoutesTitle = ref(BarMenuTitle);
+const MenuBarData = ref(useAppState.getMenus)
+const isCollapse = ref(useAppState.getCollapse)
+const userInfo = ref(useAppState.getUserInfo);
+
+//项目合同段
+const projectInfo = ref({});
+const contractInfo = ref({});
+const projectContract = ref([])
+const projectValue = ref(null);
+const projectProps = ref({
+    value: 'id',
+    label: 'projectAlias',
+    children: 'contractInfoList',
+})
+
+//渲染完成
+onMounted(() => {
+    initButtons()
+    initProjectContract()
+    const info = useAppState.getProjectContract || []
+    projectContractData(info);
+    useAppState.barMenuName = BarMenuTitle
+    setLogoImageColor()
+})
+
+//监听
+watch(() => [
+    useAppState.getProjectContract,
+    useAppState.getMenus,
+    useRoutes?.name,
+    useRoutes?.meta?.title,
+    useAppState.getCollapse,
+], ([projectContractArr, userMenus, RouteName, RouteTitle, collapse]) => {
+    MenuBarData.value = userMenus
+    MenuBarKey.value = RouteName ?? 'home-index'
+    RoutesTitle.value = RouteTitle ?? ''
+    isCollapse.value = collapse
+    projectContractData(projectContractArr || []);
+    useAppState.barMenuName = RouteTitle ?? ''
+    setAppName(appTitle.value)
+})
+
+//监听
+watch(() => [
+    useAppState.getTitle,
+    useAppState.getLogoIcon,
+    useAppState.getLogoName,
+    useAppState.getColor,
+], ([Title, LogoIcon, LogoName, ColorVal]) => {
+    appTitle.value = Title
+    appLogoIcon.value = LogoIcon
+    appLogoName.value = LogoName
+    AppColor.value = ColorVal
+    setLogoImageColor()
+})
+
+//设置Logo图片颜色
+const setLogoImageColor = () => {
+    setImageColorStyle('logo-icon', AppColor.value?.color)
+}
+
+//是否折叠
+const collapseChange = (bool) => {
+    isCollapse.value = bool
+    useAppState.setCollapse(bool)
+}
+
+//处理项目合同段数据
+const projectContractData = (projectContractData) => {
+    if (projectContractData.length > 0) {
+        //处理别名
+        projectContractData.forEach(item => {
+            let contractArr = item['contractInfoList'] || []
+            contractArr.forEach(items => {
+                items['projectAlias'] = items['name']
+            })
+        })
+        //处理其他数据
+        projectContract.value = projectContractData
+        const projectId = useAppState.getProjectId     //项目ID
+        const contractId = useAppState.getContractId   //合同段ID
+        const UserProjectInfo = useAppState.getProjectInfo
+        const UserContractInfo = useAppState.getContractInfo
+        //查询缓存的选中ID是否存在
+        const pid = projectContractData.findIndex(item => Number(item.id) === Number(projectId))
+        const contractList = projectContractData[pid]?.contractInfoList || []
+        const cid = contractList.findIndex(item => Number(item.id) === Number(contractId))
+        //如果缓存的选中ID不存在
+        if (cid === -1) {
+            //取项目数组中的第一个数据
+            let letProjectInfo = projectContractData[0];
+            let contractInfoList = letProjectInfo?.contractInfoList || []
+            let letContractInfo = contractInfoList[0] || {};
+            projectValue.value = letContractInfo?.id
+            projectInfo.value = letProjectInfo
+            contractInfo.value = letContractInfo
+            //设置缓存
+            useAppState.setProjectInfo(letProjectInfo)
+            useAppState.setContractInfo(letContractInfo)
+            useAppState.setProjectId(letProjectInfo?.id)
+            useAppState.setContractId(letContractInfo?.id)
+        } else {
+            projectValue.value = String(contractId)
+            projectInfo.value = UserProjectInfo
+            contractInfo.value = UserContractInfo
+        }
+    } else {
+        projectContract.value = []
+        projectValue.value = null
+        projectInfo.value = {}
+        contractInfo.value = {}
+    }
+}
+
+//项目被选择
+const ElCascaderRef = ref(null)
+const projectContractChange = (val) => {
+    if (val) {
+        const Nodes = ElCascaderRef.value.getCheckedNodes();
+        const UserProjectInfo = Nodes[0].parent.data;
+        const UserContractInfo = Nodes[0].data;
+        //缓存项目数据
+        useAppState.setProjectId(val[0])
+        useAppState.setContractId(val[1])
+        useAppState.setProjectInfo(UserProjectInfo)
+        useAppState.setContractInfo(UserContractInfo)
+        //更改界面更新
+        projectInfo.value = UserProjectInfo
+        contractInfo.value = UserContractInfo
+        window.$message?.info('切换了项目,数据更新中');
+        //刷新路由
+        reloadRouter.value = false
+        nextTick(() => {
+            reloadRouter.value = true
+        })
+    }
+}
+
+//菜单被点击
+const MenuBarChange = (item) => {
+    MenuBarKey.value = item?.code;
+    router.push({name: item?.code});
+}
+
+//首页
+const logoClick = () => {
+    router.push({
+        name: useAppState.homeUrl
+    });
+}
+</script>
+
+<style lang="scss" scoped>
+@import "./layout.scss";
+</style>
+
+<style lang="scss">
+.hc-layout-box .hc-container-view {
+    .hc-header-view .hc-header-content .hc-header-cascader-box {
+        .el-cascader {
+            width: 100%;
+            top: -10px;
+        }
+        .el-cascader .el-input .el-input__wrapper {
+            padding: 4px 15px;
+            border: 1px solid #00000000;
+            border-radius: 100px;
+            background: #f1f5f8;
+            color: #202532;
+            box-shadow: var(--hc-shadow);
+            .el-input__inner, .el-input__suffix {
+                color: #202532;
+            }
+        }
+        .el-cascader .el-input.is-focus .el-input__wrapper {
+            box-shadow: 4px 4px 8px 0 rgba(54, 92, 167, 0.15), -4px -4px 8px 0px #ffffff;
+        }
+        .el-cascader .el-input .icon-arrow-down {
+            font-size: 18px;
+            font-weight: bold;
+        }
+    }
+}
+
+</style>

+ 156 - 0
src/layout/modules/Cascader.vue

@@ -0,0 +1,156 @@
+<template>
+    <div class="hc-header-cascader-box">
+        <div class="project-name-box">{{ projectInfo.projectAlias }} / {{ contractInfo.name }}</div>
+        <el-cascader
+            ref="ElCascaderRef"
+            v-model="projectValue" class="hc-header-cascader"
+            :clearable="userInfo?.role_id === '1123598816738675201'"
+            :filterable="userInfo?.role_id === '1123598816738675201'"
+            :options="projectContract"
+            :props="projectProps" placeholder="请选择项目"
+            @change="projectContractChange"
+        />
+    </div>
+</template>
+
+<script setup>
+import { onMounted, ref, watch } from 'vue'
+import { useAppStore } from '~src/store'
+import { getArrValue } from 'js-fast-way'
+import { initProjectContract } from '~sto/app'
+
+//事件
+const emit = defineEmits(['change', 'send'])
+
+//状态
+const store = useAppStore()
+const userInfo = ref(store.getUserInfo)
+
+//项目合同段
+const projectInfo = ref({})
+const contractInfo = ref({})
+const projectContract = ref([])
+const projectValue = ref(null)
+const projectProps = ref({
+    value: 'id',
+    label: 'projectAlias',
+    children: 'contractInfoList',
+})
+
+//监听
+watch(() => store.getProjectContract, (val) => {
+    projectContractData(getArrValue(val))
+})
+
+//渲染完成
+onMounted(() => {
+    initProjectContract()
+    const info = store.getProjectContract || []
+    projectContractData(info)
+})
+
+//处理项目合同段数据
+const projectContractData = (projectContractData) => {
+    if (projectContractData.length > 0) {
+        //处理别名
+        projectContractData.forEach(item => {
+            let contractArr = item['contractInfoList'] || []
+            contractArr.forEach(items => {
+                items['projectAlias'] = items['name']
+            })
+        })
+        //处理其他数据
+        projectContract.value = projectContractData
+        const projectId = store.getProjectId //项目ID
+        const contractId = store.getContractId //合同段ID
+        const UserProjectInfo = store.getProjectInfo
+        const UserContractInfo = store.getContractInfo
+        //查询缓存的选中ID是否存在
+        const pid = projectContractData.findIndex(item => Number(item.id) === Number(projectId))
+        const contractList = projectContractData[pid]?.contractInfoList || []
+        const cid = contractList.findIndex(item => Number(item.id) === Number(contractId))
+        //如果缓存的选中ID不存在
+        if (cid === -1) {
+            //取项目数组中的第一个数据
+            let letProjectInfo = projectContractData[0]
+            let contractInfoList = letProjectInfo?.contractInfoList || []
+            let letContractInfo = contractInfoList[0] || {}
+            projectValue.value = letContractInfo?.id
+            projectInfo.value = letProjectInfo
+            contractInfo.value = letContractInfo
+            //设置缓存
+            store.setProjectInfo(letProjectInfo)
+            store.setContractInfo(letContractInfo)
+            store.setProjectId(letProjectInfo?.id)
+            store.setContractId(letContractInfo?.id)
+            emit('send', {
+                projectId: letProjectInfo?.id,
+                contractId: letContractInfo?.id,
+            })
+        } else {
+            projectValue.value = String(contractId)
+            projectInfo.value = UserProjectInfo
+            contractInfo.value = UserContractInfo
+            emit('send', {
+                projectId: projectId,
+                contractId: contractId,
+            })
+        }
+    } else {
+        projectContract.value = []
+        projectValue.value = null
+        projectInfo.value = {}
+        contractInfo.value = {}
+        emit('send', {
+            projectId: '',
+            contractId: '',
+        })
+    }
+}
+
+//项目被选择
+const ElCascaderRef = ref(null)
+const projectContractChange = (val) => {
+    if (val) {
+        const Nodes = ElCascaderRef.value.getCheckedNodes()
+        const UserProjectInfo = Nodes[0].parent.data
+        const UserContractInfo = Nodes[0].data
+        //缓存项目数据
+        store.setProjectId(val[0])
+        store.setContractId(val[1])
+        store.setProjectInfo(UserProjectInfo)
+        store.setContractInfo(UserContractInfo)
+        //更改界面更新
+        projectInfo.value = UserProjectInfo
+        contractInfo.value = UserContractInfo
+        window.$message?.info('切换了项目,数据更新中')
+        emit('send', {
+            projectId: val[0],
+            contractId: val[1],
+        })
+        emit('change')
+    }
+}
+</script>
+
+<style lang="scss">
+.hc-header-cascader-box {
+    position: relative;
+    margin-right: 20px;
+    .project-name-box {
+        position: relative;
+        max-width: 340px;
+        padding-right: 20px;
+        overflow: hidden;
+        z-index: -1;
+        height: 1px;
+    }
+    .el-cascader.hc-header-cascader {
+        width: 100%;
+        .el-input .el-input__wrapper {
+            border-radius: 104px;
+            height: 28px;
+        }
+    }
+}
+</style>

+ 3 - 25
src/layout/modules/ConfigBar.vue

@@ -1,6 +1,6 @@
 <template>
     <div class="header-icon-bar" @click="toConfigClick">
-        <HcIcon name="settings" class="header-icon"/>
+        <HcIcon name="settings" class="header-icon" />
     </div>
 </template>
 
@@ -12,32 +12,10 @@ const router = useRouter()
 //跳转到系统设置页面
 const toConfigClick = () => {
     router.push({
-        path: '/home/config'
-    });
+        path: '/home/config',
+    })
 }
 </script>
 
 <style lang="scss" scoped>
-.header-icon-bar {
-    position: relative;
-    height: 40px;
-    width: 40px;
-    border-radius: 100px;
-    display: flex;
-    justify-content: center;
-    align-items: center;
-    cursor: pointer;
-    margin-right: 30px;
-    font-size: 26px;
-    border: 1px solid #00000000;
-    background: #f1f5f8;
-    color: #202532;
-    box-shadow: var(--hc-shadow);
-}
-.hc-layout-box .hc-container-view.home .hc-header-view .hc-header-content .header-icon-bar {
-    border: 1px solid white;
-    color: inherit;
-    box-shadow: initial;
-    background: initial;
-}
 </style>

+ 87 - 0
src/layout/modules/HcTopMenu.vue

@@ -0,0 +1,87 @@
+<template>
+    <el-scrollbar>
+        <div class="hc-header-top-menu-bar">
+            <template v-for="(item, index) in topMenuData" :key="index">
+                <div class="item" :class="curKey === item?.code ? 'cur' : '' " @click="topMenuClick(item)">
+                    {{ item?.name }}
+                </div>
+            </template>
+        </div>
+    </el-scrollbar>
+</template>
+
+<script setup>
+import { ref, watch } from 'vue'
+import { useRoute } from 'vue-router'
+import { useAppStore } from '~src/store'
+import HcTopMenu from '~src/plugins/HcTopMenu'
+import { getArrValue } from 'js-fast-way'
+
+const emit = defineEmits(['change', 'load'])
+
+//初始组合式
+const useRoutes = useRoute()
+const store = useAppStore()
+
+//处理菜单数据
+const setMenuItem = async (item) => {
+    emit('change', await HcTopMenu.setMenuItem(item))
+}
+
+//监听菜单数据
+const topMenuData = ref([])
+watch(() => store.getMenus, (val) => {
+    topMenuData.value = getArrValue(val)
+}, { immediate: true, deep: true })
+
+//监听路由数据
+const curKey = ref('')
+watch(() => useRoutes, (val) => {
+    HcTopMenu.initMenu({
+        routes: val,
+        menu: topMenuData.value,
+        load: (key) => {
+            curKey.value = key
+            emit('load', key)
+        },
+        change: (key, item) => {
+            curKey.value = key
+            setMenuItem(item)
+        },
+    })
+}, { immediate: true, deep: true })
+
+//菜单被点击
+const topMenuClick = (item) => {
+    setMenuItem(item)
+}
+</script>
+
+<style lang="scss">
+.hc-header-top-menu-bar {
+    position: relative;
+    height: 100%;
+    display: flex;
+    align-items: center;
+    font-size: 14px;
+    .item {
+        position: relative;
+        cursor: pointer;
+        padding: 6px 8px;
+        border-radius: 3px;
+        color: #efefef;
+        transition: background .2s, color .2s;
+        &:hover {
+            color: white;
+            background: var(--el-color-primary-dark-2);
+        }
+        &.cur {
+            color: white;
+            background: var(--el-color-primary-dark-2);
+        }
+    }
+    .item + .item {
+        margin-left: 2px;
+    }
+}
+</style>

+ 19 - 42
src/layout/modules/HelpInfoBar.vue

@@ -2,27 +2,27 @@
     <el-popover :width="220" placement="bottom" trigger="hover">
         <template #reference>
             <div class="header-icon-bar">
-                <HcIcon class="header-icon" name="question"/>
+                <HcIcon class="header-icon" name="question" />
             </div>
         </template>
         <div class="header-pover-menu-list">
             <div class="list-item">
                 <span class="text">开启功能气泡提示</span>
-                <el-switch v-model="bubbleVal" @change="bubbleUpdate"/>
+                <el-switch v-model="bubbleVal" @change="bubbleUpdate" />
             </div>
             <div v-if="excelUrl" class="list-item" @click="excelPreviewClick">
                 <span class="text">查看系统操作文档</span>
-                <img :src="getAssetsHomeFile('word.png')" alt="" class="icon"/>
-                <img :src="getAssetsHomeFile('word1.png')" alt="" class="icon1"/>
+                <img :src="getAssetsHomeFile('word.png')" alt="" class="icon">
+                <img :src="getAssetsHomeFile('word1.png')" alt="" class="icon1">
             </div>
             <div v-if="videoUrl" class="list-item" @click="videoPreviewModal = true">
                 <span class="text">当前页面功能讲解</span>
-                <img :src="getAssetsHomeFile('video.png')" alt="" class="icon"/>
-                <img :src="getAssetsHomeFile('video1.png')" alt="" class="icon1"/>
+                <img :src="getAssetsHomeFile('video.png')" alt="" class="icon">
+                <img :src="getAssetsHomeFile('video1.png')" alt="" class="icon1">
             </div>
         </div>
     </el-popover>
-    <!--当前页面功能讲解-->
+    <!-- 当前页面功能讲解 -->
     <el-dialog v-model="videoPreviewModal" :before-close="videoPreviewModalClose" destroy-on-close width="62rem">
         <video :src="videoUrl" autoplay="autoplay" class="preview-video" controls="controls">
             您的浏览器不支持 video
@@ -31,11 +31,11 @@
 </template>
 
 <script setup>
-import {ref, watch, nextTick} from "vue";
-import {useRouter, useRoute} from 'vue-router'
-import {useAppStore} from "~src/store";
-import {getStoreValue} from '~src/utils/storage'
-import {getObjValue, getToObjVal} from "js-fast-way"
+import { nextTick, ref, watch } from 'vue'
+import { useRoute, useRouter } from 'vue-router'
+import { useAppStore } from '~src/store'
+import { getStoreValue } from '~src/utils/storage'
+import { getObjValue, getToObjVal } from 'js-fast-way'
 
 //初始变量
 const router = useRouter()
@@ -44,7 +44,7 @@ const useAppState = useAppStore()
 
 //相关变量
 const route = getObjValue(getStoreValue('route'))
-const bubbleVal = ref(useAppState.getBubble);
+const bubbleVal = ref(useAppState.getBubble)
 const videoUrl = ref('')
 const excelUrl = ref('')
 const videoPreviewModal = ref(false)
@@ -79,15 +79,15 @@ const getVideoUrl = (name) => {
 
 //开关值改变
 const bubbleUpdate = (val) => {
-    bubbleVal.value = val;
-    useAppState.setBubble(val);
+    bubbleVal.value = val
+    useAppState.setBubble(val)
 }
 
 // 获取assets静态资源
 const getAssetsHomeFile = (url) => {
-    const path = `../../assets/images/${url}`;
-    const modules = import.meta.globEager("../../assets/images/*");
-    return modules[path].default;
+    const path = `../../assets/images/${url}`
+    const modules = import.meta.globEager('../../assets/images/*')
+    return modules[path].default
 }
 
 //关闭视频弹窗
@@ -106,29 +106,6 @@ const excelPreviewClick = () => {
 </script>
 
 <style lang="scss" scoped>
-.header-icon-bar {
-    position: relative;
-    height: 40px;
-    width: 40px;
-    border-radius: 100px;
-    display: flex;
-    justify-content: center;
-    align-items: center;
-    font-size: 26px;
-    cursor: pointer;
-    margin-right: 30px;
-    border: 1px solid #00000000;
-    background: #f1f5f8;
-    color: #202532;
-    box-shadow: var(--hc-shadow);
-}
-.hc-layout-box .hc-container-view.home .hc-header-view .hc-header-content .header-icon-bar {
-    border: 1px solid white;
-    color: inherit;
-    box-shadow: initial;
-    background: initial;
-}
-
 .header-pover-menu-list {
     position: relative;
     margin: -5px -12px;
@@ -164,4 +141,4 @@ const excelPreviewClick = () => {
 .preview-video {
     width: 100%;
 }
-</style>
+</style>

+ 205 - 0
src/layout/modules/TopMenuBar copy.vue

@@ -0,0 +1,205 @@
+<template>
+    <div class="hc-top-menu-bar">
+        <el-scrollbar always>
+            <div class="bar-menu-content">
+                <div v-for="(item, index) in barMenuData" :class="item.key === barRoutes.key?'cur':''"
+                     class="bar-menu-btn"
+                     @click="barMenuClick(item)" @contextmenu.prevent="barMenuContextMenu($event, item, index)">
+                    <span>{{ item.title }}</span>
+                    <div class="bar-close-icon" @click.stop="barMenuCloseClick(item, index)">
+                        <HcIcon name="close"/>
+                    </div>
+                </div>
+            </div>
+        </el-scrollbar>
+        <!--右键菜单-->
+        <HcContextMenu ref="contextMenuRef" :datas="menusData" @item-click="handleMenuSelect"/>
+    </div>
+</template>
+
+<script setup>
+import {onMounted, ref, watch} from "vue";
+import {useAppStore} from "~src/store";
+import {useRouter, useRoute} from 'vue-router'
+import {getStoreValue, setStoreValue} from '~src/utils/storage'
+
+//初始组合式
+const router = useRouter()
+const useRoutes = useRoute()
+const useAppState = useAppStore()
+
+//初始变量
+const barMenuData = ref(getStoreValue('bar-menu-datas') || []);
+const barRoutes = ref({key: '', path: '', title: '', query: null});
+
+//渲染完成
+onMounted(() => {
+    const {name, path, meta, query} = useRoutes
+    barRoutes.value = {path, key: name, title: meta?.title, query}
+    setBarMenuData()
+})
+
+//监听
+watch(() => [
+    useRoutes?.name,
+    useRoutes?.path,
+    useRoutes?.query,
+    useRoutes?.meta?.title,
+], ([key, path, query, title]) => {
+    barRoutes.value = {path, key, title, query}
+    setBarMenuData()
+})
+
+//设置菜单数据
+const setBarMenuData = () => {
+    const {key, path, title, query} = barRoutes.value
+    if (['home', 'home-index'].indexOf(key) === -1) {
+        const index = barMenuData.value.findIndex(item => item.key === key)
+        if (index === -1) {
+            barMenuData.value.push({path, key: key, title, query})
+        }
+        setStoreValue('bar-menu-datas', barMenuData.value)
+    }
+}
+
+//菜单被点击
+const barMenuClick = (item) => {
+    const {key} = barRoutes.value
+    if (key !== item.key) {
+        router.push({name: item.key, query: item.query});
+    }
+}
+
+//鼠标右键菜单
+const contextMenuRef = ref(null);
+const barItem = ref({});
+const barItemIndex = ref(0);
+const menusData = ref([
+    {label: '关闭当前', key: "close"},
+    {label: '关闭所有', key: "all"},
+    {label: '关闭其它', key: "other"},
+]);
+const barMenuContextMenu = (event, item, index) => {
+    event.preventDefault();
+    barItem.value = item;
+    barItemIndex.value = index;
+    contextMenuRef.value?.showMenu(event);
+}
+
+//鼠标右键菜单被点击
+const handleMenuSelect = ({key}) => {
+    if (key === 'close') {
+        barMenuCloseClick(barItem.value, barItemIndex.value)
+    } else if (key === 'all') {
+        barMenuData.value = []
+        setStoreValue('bar-menu-datas', [])
+        router.push({
+            name: useAppState.homeUrl
+        });
+    } else if (key === 'other') {
+        const {key} = barRoutes.value
+        barMenuData.value = barMenuData.value.filter(item => item.key === key)
+        setStoreValue('bar-menu-datas', barMenuData.value)
+    }
+}
+
+//菜单关闭被点击
+const barMenuCloseClick = (item, index) => {
+    const total = barMenuData.value.length - 1;
+    const {key} = barRoutes.value
+    barMenuData.value.splice(index, 1)
+    if (key === item.key) {
+        let items = {};
+        const indexs = barMenuData.value.length - 1;
+        if (total > index) {
+            items = barMenuData.value[index]
+        } else if (indexs >= 0) {
+            items = barMenuData.value[indexs]
+        }
+        if (indexs < 0) {
+            setStoreValue('bar-menu-datas', barMenuData.value)
+            router.push({
+                name: useAppState.homeUrl
+            });
+        } else {
+            barRoutes.value = items
+            setStoreValue('bar-menu-datas', barMenuData.value)
+            router.push({name: items.key, query: items.query});
+        }
+    } else {
+        setStoreValue('bar-menu-datas', barMenuData.value)
+    }
+}
+</script>
+
+<style lang="scss">
+.hc-top-menu-bar {
+    position: relative;
+    width: 100%;
+    padding-bottom: 10px;
+    margin-top: 10px;
+    .bar-menu-content {
+        display: flex;
+        position: relative;
+        .bar-menu-btn {
+            position: relative;
+            color: #b3b3b3;
+            padding-left: 10px;
+            padding-right: 6px;
+            height: 32px;
+            font-size: 14px;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            background: #ffffff;
+            border: 1px solid #ffffff;
+            border-radius: 4px;
+            user-select: none;
+            cursor: pointer;
+            white-space: nowrap;
+            transition: background 0.3s, color 0.3s;
+            &:hover:not([class*='cur']) {
+                background: var(--el-color-primary-light-9);
+                color: #838791;
+            }
+            &:active:not([class*='cur']) {
+                background: var(--el-color-primary-light-8);
+                color: #838791;
+            }
+            &.cur {
+                color: #ffffff;
+                cursor: default;
+                background: linear-gradient(to right, var(--el-color-primary-light-5), var(--el-color-primary), var(--el-color-primary-dark-2));
+                background-size: 200%;
+                transition: background-position 0.5s;
+            }
+            .bar-close-icon {
+                height: 30px;
+                width: 18px;
+                display: flex;
+                align-items: center;
+                justify-content: center;
+                margin-left: 6px;
+                font-size: 16px;
+                cursor: pointer;
+                transition: color 0.3s;
+                &:hover {
+                    color: var(--el-color-primary);
+                }
+            }
+        }
+        .bar-menu-btn.cur .bar-close-icon:hover {
+            color: #000000;
+        }
+        .bar-menu-btn + .bar-menu-btn {
+            margin-left: 10px;
+        }
+    }
+    .el-scrollbar__bar.is-horizontal {
+        bottom: -10px;
+    }
+    .el-scrollbar__bar.is-vertical {
+        display: none;
+    }
+}
+</style>

+ 53 - 117
src/layout/modules/TopMenuBar.vue

@@ -1,27 +1,31 @@
 <template>
-    <div class="hc-top-menu-bar">
-        <el-scrollbar always>
-            <div class="bar-menu-content">
-                <div v-for="(item, index) in barMenuData" :class="item.key === barRoutes.key?'cur':''"
-                     class="bar-menu-btn"
-                     @click="barMenuClick(item)" @contextmenu.prevent="barMenuContextMenu($event, item, index)">
+    <el-scrollbar>
+        <div class="hc-router-tab-box">
+            <div class="hc-router-tab-item" :class="(barRoutes.key === 'home' || barRoutes.key === 'home-index') ? 'cur' : ''" @click="toHomeClick">
+                首页
+            </div>
+            <template v-for="(item, index) in barMenuData" :key="item.key">
+                <div
+                    :class="item.key === barRoutes.key ? 'cur' : ''" class="hc-router-tab-item"
+                    @click="barMenuClick(item)" @contextmenu.prevent="barMenuContextMenu($event, item, index)"
+                >
                     <span>{{ item.title }}</span>
-                    <div class="bar-close-icon" @click.stop="barMenuCloseClick(item, index)">
-                        <HcIcon name="close"/>
+                    <div class="close-icon" @click.stop="barMenuCloseClick(item, index)">
+                        <HcIcon name="close" />
                     </div>
                 </div>
-            </div>
-        </el-scrollbar>
-        <!--右键菜单-->
-        <HcContextMenu ref="contextMenuRef" :datas="menusData" @item-click="handleMenuSelect"/>
-    </div>
+            </template>
+        </div>
+    </el-scrollbar>
+    <!-- 右键菜单 -->
+    <HcContextMenu ref="contextMenuRef" :datas="menusData" @item-click="handleMenuSelect" />
 </template>
 
 <script setup>
-import {onMounted, ref, watch} from "vue";
-import {useAppStore} from "~src/store";
-import {useRouter, useRoute} from 'vue-router'
-import {getStoreValue, setStoreValue} from '~src/utils/storage'
+import { onMounted, ref, watch } from 'vue'
+import { useAppStore } from '~src/store'
+import { useRoute, useRouter } from 'vue-router'
+import { getStoreValue, setStoreValue } from '~src/utils/storage'
 
 //初始组合式
 const router = useRouter()
@@ -29,13 +33,13 @@ const useRoutes = useRoute()
 const useAppState = useAppStore()
 
 //初始变量
-const barMenuData = ref(getStoreValue('bar-menu-datas') || []);
-const barRoutes = ref({key: '', path: '', title: '', query: null});
+const barMenuData = ref(getStoreValue('bar-menu-datas') || [])
+const barRoutes = ref({ key: '', path: '', title: '', query: null })
 
 //渲染完成
 onMounted(() => {
-    const {name, path, meta, query} = useRoutes
-    barRoutes.value = {path, key: name, title: meta?.title, query}
+    const { name, path, meta, query } = useRoutes
+    barRoutes.value = { path, key: name, title: meta?.title, query }
     setBarMenuData()
 })
 
@@ -46,17 +50,17 @@ watch(() => [
     useRoutes?.query,
     useRoutes?.meta?.title,
 ], ([key, path, query, title]) => {
-    barRoutes.value = {path, key, title, query}
+    barRoutes.value = { path, key, title, query }
     setBarMenuData()
 })
 
 //设置菜单数据
 const setBarMenuData = () => {
-    const {key, path, title, query} = barRoutes.value
+    const { key, path, title, query } = barRoutes.value
     if (['home', 'home-index'].indexOf(key) === -1) {
         const index = barMenuData.value.findIndex(item => item.key === key)
         if (index === -1) {
-            barMenuData.value.push({path, key: key, title, query})
+            barMenuData.value.push({ path, key: key, title, query })
         }
         setStoreValue('bar-menu-datas', barMenuData.value)
     }
@@ -64,40 +68,40 @@ const setBarMenuData = () => {
 
 //菜单被点击
 const barMenuClick = (item) => {
-    const {key} = barRoutes.value
+    const { key } = barRoutes.value
     if (key !== item.key) {
-        router.push({name: item.key, query: item.query});
+        router.push({ name: item.key, query: item.query })
     }
 }
 
 //鼠标右键菜单
-const contextMenuRef = ref(null);
-const barItem = ref({});
-const barItemIndex = ref(0);
+const contextMenuRef = ref(null)
+const barItem = ref({})
+const barItemIndex = ref(0)
 const menusData = ref([
-    {label: '关闭当前', key: "close"},
-    {label: '关闭所有', key: "all"},
-    {label: '关闭其它', key: "other"},
-]);
+    { label: '关闭当前', key: 'close' },
+    { label: '关闭所有', key: 'all' },
+    { label: '关闭其它', key: 'other' },
+])
 const barMenuContextMenu = (event, item, index) => {
-    event.preventDefault();
-    barItem.value = item;
-    barItemIndex.value = index;
-    contextMenuRef.value?.showMenu(event);
+    event.preventDefault()
+    barItem.value = item
+    barItemIndex.value = index
+    contextMenuRef.value?.showMenu(event)
 }
 
 //鼠标右键菜单被点击
-const handleMenuSelect = ({key}) => {
+const handleMenuSelect = ({ key }) => {
     if (key === 'close') {
         barMenuCloseClick(barItem.value, barItemIndex.value)
     } else if (key === 'all') {
         barMenuData.value = []
         setStoreValue('bar-menu-datas', [])
         router.push({
-            name: useAppState.homeUrl
-        });
+            name: useAppState.homeUrl,
+        })
     } else if (key === 'other') {
-        const {key} = barRoutes.value
+        const { key } = barRoutes.value
         barMenuData.value = barMenuData.value.filter(item => item.key === key)
         setStoreValue('bar-menu-datas', barMenuData.value)
     }
@@ -105,12 +109,12 @@ const handleMenuSelect = ({key}) => {
 
 //菜单关闭被点击
 const barMenuCloseClick = (item, index) => {
-    const total = barMenuData.value.length - 1;
-    const {key} = barRoutes.value
+    const total = barMenuData.value.length - 1
+    const { key } = barRoutes.value
     barMenuData.value.splice(index, 1)
     if (key === item.key) {
-        let items = {};
-        const indexs = barMenuData.value.length - 1;
+        let items = {}
+        const indexs = barMenuData.value.length - 1
         if (total > index) {
             items = barMenuData.value[index]
         } else if (indexs >= 0) {
@@ -119,12 +123,12 @@ const barMenuCloseClick = (item, index) => {
         if (indexs < 0) {
             setStoreValue('bar-menu-datas', barMenuData.value)
             router.push({
-                name: useAppState.homeUrl
-            });
+                name: useAppState.homeUrl,
+            })
         } else {
             barRoutes.value = items
             setStoreValue('bar-menu-datas', barMenuData.value)
-            router.push({name: items.key, query: items.query});
+            router.push({ name: items.key, query: items.query })
         }
     } else {
         setStoreValue('bar-menu-datas', barMenuData.value)
@@ -133,73 +137,5 @@ const barMenuCloseClick = (item, index) => {
 </script>
 
 <style lang="scss">
-.hc-top-menu-bar {
-    position: relative;
-    width: 100%;
-    padding-bottom: 10px;
-    margin-top: 10px;
-    .bar-menu-content {
-        display: flex;
-        position: relative;
-        .bar-menu-btn {
-            position: relative;
-            color: #b3b3b3;
-            padding-left: 10px;
-            padding-right: 6px;
-            height: 32px;
-            font-size: 14px;
-            display: flex;
-            align-items: center;
-            justify-content: center;
-            background: #ffffff;
-            border: 1px solid #ffffff;
-            border-radius: 4px;
-            user-select: none;
-            cursor: pointer;
-            white-space: nowrap;
-            transition: background 0.3s, color 0.3s;
-            &:hover:not([class*='cur']) {
-                background: var(--el-color-primary-light-9);
-                color: #838791;
-            }
-            &:active:not([class*='cur']) {
-                background: var(--el-color-primary-light-8);
-                color: #838791;
-            }
-            &.cur {
-                color: #ffffff;
-                cursor: default;
-                background: linear-gradient(to right, var(--el-color-primary-light-5), var(--el-color-primary), var(--el-color-primary-dark-2));
-                background-size: 200%;
-                transition: background-position 0.5s;
-            }
-            .bar-close-icon {
-                height: 30px;
-                width: 18px;
-                display: flex;
-                align-items: center;
-                justify-content: center;
-                margin-left: 6px;
-                font-size: 16px;
-                cursor: pointer;
-                transition: color 0.3s;
-                &:hover {
-                    color: var(--el-color-primary);
-                }
-            }
-        }
-        .bar-menu-btn.cur .bar-close-icon:hover {
-            color: #000000;
-        }
-        .bar-menu-btn + .bar-menu-btn {
-            margin-left: 10px;
-        }
-    }
-    .el-scrollbar__bar.is-horizontal {
-        bottom: -10px;
-    }
-    .el-scrollbar__bar.is-vertical {
-        display: none;
-    }
-}
+
 </style>

+ 45 - 43
src/layout/modules/UserInfoBar.vue

@@ -1,15 +1,15 @@
 <template>
     <el-dropdown size="large">
         <div class="header-bar user-info-bar">
-            <img :alt="userInfo['account']" :src="userInfo['avatar'] || avatarPng" class="user-avatar">
-            <span class="user-name">{{ userInfo['real_name'] }}</span>
-            <HcIcon name="arrow-down-s" ui="arrow-icon"/>
+            <img :alt="userInfo.account" :src="userInfo.avatar || avatarPng" class="user-avatar">
+            <span class="user-name">{{ userInfo.real_name }}</span>
+            <HcIcon name="arrow-down-s" ui="arrow-icon" />
         </div>
         <template #dropdown>
             <el-dropdown-menu>
                 <el-dropdown-item v-for="item in options">
                     <div class="hc-dropdown-item" @click="handleSelect(item.key)">
-                        <HcIcon :name="item.icon" class="icon"/>
+                        <HcIcon :name="item.icon" class="icon" />
                         <span class="label">{{ item.label }}</span>
                     </div>
                 </el-dropdown-item>
@@ -19,24 +19,26 @@
 </template>
 
 <script setup>
-import {onMounted, ref, watch} from "vue";
-import {useRouter} from 'vue-router'
-import {useAppStore} from "~src/store";
-import website from "~src/config/index";
-import avatarPng from '~src/assets/images/avatar.png';
-import {RefreshToken, LogOut} from "~sto/user";
-import {getStoreValue} from '~src/utils/storage'
-import {calcDate, isNullES} from "js-fast-way"
+import { onMounted, ref, watch } from 'vue'
+import { useRouter } from 'vue-router'
+import { useAppStore } from '~src/store'
+import website from '~src/config/index'
+import avatarPng from '~src/assets/images/avatar.png'
+import { LogOut, RefreshToken } from '~sto/user'
+import { getStoreValue } from '~src/utils/storage'
+import { calcDate, isNullES } from 'js-fast-way'
 
+//事件
+const emit = defineEmits(['change'])
 //变量
 const router = useRouter()
 const userStore = useAppStore()
-const userInfo = ref(userStore.getUserInfo);
-const refreshLock = ref(false);
+const userInfo = ref(userStore.getUserInfo)
+const refreshLock = ref(false)
 
 //监听
 watch(() => [
-    userStore.getUserInfo
+    userStore.getUserInfo,
 ], ([info]) => {
     userInfo.value = info
 })
@@ -48,48 +50,47 @@ onMounted(() => {
 //刷新token
 const getRefreshToken = () => {
     setInterval(() => {
-        const token = getStoreValue("token", true) || {};
-        const date = calcDate(token.datetime, new Date().getTime());
-        if (isNullES(date)) return;
+        const token = getStoreValue('token', true) || {}
+        const date = calcDate(token.datetime, new Date().getTime())
+        if (isNullES(date)) return
         if (date.seconds >= website.tokenTime && !refreshLock.value) {
-            refreshLock.value = true;
+            refreshLock.value = true
             console.log('刷新token')
             RefreshToken().then(() => {
-                refreshLock.value = false;
+                refreshLock.value = false
             }).catch(() => {
-                refreshLock.value = false;
-                router.push({name: 'login'});
-            });
+                refreshLock.value = false
+                router.push({ name: 'login' })
+            })
         }
     }, 10000)
 }
 
 const options = [
     {
-        key: "my",
-        label: "个人中心",
-        icon: 'user-3'
+        key: 'my',
+        label: '个人中心',
+        icon: 'user-3',
     },
     {
-        key: "logout",
-        label: "退出登录",
-        icon: 'login-box'
-    }
-];
+        key: 'logout',
+        label: '退出登录',
+        icon: 'login-box',
+    },
+]
 
-//事件
-const emit = defineEmits(['change'])
 const handleSelect = (key) => {
     if (key === 'my') {
         //router.push({name: 'user-index'});
     } else if (key === 'logout') {
-        LogOut().then();
-        window.$message?.info('退出成功');
-        router.push({name: 'login'});
+        LogOut().then()
+        window.$message?.info('退出成功')
+        router.push({ name: 'login' })
     }
 }
 </script>
 
+
 <style lang="scss" scoped>
 .user-info-bar {
     position: relative;
@@ -97,11 +98,12 @@ const handleSelect = (key) => {
     align-items: center;
     height: 100%;
     cursor: pointer;
-    padding-left: 24px;
+    padding-left: 16px;
+    margin-left: 4px;
     outline: none;
     .user-avatar {
-        width: 40px;
-        height: 40px;
+        width: 26px;
+        height: 26px;
         border-radius: 50%;
         background: white;
         object-fit: cover;
@@ -109,20 +111,20 @@ const handleSelect = (key) => {
     .user-name {
         font-size: 16px;
         margin-left: 10px;
-        color: #202532;
+        color: white;
     }
     .arrow-icon {
         margin-left: 5px;
         font-size: 20px;
-        color: #202532;
+        color: white;
     }
     &::before {
         position: absolute;
         content: '';
         left: 0;
         width: 0;
-        height: 24px;
-        border-left: 1px solid #ccd0de;
+        height: 20px;
+        border-left: 1px solid #7291ff;
     }
 }
 .hc-layout-box .hc-container-view.home .hc-header-view .hc-header-content .user-info-bar {

+ 56 - 0
src/plugins/HcSocket.js

@@ -0,0 +1,56 @@
+import website from '~src/config/index'
+import { isNullES } from 'js-fast-way'
+
+// 长链接推送插件
+export default class HcSocket {
+
+    static socket = null
+
+    static create(data, change) {
+        const socket = new WebSocket(website.socket + data)
+        socket.onopen = function () {
+            console.log('websocket 链接成功')
+        }
+        socket.onclose = function () {
+            console.log('websocket 链接已断开')
+        }
+        socket.onmessage = function ({ data }) {
+            if (typeof change !== 'function') {
+                return false
+            } else {
+                change(JSON.parse(data))
+            }
+        }
+        socket.onerror = function ({ data }) {
+            console.log('websocket 发生错误:', data)
+        }
+        this.socket = socket
+    }
+
+    //发送消息
+    static async send(data) {
+        const is_socket = await this.isSocket()
+        if (!is_socket) return false
+        this.socket.send(data)
+    }
+
+    //链接是否存在
+    static async isSocket(i = 0) {
+        let _this = this
+        return new Promise((resolve) => {
+            if (isNullES(_this.socket)) {
+                if (i <= 30) {
+                    setTimeout(async () => {
+                        i++
+                        resolve(await _this.isSocket(i))
+                    }, 1000)
+                } else {
+                    resolve(false)
+                }
+            } else {
+                resolve(true)
+            }
+        })
+    }
+
+}

+ 47 - 0
src/plugins/HcTopMenu.js

@@ -0,0 +1,47 @@
+import { isPathUrl } from '~uti/tools'
+import { getToken } from '~src/api/util/auth'
+import { getStoreValue } from '~uti/storage'
+import { getTenantDetail } from '~api/other'
+import { getArrValue, getObjValue } from 'js-fast-way'
+
+export default class HcTopMenu {
+
+    // 基础菜单
+    static baseMenu = [
+        'home', 'home-index', 'home-index-static', 'home-config', 'order-service', 'user-index', '403', '404', '500',
+    ]
+
+    static initMenu({ routes, menu, load, change }) {
+        const topName = routes.matched[0]?.name
+        if (this.baseMenu.includes(topName)) {
+            load(topName)
+            return false
+        }
+        for (let i = 0; i < menu.length; i++) {
+            if (menu[i].code === topName) {
+                change(topName, menu[i])
+            }
+        }
+    }
+
+    static async setMenuItem(item) {
+        if (isPathUrl(item?.path)) {
+            let token = getToken(), domain = item?.path
+            if (item?.code === 'to-archives-url') {
+                const tenantId = getStoreValue('tenantId')
+                if (tenantId === '000000' || !tenantId) {
+                    domain = item?.path
+                } else {
+                    const { error, code, data } = await getTenantDetail(tenantId)
+                    if (!error && code === 200) {
+                        const url = getObjValue(data).domainUrl
+                        domain = url ? url : item?.path
+                    }
+                }
+            }
+            window.open(domain + '/#/auth?token=' + token, '_blank')
+        } else {
+            return getArrValue(item?.children)
+        }
+    }
+}

+ 11 - 0
src/styles/app/element.scss

@@ -33,3 +33,14 @@
         text-align: left;
     }
 }
+//新改变版按钮
+.el-button[hc-btn] {
+    border-radius: 0;
+    padding: 0 10px;
+    font-weight: initial;
+    height: 28px;
+    font-size: 14px;
+    border: 0;
+    box-shadow: none;
+    outline: 0;
+}

+ 8 - 4
src/utils/tools.js

@@ -9,17 +9,21 @@ export const delMessage = (cbk) => {
             if (action === 'confirm') {
                 cbk()
             }
-        }
+        },
     })
 }
 
 //获取当前域名
 export const getTopUrl = () => {
-    return window.location.href.split('/#/')[0];
+    return window.location.href.split('/#/')[0]
 }
 
 //设置系统名称
 export const setAppName = (name) => {
-    const title = window.document.title;
-    window.document.title = `${title}${name?' - ' + name:''}`;
+    const title = window.document.title
+    window.document.title = `${title}${name ? ' - ' + name : ''}`
 }
+//判断是否为网址
+export const isPathUrl = (path) => {
+    return /^(https?:|mailto:|tel:)/.test(path)
+}

+ 21 - 20
src/views/base/agree.vue

@@ -1,41 +1,42 @@
 <template>
-    <HcCard>
+    <HcNewCard padding>
+        <template #extra>
+            <el-button type="primary" hc-btn @click="addRowClick">
+                <HcIcon name="add" />
+                <span>新增</span>
+            </el-button>
+            <el-button type="danger" hc-btn :disabled="tableCheckedKeys.length < 1" @click="batchClick">
+                <HcIcon name="delete-bin" />
+                <span>删除</span>
+            </el-button>
+        </template>
         <template #header>
             <div class="w-36">
-                <el-select v-model="searchForm.areaId" block clearable placeholder="请选择区域" size="large">
+                <el-select v-model="searchForm.areaId" block clearable placeholder="请选择区域">
                     <el-option v-for="item in areaType" :key="item.id" :label="item.areaName" :value="item.id" />
                 </el-select>
             </div>
             <div class="w-36 ml-4">
-                <el-date-picker v-model="searchForm.startDate" class="block" type="date" value-format="YYYY-MM-DD" placeholder="开始日期" clearable size="large" />
+                <el-date-picker v-model="searchForm.startDate" class="block" type="date" value-format="YYYY-MM-DD" placeholder="开始日期" clearable />
             </div>
             <div class="mx-2">
                 ~
             </div>
             <div class="w-36">
-                <el-date-picker v-model="searchForm.endDate" class="block" type="date" value-format="YYYY-MM-DD" placeholder="结束日期" clearable size="large" />
+                <el-date-picker v-model="searchForm.endDate" class="block" type="date" value-format="YYYY-MM-DD" placeholder="结束日期" clearable />
             </div>
             <div class="w-48 ml-2">
-                <el-input v-model="searchForm.name" clearable placeholder="请输入名称进行查询" size="large" />
+                <el-input v-model="searchForm.name" clearable placeholder="请输入名称进行查询" />
             </div>
             <div class="ml-4">
-                <el-button type="primary" size="large" @click="searchClick">
+                <el-button type="primary" @click="searchClick">
                     <HcIcon name="search-2" />
                     <span>搜索</span>
                 </el-button>
             </div>
         </template>
-        <template #extra>
-            <el-button size="large" type="primary" hc-btn @click="addRowClick">
-                <HcIcon name="add" />
-                <span>新增</span>
-            </el-button>
-            <el-button size="large" type="danger" hc-btn :disabled="tableCheckedKeys.length < 1" @click="batchClick">
-                <HcIcon name="delete-bin" />
-                <span>删除</span>
-            </el-button>
-        </template>
-        <HcTable ref="tableListRef" :column="tableColumn" :datas="tableData" :loading="tableLoading" is-check @selection-change="tableSelectionChange">
+       
+        <HcTable ref="tableListRef" :column="tableColumn" :datas="tableData" :loading="tableLoading" is-check is-new @selection-change="tableSelectionChange">
             <template #action="{ row, index }">
                 <el-button size="small" type="warning" @click="previewPdf(row)">
                     查看附件
@@ -53,7 +54,7 @@
         </template>
 
         <!-- 新增/编辑 -->
-        <HcDialog is-to-body bg-color="white" :show="rowModal" :title="formModel.id ? '编辑' : '新增'" widths="62rem" :loading="submitLoading" @save="rowModalSave" @close="rowModalClose">
+        <hc-new-dialog is-to-body bg-color="white" :show="rowModal" :title="formModel.id ? '编辑' : '新增'" widths="62rem" :loading="submitLoading" @save="rowModalSave" @close="rowModalClose">
             <el-form ref="formRef" :model="formModel" :rules="formRules" label-position="left" label-width="auto" size="large">
                 <div class="flex">
                     <div class="flex-1 mr-4">
@@ -79,10 +80,10 @@
                     </div>
                 </div>
             </el-form>
-        </HcDialog>
+        </hc-new-dialog>
 
         <HcUploadFile ref="HcUploadFileRef" :options="UploadFileOptions" :params="{ projectId }" @finish="UploadFileFinish" @success="HcUploadFileSuccess" />
-    </HcCard>
+    </HcNewCard>
 </template>
 
 <script setup>

+ 14 - 14
src/views/base/crops.vue

@@ -7,34 +7,34 @@
                 </el-scrollbar>
             </div>
         </template>
-        <HcCard>
+        <HcNewCard padding>
             <template #header>
                 <div class="w-48">
-                    <el-select v-model="searchForm.compensationType" block clearable placeholder="请选择补偿性质" size="large">
+                    <el-select v-model="searchForm.compensationType" block clearable placeholder="请选择补偿性质">
                         <el-option v-for="item in compensationType" :key="item.id" :label="item.dictValue" :value="item.dictKey" />
                     </el-select>
                 </div>
                 <div class="w-64 ml-2">
-                    <el-input v-model="searchForm.name" clearable placeholder="请输入名称进行查询" size="large" />
+                    <el-input v-model="searchForm.name" clearable placeholder="请输入名称进行查询" />
                 </div>
                 <div class="ml-4">
-                    <el-button type="primary" size="large" @click="searchClick">
+                    <el-button type="primary" @click="searchClick">
                         <HcIcon name="search-2" />
                         <span>搜索</span>
                     </el-button>
                 </div>
             </template>
             <template #extra>
-                <el-button size="large" type="primary" hc-btn @click="addRowClick">
+                <el-button type="primary" hc-btn @click="addRowClick">
                     <HcIcon name="add" />
                     <span>新增</span>
                 </el-button>
-                <el-button size="large" type="danger" hc-btn :disabled="tableCheckedKeys.length < 1" @click="batchClick">
+                <el-button type="danger" hc-btn :disabled="tableCheckedKeys.length < 1" @click="batchClick">
                     <HcIcon name="delete-bin" />
                     <span>删除</span>
                 </el-button>
             </template>
-            <HcTable ref="tableListRef" :column="tableColumn" :datas="tableData" :loading="tableLoading" is-check @selection-change="tableSelectionChange">
+            <HcTable ref="tableListRef" is-new :column="tableColumn" :datas="tableData" :loading="tableLoading" is-check @selection-change="tableSelectionChange">
                 <template #action="{ row, index }">
                     <el-button size="small" type="warning" @click="viewRowClick(row)">
                         查看
@@ -50,10 +50,10 @@
             <template #action>
                 <HcPages :pages="searchForm" @change="pageChange" />
             </template>
-        </HcCard>
+        </HcNewCard>
 
         <!-- 新增/编辑 -->
-        <HcDialog
+        <hc-new-dialog
             is-to-body bg-color="white" :show="rowModal" is-table widths="80%" :padding="false"
             :title="formModel.id ? '编辑' : '新增'" :loading="submitLoading" @save="rowModalSave" @close="rowModalClose" 
         >
@@ -76,7 +76,7 @@
                         <span>新增</span>
                     </el-button>
                 </template>
-                <HcTable :column="tableColumn1" :datas="tableData1">
+                <HcTable :column="tableColumn1" :datas="tableData1" is-new>
                     <template #specificationName="{ row, index }">
                         <el-input v-model="row.specificationName" />
                     </template>
@@ -97,10 +97,10 @@
                     </template>
                 </HcTable>
             </HcCard>
-        </HcDialog>
+        </hc-new-dialog>
 
         <!-- 查看 -->
-        <HcDialog is-to-body bg-color="white" :footer="false" :show="rowViewModal" is-table widths="80%" :padding="false" title="查看" @close="rowViewModalClose">
+        <hc-new-dialog is-to-body bg-color="white" :footer="false" :show="rowViewModal" is-table widths="80%" :padding="false" title="查看" @close="rowViewModalClose">
             <HcCard>
                 <template #header>
                     <el-form inline :model="formModel" size="large" disabled>
@@ -114,9 +114,9 @@
                         </el-form-item>
                     </el-form>
                 </template>
-                <HcTable :column="tableColumn2" :datas="tableData1" />
+                <HcTable :column="tableColumn2" :datas="tableData1" is-new />
             </HcCard>
-        </HcDialog>
+        </hc-new-dialog>
     </HcPageLayout>
 </template>
 

+ 8 - 8
src/views/base/land.vue

@@ -7,18 +7,18 @@
                 </el-scrollbar>
             </div>
         </template>
-        <HcCard>
+        <HcNewCard padding>
             <template #header>
                 <div class="w-36">
-                    <el-select v-model="searchForm.landNature" block clearable placeholder="请选择土地性质" size="large">
+                    <el-select v-model="searchForm.landNature" block clearable placeholder="请选择土地性质">
                         <el-option v-for="item in natureType" :key="item.id" :label="item.dictValue" :value="item.dictKey" />
                     </el-select>
                 </div>
                 <div class="w-52 ml-2">
-                    <el-input v-model="searchForm.name" clearable placeholder="请输入名称进行查询" size="large" />
+                    <el-input v-model="searchForm.name" clearable placeholder="请输入名称进行查询" />
                 </div>
                 <div class="ml-4">
-                    <el-button type="primary" size="large" @click="searchClick">
+                    <el-button type="primary" @click="searchClick">
                         <HcIcon name="search-2" />
                         <span>搜索</span>
                     </el-button>
@@ -34,7 +34,7 @@
                     <span>删除</span>
                 </el-button>
             </template>
-            <HcTable ref="tableListRef" :column="tableColumn" :datas="tableData" :loading="tableLoading" is-check @selection-change="tableSelectionChange">
+            <HcTable ref="tableListRef" :column="tableColumn" :datas="tableData" :loading="tableLoading" is-check is-new @selection-change="tableSelectionChange">
                 <template #action="{ row, index }">
                     <el-button size="small" type="primary" @click="editRowClick(row)">
                         编辑
@@ -47,9 +47,9 @@
             <template #action>
                 <HcPages :pages="searchForm" @change="pageChange" />
             </template>
-        </HcCard>
+        </HcNewCard>
         <!-- 新增/编辑 -->
-        <HcDialog is-to-body bg-color="white" :show="rowModal" :title="formModel.id ? '编辑' : '新增'" widths="30rem" :loading="submitLoading" @save="rowModalSave" @close="rowModalClose">
+        <hc-new-dialog is-to-body bg-color="white" :show="rowModal" :title="formModel.id ? '编辑' : '新增'" widths="30rem" :loading="submitLoading" @save="rowModalSave" @close="rowModalClose">
             <el-form ref="formRef" :model="formModel" :rules="formRules" label-position="top" size="large">
                 <el-form-item label="名称:" prop="name">
                     <el-input v-model="formModel.name" />
@@ -66,7 +66,7 @@
                     <el-input v-model="formModel.agreementStand" />
                 </el-form-item>
             </el-form>
-        </HcDialog>
+        </hc-new-dialog>
     </HcPageLayout>
 </template>
 

+ 36 - 32
src/views/base/policy.vue

@@ -1,41 +1,45 @@
 <template>
-    <HcCard>
-        <template #header>
-            <div class="w-36">
-                <el-select v-model="searchForm.areaId" block clearable placeholder="请选择区域" size="large">
-                    <el-option v-for="item in areaType" :key="item.id" :label="item.areaName" :value="item.id" />
-                </el-select>
-            </div>
-            <div class="w-36 ml-4">
-                <el-date-picker v-model="searchForm.startDate" class="block" type="date" value-format="YYYY-MM-DD" placeholder="开始日期" clearable size="large" />
-            </div>
-            <div class="mx-2">
-                ~
-            </div>
-            <div class="w-36">
-                <el-date-picker v-model="searchForm.endDate" class="block" type="date" value-format="YYYY-MM-DD" placeholder="结束日期" clearable size="large" />
-            </div>
-            <div class="w-48 ml-2">
-                <el-input v-model="searchForm.name" clearable placeholder="请输入名称进行查询" size="large" />
-            </div>
-            <div class="ml-4">
-                <el-button type="primary" size="large" @click="searchClick">
-                    <HcIcon name="search-2" />
-                    <span>搜索</span>
-                </el-button>
-            </div>
-        </template>
+    <HcNewCard padding>
         <template #extra>
-            <el-button size="large" type="primary" hc-btn @click="addRowClick">
+            <el-button type="primary" hc-btn @click="addRowClick">
                 <HcIcon name="add" />
                 <span>新增</span>
             </el-button>
-            <el-button size="large" type="danger" hc-btn :disabled="tableCheckedKeys.length < 1" @click="batchClick">
+            <el-button type="danger" hc-btn :disabled="tableCheckedKeys.length < 1" @click="batchClick">
                 <HcIcon name="delete-bin" />
                 <span>删除</span>
             </el-button>
         </template>
-        <HcTable ref="tableListRef" :column="tableColumn" :datas="tableData" :loading="tableLoading" is-check @selection-change="tableSelectionChange">
+        <template #header>
+            <div class="flex items-center">
+                <div class="w-36">
+                    <el-select v-model="searchForm.areaId" block clearable placeholder="请选择区域">
+                        <el-option v-for="item in areaType" :key="item.id" :label="item.areaName" :value="item.id" />
+                    </el-select>
+                </div>
+                <div class="w-36 ml-4">
+                    <el-date-picker v-model="searchForm.startDate" class="block" type="date" value-format="YYYY-MM-DD" placeholder="开始日期" clearable />
+                </div>
+                <div class="mx-2">
+                    ~
+                </div>
+                <div class="w-36">
+                    <el-date-picker v-model="searchForm.endDate" class="block" type="date" value-format="YYYY-MM-DD" placeholder="结束日期" clearable />
+                </div>
+                <div class="w-48 ml-2">
+                    <el-input v-model="searchForm.name" clearable placeholder="请输入名称进行查询" />
+                </div>
+                <div class="ml-4">
+                    <el-button type="primary" @click="searchClick">
+                        <HcIcon name="search-2" />
+                        <span>搜索</span>
+                    </el-button>
+                </div>
+            </div>
+        </template>
+      
+    
+        <HcTable ref="tableListRef" :column="tableColumn" :datas="tableData" :loading="tableLoading" is-check is-new @selection-change="tableSelectionChange">
             <template #action="{ row, index }">
                 <el-button size="small" type="warning" @click="previewPdf(row)">
                     查看附件
@@ -53,7 +57,7 @@
         </template>
 
         <!-- 新增/编辑 -->
-        <HcDialog is-to-body bg-color="white" :show="rowModal" :title="formModel.id ? '编辑' : '新增'" widths="62rem" :loading="submitLoading" @save="rowModalSave" @close="rowModalClose">
+        <hc-new-dialog is-to-body bg-color="white" :show="rowModal" :title="formModel.id ? '编辑' : '新增'" widths="62rem" :loading="submitLoading" @save="rowModalSave" @close="rowModalClose">
             <el-form ref="formRef" :model="formModel" :rules="formRules" label-position="left" label-width="auto" size="large">
                 <div class="flex">
                     <div class="flex-1 mr-4">
@@ -79,10 +83,10 @@
                     </div>
                 </div>
             </el-form>
-        </HcDialog>
+        </hc-new-dialog>
 
         <HcUploadFile ref="HcUploadFileRef" :options="UploadFileOptions" :params="{ projectId }" @finish="UploadFileFinish" @success="HcUploadFileSuccess" />
-    </HcCard>
+    </HcNewCard>
 </template>
 
 <script setup>

+ 9 - 9
src/views/base/region.vue

@@ -1,29 +1,29 @@
 <template>
-    <HcCard>
+    <HcNewCard padding>
         <template #header>
             <div class="w-64">
-                <el-input v-model="searchForm.name" clearable placeholder="请输入名称进行查询" size="large" />
+                <el-input v-model="searchForm.name" clearable placeholder="请输入名称进行查询" />
             </div>
             <div class="ml-4">
-                <el-button type="primary" size="large" @click="searchClick">
+                <el-button type="primary" @click="searchClick">
                     <HcIcon name="search-2" />
                     <span>搜索</span>
                 </el-button>
             </div>
         </template>
         <template #extra>
-            <el-button size="large" type="primary" hc-btn @click="addRowClick">
+            <el-button type="primary" hc-btn @click="addRowClick">
                 <HcIcon name="add" />
                 <span>新增</span>
             </el-button>
-            <el-button size="large" type="danger" hc-btn :disabled="tableCheckedKeys.length < 1" @click="batchClick">
+            <el-button type="danger" hc-btn :disabled="tableCheckedKeys.length < 1" @click="batchClick">
                 <HcIcon name="delete-bin" />
                 <span>删除</span>
             </el-button>
         </template>
         <div class="base-region-box">
             <div id="region-01" class="base-region-table">
-                <HcTable ref="tableListRef" :column="tableColumn" :datas="tableData" :loading="tableLoading" is-check @selection-change="tableSelectionChange" @row-click="rowView">
+                <HcTable ref="tableListRef" is-new :column="tableColumn" :datas="tableData" :loading="tableLoading" is-check @selection-change="tableSelectionChange" @row-click="rowView">
                     <template #action="{ row, index }">
                         <el-button size="small" type="primary" @click="editRowClick(row)">
                             编辑
@@ -62,7 +62,7 @@
         </template>
 
         <!-- 新增/编辑 -->
-        <HcDialog is-to-body bg-color="white" :show="rowModal" is-table widths="62rem" :title="formModel.id ? '编辑' : '新增'" :loading="submitLoading" @save="rowModalSave" @close="rowModalClose">
+        <hc-new-dialog is-to-body bg-color="white" :show="rowModal" is-table widths="62rem" :title="formModel.id ? '编辑' : '新增'" :loading="submitLoading" @save="rowModalSave" @close="rowModalClose">
             <div class="base-region-dialog">
                 <div class="dialog-form">
                     <el-scrollbar>
@@ -93,8 +93,8 @@
                     </div>
                 </div>
             </div>
-        </HcDialog>
-    </HcCard>
+        </hc-new-dialog>
+    </HcNewCard>
 </template>
 
 <script setup>

+ 204 - 168
yarn.lock

@@ -12,10 +12,10 @@
   resolved "http://47.110.251.215:9000/@alloc/quick-lru/-/quick-lru-5.2.0.tgz#7bf68b20c0a350f936915fcae06f58e32007ce30"
   integrity sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==
 
-"@babel/parser@^7.20.15", "@babel/parser@^7.21.3":
-  version "7.22.5"
-  resolved "http://47.110.251.215:9000/@babel/parser/-/parser-7.22.5.tgz#721fd042f3ce1896238cf1b341c77eb7dee7dbea"
-  integrity sha512-DFZMC9LJUG9PLOclRC32G63UXwzqS2koQC8dkx+PLdmt1xSePYpbT/NbsrJy8Q/muXz7o/h/d4A7Fuyixm559Q==
+"@babel/parser@^7.23.0":
+  version "7.23.0"
+  resolved "http://47.110.251.215:9000/@babel/parser/-/parser-7.23.0.tgz#da950e622420bf96ca0d0f2909cdddac3acd8719"
+  integrity sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==
 
 "@ctrl/tinycolor@^3.4.1":
   version "3.6.1"
@@ -164,10 +164,10 @@
     minimatch "^3.1.2"
     strip-json-comments "^3.1.1"
 
-"@eslint/js@8.49.0":
-  version "8.49.0"
-  resolved "http://47.110.251.215:9000/@eslint/js/-/js-8.49.0.tgz#86f79756004a97fa4df866835093f1df3d03c333"
-  integrity sha512-1S8uAY/MTJqVx0SC4epBq+N2yhuwtNwLbJYNZyhL2pO1ZVKn5HFXav5T41Ryzy9K9V7ZId2JB2oy/W4aCd9/2w==
+"@eslint/js@8.52.0":
+  version "8.52.0"
+  resolved "http://47.110.251.215:9000/@eslint/js/-/js-8.52.0.tgz#78fe5f117840f69dc4a353adf9b9cd926353378c"
+  integrity sha512-mjZVbpaeMZludF2fsWLD0Z9gCref1Tk4i9+wddjRvpUNqqcndPkBD09N/Mapey0b3jaXbLm2kICwFv2E64QinA==
 
 "@floating-ui/core@^1.4.2":
   version "1.5.0"
@@ -189,12 +189,12 @@
   resolved "http://47.110.251.215:9000/@floating-ui/utils/-/utils-0.1.4.tgz#19654d1026cc410975d46445180e70a5089b3e7d"
   integrity sha512-qprfWkn82Iw821mcKofJ5Pk9wgioHicxcQMxx+5zt5GSKoqdWvgG5AxVmpmUUjzTLPVSH5auBrhI93Deayn/DA==
 
-"@humanwhocodes/config-array@^0.11.11":
-  version "0.11.11"
-  resolved "http://47.110.251.215:9000/@humanwhocodes/config-array/-/config-array-0.11.11.tgz#88a04c570dbbc7dd943e4712429c3df09bc32844"
-  integrity sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==
+"@humanwhocodes/config-array@^0.11.13":
+  version "0.11.13"
+  resolved "http://47.110.251.215:9000/@humanwhocodes/config-array/-/config-array-0.11.13.tgz#075dc9684f40a531d9b26b0822153c1e832ee297"
+  integrity sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==
   dependencies:
-    "@humanwhocodes/object-schema" "^1.2.1"
+    "@humanwhocodes/object-schema" "^2.0.1"
     debug "^4.1.1"
     minimatch "^3.0.5"
 
@@ -203,10 +203,10 @@
   resolved "http://47.110.251.215:9000/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c"
   integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==
 
-"@humanwhocodes/object-schema@^1.2.1":
-  version "1.2.1"
-  resolved "http://47.110.251.215:9000/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45"
-  integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==
+"@humanwhocodes/object-schema@^2.0.1":
+  version "2.0.1"
+  resolved "http://47.110.251.215:9000/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz#e5211452df060fa8522b55c7b3c0c4d1981cb044"
+  integrity sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==
 
 "@jridgewell/gen-mapping@^0.3.2":
   version "0.3.3"
@@ -232,7 +232,7 @@
   resolved "http://47.110.251.215:9000/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24"
   integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==
 
-"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.13":
+"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.15":
   version "1.4.15"
   resolved "http://47.110.251.215:9000/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32"
   integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==
@@ -293,105 +293,110 @@
   resolved "http://47.110.251.215:9000/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz#1d12873a8e49567371f2a75fe3e7f7edca6662d8"
   integrity sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ==
 
-"@vitejs/plugin-vue@^4.2.3":
-  version "4.3.4"
-  resolved "http://47.110.251.215:9000/@vitejs/plugin-vue/-/plugin-vue-4.3.4.tgz#a289dff38e01949fe7be581d5542cabaeb961dec"
-  integrity sha512-ciXNIHKPriERBisHFBvnTbfKa6r9SAesOYXeGDzgegcvy9Q4xdScSHAmKbNT0M3O0S9LKhIf5/G+UYG4NnnzYw==
+"@ungap/structured-clone@^1.2.0":
+  version "1.2.0"
+  resolved "http://47.110.251.215:9000/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406"
+  integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==
 
-"@vue/compiler-core@3.3.4":
-  version "3.3.4"
-  resolved "http://47.110.251.215:9000/@vue/compiler-core/-/compiler-core-3.3.4.tgz#7fbf591c1c19e1acd28ffd284526e98b4f581128"
-  integrity sha512-cquyDNvZ6jTbf/+x+AgM2Arrp6G4Dzbb0R64jiG804HRMfRiFXWI6kqUVqZ6ZR0bQhIoQjB4+2bhNtVwndW15g==
+"@vitejs/plugin-vue@^4.4.0":
+  version "4.4.0"
+  resolved "http://47.110.251.215:9000/@vitejs/plugin-vue/-/plugin-vue-4.4.0.tgz#8ae96573236cdb12de6850a6d929b5537ec85390"
+  integrity sha512-xdguqb+VUwiRpSg+nsc2HtbAUSGak25DXYvpQQi4RVU1Xq1uworyoH/md9Rfd8zMmPR/pSghr309QNcftUVseg==
+
+"@vue/compiler-core@3.3.7":
+  version "3.3.7"
+  resolved "http://47.110.251.215:9000/@vue/compiler-core/-/compiler-core-3.3.7.tgz#865a5734c971686d9737d85a0c5a08de045b6162"
+  integrity sha512-pACdY6YnTNVLXsB86YD8OF9ihwpolzhhtdLVHhBL6do/ykr6kKXNYABRtNMGrsQXpEXXyAdwvWWkuTbs4MFtPQ==
   dependencies:
-    "@babel/parser" "^7.21.3"
-    "@vue/shared" "3.3.4"
+    "@babel/parser" "^7.23.0"
+    "@vue/shared" "3.3.7"
     estree-walker "^2.0.2"
     source-map-js "^1.0.2"
 
-"@vue/compiler-dom@3.3.4":
-  version "3.3.4"
-  resolved "http://47.110.251.215:9000/@vue/compiler-dom/-/compiler-dom-3.3.4.tgz#f56e09b5f4d7dc350f981784de9713d823341151"
-  integrity sha512-wyM+OjOVpuUukIq6p5+nwHYtj9cFroz9cwkfmP9O1nzH68BenTTv0u7/ndggT8cIQlnBeOo6sUT/gvHcIkLA5w==
-  dependencies:
-    "@vue/compiler-core" "3.3.4"
-    "@vue/shared" "3.3.4"
-
-"@vue/compiler-sfc@3.3.4", "@vue/compiler-sfc@^3.3.4":
-  version "3.3.4"
-  resolved "http://47.110.251.215:9000/@vue/compiler-sfc/-/compiler-sfc-3.3.4.tgz#b19d942c71938893535b46226d602720593001df"
-  integrity sha512-6y/d8uw+5TkCuzBkgLS0v3lSM3hJDntFEiUORM11pQ/hKvkhSKZrXW6i69UyXlJQisJxuUEJKAWEqWbWsLeNKQ==
-  dependencies:
-    "@babel/parser" "^7.20.15"
-    "@vue/compiler-core" "3.3.4"
-    "@vue/compiler-dom" "3.3.4"
-    "@vue/compiler-ssr" "3.3.4"
-    "@vue/reactivity-transform" "3.3.4"
-    "@vue/shared" "3.3.4"
+"@vue/compiler-dom@3.3.7":
+  version "3.3.7"
+  resolved "http://47.110.251.215:9000/@vue/compiler-dom/-/compiler-dom-3.3.7.tgz#a245aa03f9bfcdb537a239bf02842072de0644c9"
+  integrity sha512-0LwkyJjnUPssXv/d1vNJ0PKfBlDoQs7n81CbO6Q0zdL7H1EzqYRrTVXDqdBVqro0aJjo/FOa1qBAPVI4PGSHBw==
+  dependencies:
+    "@vue/compiler-core" "3.3.7"
+    "@vue/shared" "3.3.7"
+
+"@vue/compiler-sfc@3.3.7", "@vue/compiler-sfc@^3.3.7":
+  version "3.3.7"
+  resolved "http://47.110.251.215:9000/@vue/compiler-sfc/-/compiler-sfc-3.3.7.tgz#219d04b3013c7b15fbc536e2279e07810b731cc2"
+  integrity sha512-7pfldWy/J75U/ZyYIXRVqvLRw3vmfxDo2YLMwVtWVNew8Sm8d6wodM+OYFq4ll/UxfqVr0XKiVwti32PCrruAw==
+  dependencies:
+    "@babel/parser" "^7.23.0"
+    "@vue/compiler-core" "3.3.7"
+    "@vue/compiler-dom" "3.3.7"
+    "@vue/compiler-ssr" "3.3.7"
+    "@vue/reactivity-transform" "3.3.7"
+    "@vue/shared" "3.3.7"
     estree-walker "^2.0.2"
-    magic-string "^0.30.0"
-    postcss "^8.1.10"
+    magic-string "^0.30.5"
+    postcss "^8.4.31"
     source-map-js "^1.0.2"
 
-"@vue/compiler-ssr@3.3.4":
-  version "3.3.4"
-  resolved "http://47.110.251.215:9000/@vue/compiler-ssr/-/compiler-ssr-3.3.4.tgz#9d1379abffa4f2b0cd844174ceec4a9721138777"
-  integrity sha512-m0v6oKpup2nMSehwA6Uuu+j+wEwcy7QmwMkVNVfrV9P2qE5KshC6RwOCq8fjGS/Eak/uNb8AaWekfiXxbBB6gQ==
+"@vue/compiler-ssr@3.3.7":
+  version "3.3.7"
+  resolved "http://47.110.251.215:9000/@vue/compiler-ssr/-/compiler-ssr-3.3.7.tgz#eff4a70f7ceb800d60e68d208b96a030c0f1b636"
+  integrity sha512-TxOfNVVeH3zgBc82kcUv+emNHo+vKnlRrkv8YvQU5+Y5LJGJwSNzcmLUoxD/dNzv0bhQ/F0s+InlgV0NrApJZg==
   dependencies:
-    "@vue/compiler-dom" "3.3.4"
-    "@vue/shared" "3.3.4"
+    "@vue/compiler-dom" "3.3.7"
+    "@vue/shared" "3.3.7"
 
 "@vue/devtools-api@^6.5.0":
   version "6.5.0"
   resolved "http://47.110.251.215:9000/@vue/devtools-api/-/devtools-api-6.5.0.tgz#98b99425edee70b4c992692628fa1ea2c1e57d07"
   integrity sha512-o9KfBeaBmCKl10usN4crU53fYtC1r7jJwdGKjPT24t348rHxgfpZ0xL3Xm/gLUYnc0oTp8LAmrxOeLyu6tbk2Q==
 
-"@vue/reactivity-transform@3.3.4":
-  version "3.3.4"
-  resolved "http://47.110.251.215:9000/@vue/reactivity-transform/-/reactivity-transform-3.3.4.tgz#52908476e34d6a65c6c21cd2722d41ed8ae51929"
-  integrity sha512-MXgwjako4nu5WFLAjpBnCj/ieqcjE2aJBINUNQzkZQfzIZA4xn+0fV1tIYBJvvva3N3OvKGofRLvQIwEQPpaXw==
+"@vue/reactivity-transform@3.3.7":
+  version "3.3.7"
+  resolved "http://47.110.251.215:9000/@vue/reactivity-transform/-/reactivity-transform-3.3.7.tgz#eb9f5110af5085079b851d162205394bc790d539"
+  integrity sha512-APhRmLVbgE1VPGtoLQoWBJEaQk4V8JUsqrQihImVqKT+8U6Qi3t5ATcg4Y9wGAPb3kIhetpufyZ1RhwbZCIdDA==
   dependencies:
-    "@babel/parser" "^7.20.15"
-    "@vue/compiler-core" "3.3.4"
-    "@vue/shared" "3.3.4"
+    "@babel/parser" "^7.23.0"
+    "@vue/compiler-core" "3.3.7"
+    "@vue/shared" "3.3.7"
     estree-walker "^2.0.2"
-    magic-string "^0.30.0"
+    magic-string "^0.30.5"
 
-"@vue/reactivity@3.3.4":
-  version "3.3.4"
-  resolved "http://47.110.251.215:9000/@vue/reactivity/-/reactivity-3.3.4.tgz#a27a29c6cd17faba5a0e99fbb86ee951653e2253"
-  integrity sha512-kLTDLwd0B1jG08NBF3R5rqULtv/f8x3rOFByTDz4J53ttIQEDmALqKqXY0J+XQeN0aV2FBxY8nJDf88yvOPAqQ==
+"@vue/reactivity@3.3.7":
+  version "3.3.7"
+  resolved "http://47.110.251.215:9000/@vue/reactivity/-/reactivity-3.3.7.tgz#48b6671a45ba33039da2c0eb25ae702f924486a9"
+  integrity sha512-cZNVjWiw00708WqT0zRpyAgduG79dScKEPYJXq2xj/aMtk3SKvL3FBt2QKUlh6EHBJ1m8RhBY+ikBUzwc7/khg==
   dependencies:
-    "@vue/shared" "3.3.4"
+    "@vue/shared" "3.3.7"
 
-"@vue/runtime-core@3.3.4":
-  version "3.3.4"
-  resolved "http://47.110.251.215:9000/@vue/runtime-core/-/runtime-core-3.3.4.tgz#4bb33872bbb583721b340f3088888394195967d1"
-  integrity sha512-R+bqxMN6pWO7zGI4OMlmvePOdP2c93GsHFM/siJI7O2nxFRzj55pLwkpCedEY+bTMgp5miZ8CxfIZo3S+gFqvA==
+"@vue/runtime-core@3.3.7":
+  version "3.3.7"
+  resolved "http://47.110.251.215:9000/@vue/runtime-core/-/runtime-core-3.3.7.tgz#c1eece1c98f936dc69dd0667d11b464579b128fd"
+  integrity sha512-LHq9du3ubLZFdK/BP0Ysy3zhHqRfBn80Uc+T5Hz3maFJBGhci1MafccnL3rpd5/3wVfRHAe6c+PnlO2PAavPTQ==
   dependencies:
-    "@vue/reactivity" "3.3.4"
-    "@vue/shared" "3.3.4"
+    "@vue/reactivity" "3.3.7"
+    "@vue/shared" "3.3.7"
 
-"@vue/runtime-dom@3.3.4":
-  version "3.3.4"
-  resolved "http://47.110.251.215:9000/@vue/runtime-dom/-/runtime-dom-3.3.4.tgz#992f2579d0ed6ce961f47bbe9bfe4b6791251566"
-  integrity sha512-Aj5bTJ3u5sFsUckRghsNjVTtxZQ1OyMWCr5dZRAPijF/0Vy4xEoRCwLyHXcj4D0UFbJ4lbx3gPTgg06K/GnPnQ==
+"@vue/runtime-dom@3.3.7":
+  version "3.3.7"
+  resolved "http://47.110.251.215:9000/@vue/runtime-dom/-/runtime-dom-3.3.7.tgz#e7cf88cc01591fdf6e3164825554fdadc3137ffc"
+  integrity sha512-PFQU1oeJxikdDmrfoNQay5nD4tcPNYixUBruZzVX/l0eyZvFKElZUjW4KctCcs52nnpMGO6UDK+jF5oV4GT5Lw==
   dependencies:
-    "@vue/runtime-core" "3.3.4"
-    "@vue/shared" "3.3.4"
-    csstype "^3.1.1"
+    "@vue/runtime-core" "3.3.7"
+    "@vue/shared" "3.3.7"
+    csstype "^3.1.2"
 
-"@vue/server-renderer@3.3.4":
-  version "3.3.4"
-  resolved "http://47.110.251.215:9000/@vue/server-renderer/-/server-renderer-3.3.4.tgz#ea46594b795d1536f29bc592dd0f6655f7ea4c4c"
-  integrity sha512-Q6jDDzR23ViIb67v+vM1Dqntu+HUexQcsWKhhQa4ARVzxOY2HbC7QRW/ggkDBd5BU+uM1sV6XOAP0b216o34JQ==
+"@vue/server-renderer@3.3.7":
+  version "3.3.7"
+  resolved "http://47.110.251.215:9000/@vue/server-renderer/-/server-renderer-3.3.7.tgz#0cc3dc6ad39a54693e6e8f853caa3c7bb43b0364"
+  integrity sha512-UlpKDInd1hIZiNuVVVvLgxpfnSouxKQOSE2bOfQpBuGwxRV/JqqTCyyjXUWiwtVMyeRaZhOYYqntxElk8FhBhw==
   dependencies:
-    "@vue/compiler-ssr" "3.3.4"
-    "@vue/shared" "3.3.4"
+    "@vue/compiler-ssr" "3.3.7"
+    "@vue/shared" "3.3.7"
 
-"@vue/shared@3.3.4":
-  version "3.3.4"
-  resolved "http://47.110.251.215:9000/@vue/shared/-/shared-3.3.4.tgz#06e83c5027f464eef861c329be81454bc8b70780"
-  integrity sha512-7OjdcV8vQ74eiz1TZLzZP4JwqM5fA94K6yntPS5Z25r9HDuGNzaGdgvwKYq6S+MxwF0TFRwe50fIR/MYnakdkQ==
+"@vue/shared@3.3.7":
+  version "3.3.7"
+  resolved "http://47.110.251.215:9000/@vue/shared/-/shared-3.3.7.tgz#0091852fe5cc4237c8440fe32f3ab6bc920ae6d9"
+  integrity sha512-N/tbkINRUDExgcPTBvxNkvHGu504k8lzlNQRITVnm6YjOjwa4r0nnbd4Jb01sNpur5hAllyRJzSK5PvB9PPwRg==
 
 "@vueuse/core@^9.1.0":
   version "9.13.0"
@@ -522,10 +527,10 @@ autoprefixer@^10.4.16:
     picocolors "^1.0.0"
     postcss-value-parser "^4.2.0"
 
-axios@^1.4.0, axios@^1.5.0:
-  version "1.5.0"
-  resolved "http://47.110.251.215:9000/axios/-/axios-1.5.0.tgz#f02e4af823e2e46a9768cfc74691fdd0517ea267"
-  integrity sha512-D4DdjDo5CY50Qms0qGQTTw6Q44jl7zRwY7bthds06pUGfChBCTcQs+N743eFWGEd6pRTMd6A+I87aWyFV5wiZQ==
+axios@^1.5.1, axios@^1.6.0:
+  version "1.6.0"
+  resolved "http://47.110.251.215:9000/axios/-/axios-1.6.0.tgz#f1e5292f26b2fd5c2e66876adc5b06cdbd7d2102"
+  integrity sha512-EZ1DYihju9pwVB+jg67ogm+Tmqc6JmhamRN6I4Zt8DfZu5lbcQGw3ozH9lFejSJgs/ibaef3A9PMXPLeefFGJg==
   dependencies:
     follow-redirects "^1.15.0"
     form-data "^4.0.0"
@@ -727,10 +732,10 @@ cross-spawn@^7.0.2:
     shebang-command "^2.0.0"
     which "^2.0.1"
 
-crypto-js@^4.1.1:
-  version "4.1.1"
-  resolved "http://47.110.251.215:9000/crypto-js/-/crypto-js-4.1.1.tgz#9e485bcf03521041bd85844786b83fb7619736cf"
-  integrity sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw==
+crypto-js@^4.2.0:
+  version "4.2.0"
+  resolved "http://47.110.251.215:9000/crypto-js/-/crypto-js-4.2.0.tgz#4d931639ecdfd12ff80e8186dba6af2c2e856631"
+  integrity sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==
 
 css-declaration-sorter@^6.3.1:
   version "6.4.0"
@@ -829,7 +834,7 @@ csso@^5.0.5:
   dependencies:
     css-tree "~2.2.0"
 
-csstype@^3.1.1:
+csstype@^3.1.2:
   version "3.1.2"
   resolved "http://47.110.251.215:9000/csstype/-/csstype-3.1.2.tgz#1d4bf9d572f11c14031f0436e1c10bc1f571f50b"
   integrity sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==
@@ -937,6 +942,27 @@ element-plus@2.3.14:
     memoize-one "^6.0.0"
     normalize-wheel-es "^1.2.0"
 
+element-plus@2.4.1:
+  version "2.4.1"
+  resolved "http://47.110.251.215:9000/element-plus/-/element-plus-2.4.1.tgz#8a5faa69e856d82494b94d77fb485d9e727c8bc1"
+  integrity sha512-t7nl+vQlkBKVk1Ag6AufSDyFV8YIXxTFsaya4Nz/0tiRlcz65WPN4WMFeNURuFJleu1HLNtP4YyQKMuS7El8uA==
+  dependencies:
+    "@ctrl/tinycolor" "^3.4.1"
+    "@element-plus/icons-vue" "^2.0.6"
+    "@floating-ui/dom" "^1.0.1"
+    "@popperjs/core" "npm:@sxzz/popperjs-es@^2.11.7"
+    "@types/lodash" "^4.14.182"
+    "@types/lodash-es" "^4.17.6"
+    "@vueuse/core" "^9.1.0"
+    async-validator "^4.2.5"
+    dayjs "^1.11.3"
+    escape-html "^1.0.3"
+    lodash "^4.17.21"
+    lodash-es "^4.17.21"
+    lodash-unified "^1.0.2"
+    memoize-one "^6.0.0"
+    normalize-wheel-es "^1.2.0"
+
 entities@^4.2.0:
   version "4.5.0"
   resolved "http://47.110.251.215:9000/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48"
@@ -985,10 +1011,10 @@ escape-string-regexp@^4.0.0:
   resolved "http://47.110.251.215:9000/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
   integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
 
-eslint-plugin-vue@^9.15.1:
-  version "9.17.0"
-  resolved "http://47.110.251.215:9000/eslint-plugin-vue/-/eslint-plugin-vue-9.17.0.tgz#4501547373f246547083482838b4c8f4b28e5932"
-  integrity sha512-r7Bp79pxQk9I5XDP0k2dpUC7Ots3OSWgvGZNu3BxmKK6Zg7NgVtcOB6OCna5Kb9oQwJPl5hq183WD0SY5tZtIQ==
+eslint-plugin-vue@^9.18.1:
+  version "9.18.1"
+  resolved "http://47.110.251.215:9000/eslint-plugin-vue/-/eslint-plugin-vue-9.18.1.tgz#73cf29df7450ce5913296465f8d1dc545344920c"
+  integrity sha512-7hZFlrEgg9NIzuVik2I9xSnJA5RsmOfueYgsUGUokEDLJ1LHtxO0Pl4duje1BriZ/jDWb+44tcIlC3yi0tdlZg==
   dependencies:
     "@eslint-community/eslint-utils" "^4.4.0"
     natural-compare "^1.4.0"
@@ -1011,18 +1037,19 @@ eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4
   resolved "http://47.110.251.215:9000/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800"
   integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==
 
-eslint@^8.44.0:
-  version "8.49.0"
-  resolved "http://47.110.251.215:9000/eslint/-/eslint-8.49.0.tgz#09d80a89bdb4edee2efcf6964623af1054bf6d42"
-  integrity sha512-jw03ENfm6VJI0jA9U+8H5zfl5b+FvuU3YYvZRdZHOlU2ggJkxrlkJH4HcDrZpj6YwD8kuYqvQM8LyesoazrSOQ==
+eslint@^8.52.0:
+  version "8.52.0"
+  resolved "http://47.110.251.215:9000/eslint/-/eslint-8.52.0.tgz#d0cd4a1fac06427a61ef9242b9353f36ea7062fc"
+  integrity sha512-zh/JHnaixqHZsolRB/w9/02akBk9EPrOs9JwcTP2ek7yL5bVvXuRariiaAjjoJ5DvuwQ1WAE/HsMz+w17YgBCg==
   dependencies:
     "@eslint-community/eslint-utils" "^4.2.0"
     "@eslint-community/regexpp" "^4.6.1"
     "@eslint/eslintrc" "^2.1.2"
-    "@eslint/js" "8.49.0"
-    "@humanwhocodes/config-array" "^0.11.11"
+    "@eslint/js" "8.52.0"
+    "@humanwhocodes/config-array" "^0.11.13"
     "@humanwhocodes/module-importer" "^1.0.1"
     "@nodelib/fs.walk" "^1.2.8"
+    "@ungap/structured-clone" "^1.2.0"
     ajv "^6.12.4"
     chalk "^4.0.0"
     cross-spawn "^7.0.2"
@@ -1102,10 +1129,10 @@ fast-fifo@^1.1.0, fast-fifo@^1.2.0:
   resolved "http://47.110.251.215:9000/fast-fifo/-/fast-fifo-1.3.2.tgz#286e31de96eb96d38a97899815740ba2a4f3640c"
   integrity sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==
 
-fast-glob@^3.2.12:
-  version "3.2.12"
-  resolved "http://47.110.251.215:9000/fast-glob/-/fast-glob-3.2.12.tgz#7f39ec99c2e6ab030337142da9e0c18f37afae80"
-  integrity sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==
+fast-glob@^3.3.0:
+  version "3.3.1"
+  resolved "http://47.110.251.215:9000/fast-glob/-/fast-glob-3.3.1.tgz#784b4e897340f3dbbef17413b3f11acf03c874c4"
+  integrity sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==
   dependencies:
     "@nodelib/fs.stat" "^2.0.2"
     "@nodelib/fs.walk" "^1.2.3"
@@ -1278,20 +1305,20 @@ has@^1.0.3:
   dependencies:
     function-bind "^1.1.1"
 
-hc-vue3-ui@^2.0.9:
-  version "2.0.9"
-  resolved "http://47.110.251.215:9000/hc-vue3-ui/-/hc-vue3-ui-2.0.9.tgz#033e5741c5207fcbf4ec6647cbb43eb9fd5de3ee"
-  integrity sha512-zefjcoUk/eWVMoWtjpCRKJXeK/DiHZjan7hT86EiZUDHzINk7IOGcGcpEIrZoFLzqIwlmAbwNU6OTVEW17Cwyw==
+hc-vue3-ui@^2.3.4:
+  version "2.3.4"
+  resolved "http://47.110.251.215:9000/hc-vue3-ui/-/hc-vue3-ui-2.3.4.tgz#67fe7e125176bbd6031fca55b8ab2d64ca30215e"
+  integrity sha512-6zNLI0alZuJ3HBtkWzB79S5fIUVhVGcM2vnw6d48PZt8GvqBA6yZsAoLTseNza9vHbVeI8Jj3MzKb7TdQpQCrA==
   dependencies:
-    axios "^1.5.0"
+    axios "^1.5.1"
     dayjs "^1.11.10"
-    element-plus "2.3.14"
+    element-plus "2.4.1"
     js-fast-way "^0.2.9"
-    js-md5 "^0.7.3"
+    js-md5 "^0.8.3"
     lottie-web "^5.12.2"
     simple-uploader.js "^0.6.0"
     sortablejs "^1.15.0"
-    vue "3.3.4"
+    vue "3.3.7"
     vuedraggable "^2.24.3"
 
 ignore@^5.2.0:
@@ -1376,10 +1403,10 @@ isexe@^2.0.0:
   resolved "http://47.110.251.215:9000/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
   integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==
 
-jiti@^1.18.2:
-  version "1.18.2"
-  resolved "http://47.110.251.215:9000/jiti/-/jiti-1.18.2.tgz#80c3ef3d486ebf2450d9335122b32d121f2a83cd"
-  integrity sha512-QAdOptna2NYiSSpv0O/BwoHBSmz4YhpzJHyi+fnMRTXFjp7B8i/YG5Z8IfusxB1ufjcD2Sre1F3R+nX3fvy7gg==
+jiti@^1.19.1:
+  version "1.20.0"
+  resolved "http://47.110.251.215:9000/jiti/-/jiti-1.20.0.tgz#2d823b5852ee8963585c8dd8b7992ffc1ae83b42"
+  integrity sha512-3TV69ZbrvV6U5DfQimop50jE9Dl6J8O1ja1dvBbMba/sZ3YBEQqJ2VZRoQPVnhlzjNtU1vaXRZVrVjU4qtm8yA==
 
 js-base64@^3.7.5:
   version "3.7.5"
@@ -1396,10 +1423,10 @@ js-fast-way@^0.2.9:
   resolved "http://47.110.251.215:9000/js-fast-way/-/js-fast-way-0.2.9.tgz#fd193f1a63644315331274474232d18d2c494c35"
   integrity sha512-ORSz9K/vLBu0Xo9dXgAS9nbqi35BsooPZYj1EpkjOWEVQ8hz3dUFGwTG2r7huZyxxnWd2fXoZwSe0X77aPwhlg==
 
-js-md5@^0.7.3:
-  version "0.7.3"
-  resolved "http://47.110.251.215:9000/js-md5/-/js-md5-0.7.3.tgz#b4f2fbb0b327455f598d6727e38ec272cd09c3f2"
-  integrity sha512-ZC41vPSTLKGwIRjqDh8DfXoCrdQIyBgspJVPXHBGu4nZlAEvG3nf+jO9avM9RmLiGakg7vz974ms99nEV0tmTQ==
+js-md5@^0.8.3:
+  version "0.8.3"
+  resolved "http://47.110.251.215:9000/js-md5/-/js-md5-0.8.3.tgz#921bab7efa95bfc9d62b87ee08a57f8fe4305b69"
+  integrity sha512-qR0HB5uP6wCuRMrWPTrkMaev7MJZwJuuw4fnwAzRgP4J4/F8RwtodOKpGp4XpqsLBFzzgqIO42efFAyz2Et6KQ==
 
 js-yaml@^4.1.0:
   version "4.1.0"
@@ -1504,12 +1531,12 @@ lru-cache@^6.0.0:
   dependencies:
     yallist "^4.0.0"
 
-magic-string@^0.30.0:
-  version "0.30.0"
-  resolved "http://47.110.251.215:9000/magic-string/-/magic-string-0.30.0.tgz#fd58a4748c5c4547338a424e90fa5dd17f4de529"
-  integrity sha512-LA+31JYDJLs82r2ScLrlz1GjSgu66ZV518eyWT+S8VhyQn/JL0u9MeBOvQMGYiPk1DBiSN9DDMOcXvigJZaViQ==
+magic-string@^0.30.5:
+  version "0.30.5"
+  resolved "http://47.110.251.215:9000/magic-string/-/magic-string-0.30.5.tgz#1994d980bd1c8835dc6e78db7cbd4ae4f24746f9"
+  integrity sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA==
   dependencies:
-    "@jridgewell/sourcemap-codec" "^1.4.13"
+    "@jridgewell/sourcemap-codec" "^1.4.15"
 
 mdn-data@2.0.28:
   version "2.0.28"
@@ -1706,10 +1733,10 @@ pify@^2.3.0:
   resolved "http://47.110.251.215:9000/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
   integrity sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==
 
-pinia@^2.1.4:
-  version "2.1.6"
-  resolved "http://47.110.251.215:9000/pinia/-/pinia-2.1.6.tgz#e88959f14b61c4debd9c42d0c9944e2875cbe0fa"
-  integrity sha512-bIU6QuE5qZviMmct5XwCesXelb5VavdOWKWaB17ggk++NUwQWWbP5YnsONTk3b752QkW9sACiR81rorpeOMSvQ==
+pinia@^2.1.7:
+  version "2.1.7"
+  resolved "http://47.110.251.215:9000/pinia/-/pinia-2.1.7.tgz#4cf5420d9324ca00b7b4984d3fbf693222115bbc"
+  integrity sha512-+C2AHFtcFqjPih0zpYuvof37SFxMQ7OEG2zV9jRI12i9BOy3YQVAHwdKtyyc8pDcDyIc33WCIsZaCFWU7WWxGQ==
   dependencies:
     "@vue/devtools-api" "^6.5.0"
     vue-demi ">=0.14.5"
@@ -1959,7 +1986,7 @@ postcss-value-parser@^4.0.0, postcss-value-parser@^4.2.0:
   resolved "http://47.110.251.215:9000/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514"
   integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==
 
-postcss@^8.1.10, postcss@^8.4.23:
+postcss@^8.4.23:
   version "8.4.24"
   resolved "http://47.110.251.215:9000/postcss/-/postcss-8.4.24.tgz#f714dba9b2284be3cc07dbd2fc57ee4dc972d2df"
   integrity sha512-M0RzbcI0sO/XJNucsGjvWU9ERWxb/ytp1w6dKtxTKgixdtQDq4rmx/g8W1hnaheq9jgwL/oyEdH5Bc4WwJKMqg==
@@ -1968,7 +1995,7 @@ postcss@^8.1.10, postcss@^8.4.23:
     picocolors "^1.0.0"
     source-map-js "^1.0.2"
 
-postcss@^8.4.26, postcss@^8.4.27:
+postcss@^8.4.27:
   version "8.4.30"
   resolved "http://47.110.251.215:9000/postcss/-/postcss-8.4.30.tgz#0e0648d551a606ef2192a26da4cabafcc09c1aa7"
   integrity sha512-7ZEao1g4kd68l97aWG/etQKPKq07us0ieSZ2TnFDk11i0ZfDW2AwKHYU8qv4MZKqN2fdBfg+7q0ES06UA73C1g==
@@ -1977,6 +2004,15 @@ postcss@^8.4.26, postcss@^8.4.27:
     picocolors "^1.0.0"
     source-map-js "^1.0.2"
 
+postcss@^8.4.31:
+  version "8.4.31"
+  resolved "http://47.110.251.215:9000/postcss/-/postcss-8.4.31.tgz#92b451050a9f914da6755af352bdc0192508656d"
+  integrity sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==
+  dependencies:
+    nanoid "^3.3.6"
+    picocolors "^1.0.0"
+    source-map-js "^1.0.2"
+
 prelude-ls@^1.2.1:
   version "1.2.1"
   resolved "http://47.110.251.215:9000/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
@@ -2100,10 +2136,10 @@ safe-buffer@~5.2.0:
   resolved "http://47.110.251.215:9000/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
   integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
 
-sass@^1.63.6:
-  version "1.68.0"
-  resolved "http://47.110.251.215:9000/sass/-/sass-1.68.0.tgz#0034b0cc9a50248b7d1702ac166fd25990023669"
-  integrity sha512-Lmj9lM/fef0nQswm1J2HJcEsBUba4wgNx2fea6yJHODREoMFnwRpZydBnX/RjyXw2REIwdkbqE4hrTo4qfDBUA==
+sass@^1.69.5:
+  version "1.69.5"
+  resolved "http://47.110.251.215:9000/sass/-/sass-1.69.5.tgz#23e18d1c757a35f2e52cc81871060b9ad653dfde"
+  integrity sha512-qg2+UCJibLr2LCVOt3OlPhr/dqVHWOa9XtZf2OjbLs/T4VPSJ00udtgJxH3neXZm+QqX8B+3cU7RaLqp1iVfcQ==
   dependencies:
     chokidar ">=3.0.0 <4.0.0"
     immutable "^4.0.0"
@@ -2232,20 +2268,20 @@ svgo@^3.0.2:
     csso "^5.0.5"
     picocolors "^1.0.0"
 
-tailwindcss@3.3.3:
-  version "3.3.3"
-  resolved "http://47.110.251.215:9000/tailwindcss/-/tailwindcss-3.3.3.tgz#90da807393a2859189e48e9e7000e6880a736daf"
-  integrity sha512-A0KgSkef7eE4Mf+nKJ83i75TMyq8HqY3qmFIJSWy8bNt0v1lG7jUcpGpoTFxAwYcWOphcTBLPPJg+bDfhDf52w==
+tailwindcss@3.3.5:
+  version "3.3.5"
+  resolved "http://47.110.251.215:9000/tailwindcss/-/tailwindcss-3.3.5.tgz#22a59e2fbe0ecb6660809d9cc5f3976b077be3b8"
+  integrity sha512-5SEZU4J7pxZgSkv7FP1zY8i2TIAOooNZ1e/OGtxIEv6GltpoiXUqWvLy89+a10qYTB1N5Ifkuw9lqQkN9sscvA==
   dependencies:
     "@alloc/quick-lru" "^5.2.0"
     arg "^5.0.2"
     chokidar "^3.5.3"
     didyoumean "^1.2.2"
     dlv "^1.1.3"
-    fast-glob "^3.2.12"
+    fast-glob "^3.3.0"
     glob-parent "^6.0.2"
     is-glob "^4.0.3"
-    jiti "^1.18.2"
+    jiti "^1.19.1"
     lilconfig "^2.1.0"
     micromatch "^4.0.5"
     normalize-path "^3.0.0"
@@ -2337,10 +2373,10 @@ util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1:
   resolved "http://47.110.251.215:9000/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
   integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==
 
-vite@^4.4.4:
-  version "4.4.9"
-  resolved "http://47.110.251.215:9000/vite/-/vite-4.4.9.tgz#1402423f1a2f8d66fd8d15e351127c7236d29d3d"
-  integrity sha512-2mbUn2LlUmNASWwSCNSJ/EG2HuSRTnVNaydp6vMCm5VIqJsjMfbIWtbH2kDuwUVW5mMUKKZvGPX/rqeqVvv1XA==
+vite@^4.5.0:
+  version "4.5.0"
+  resolved "http://47.110.251.215:9000/vite/-/vite-4.5.0.tgz#ec406295b4167ac3bc23e26f9c8ff559287cff26"
+  integrity sha512-ulr8rNLA6rkyFAlVWw2q5YJ91v098AFQ2R0PRFwPzREXOUJQPtFUG0t+/ZikhaOCDqFoDhN6/v8Sq0o4araFAw==
   dependencies:
     esbuild "^0.18.10"
     postcss "^8.4.27"
@@ -2366,23 +2402,23 @@ vue-eslint-parser@^9.3.1:
     lodash "^4.17.21"
     semver "^7.3.6"
 
-vue-router@^4.2.4:
-  version "4.2.4"
-  resolved "http://47.110.251.215:9000/vue-router/-/vue-router-4.2.4.tgz#382467a7e2923e6a85f015d081e1508052c191b9"
-  integrity sha512-9PISkmaCO02OzPVOMq2w82ilty6+xJmQrarYZDkjZBfl4RvYAlt4PKnEX21oW4KTtWfa9OuO/b3qk1Od3AEdCQ==
+vue-router@^4.2.5:
+  version "4.2.5"
+  resolved "http://47.110.251.215:9000/vue-router/-/vue-router-4.2.5.tgz#b9e3e08f1bd9ea363fdd173032620bc50cf0e98a"
+  integrity sha512-DIUpKcyg4+PTQKfFPX88UWhlagBEBEfJ5A8XDXRJLUnZOvcpMF8o/dnL90vpVkGaPbjvXazV/rC1qBKrZlFugw==
   dependencies:
     "@vue/devtools-api" "^6.5.0"
 
-vue@3.3.4, vue@^3.3.4:
-  version "3.3.4"
-  resolved "http://47.110.251.215:9000/vue/-/vue-3.3.4.tgz#8ed945d3873667df1d0fcf3b2463ada028f88bd6"
-  integrity sha512-VTyEYn3yvIeY1Py0WaYGZsXnz3y5UnGi62GjVEqvEGPl6nxbOrCXbVOTQWBEJUqAyTUk2uJ5JLVnYJ6ZzGbrSw==
+vue@3.3.7, vue@^3.3.7:
+  version "3.3.7"
+  resolved "http://47.110.251.215:9000/vue/-/vue-3.3.7.tgz#972a218682443a3819d121261b2bff914417f4f0"
+  integrity sha512-YEMDia1ZTv1TeBbnu6VybatmSteGOS3A3YgfINOfraCbf85wdKHzscD6HSS/vB4GAtI7sa1XPX7HcQaJ1l24zA==
   dependencies:
-    "@vue/compiler-dom" "3.3.4"
-    "@vue/compiler-sfc" "3.3.4"
-    "@vue/runtime-dom" "3.3.4"
-    "@vue/server-renderer" "3.3.4"
-    "@vue/shared" "3.3.4"
+    "@vue/compiler-dom" "3.3.7"
+    "@vue/compiler-sfc" "3.3.7"
+    "@vue/runtime-dom" "3.3.7"
+    "@vue/server-renderer" "3.3.7"
+    "@vue/shared" "3.3.7"
 
 vuedraggable@^2.24.3:
   version "2.24.3"