|
@@ -1,116 +1,76 @@
|
|
<template>
|
|
<template>
|
|
- <t-layout class="h-full app-layout">
|
|
|
|
- <!-- <t-header class="layout-header">
|
|
|
|
- <div class="header-wrap flex items-center">页头</div>
|
|
|
|
- </t-header> -->
|
|
|
|
- <t-aside
|
|
|
|
- :width="
|
|
|
|
- (appStore.menuCollapse ? appStore.collapseWidth : appStore.menuWidth) +
|
|
|
|
- 'px'
|
|
|
|
- "
|
|
|
|
- >
|
|
|
|
- <!-- <div class="logo-box flex items-center justify-center">
|
|
|
|
- <img src="../assets/logo.svg" />
|
|
|
|
- </div> -->
|
|
|
|
- <left-menu></left-menu>
|
|
|
|
- </t-aside>
|
|
|
|
- <t-layout class="right-view">
|
|
|
|
- <t-header class="layout-header">
|
|
|
|
- <div class="h-full header-wrap flex items-center justify-between">
|
|
|
|
- <div class="flex-1">
|
|
|
|
- <t-head-menu
|
|
|
|
- style="height: 55px"
|
|
|
|
- :value="userStore.curPageModule"
|
|
|
|
- theme="light"
|
|
|
|
- @change="moduleChange"
|
|
|
|
|
|
+ <t-layout class="app-layout">
|
|
|
|
+ <t-aside width="314px" class="app-layout-side">
|
|
|
|
+ <t-layout class="app-layout-side-body" direction="horizontal">
|
|
|
|
+ <t-aside class="app-menu" width="82px">
|
|
|
|
+ <div class="app-menu-list">
|
|
|
|
+ <div class="app-menu-logo">
|
|
|
|
+ <img src="@/assets/imgs/menu-logo.png" alt="logo" />
|
|
|
|
+ </div>
|
|
|
|
+ <div
|
|
|
|
+ v-for="item in userStore.headerMenus"
|
|
|
|
+ :key="item.name"
|
|
|
|
+ :class="[
|
|
|
|
+ 'app-menu-item',
|
|
|
|
+ { 'is-actice': userStore.curPageModule === item.name },
|
|
|
|
+ ]"
|
|
|
|
+ @click="moduleChange(item.name)"
|
|
>
|
|
>
|
|
- <t-menu-item
|
|
|
|
- :value="item.name"
|
|
|
|
- v-for="item in userStore.headerMenus"
|
|
|
|
- :key="item.name"
|
|
|
|
- >
|
|
|
|
- {{ item.meta?.title }}
|
|
|
|
- </t-menu-item>
|
|
|
|
- </t-head-menu>
|
|
|
|
|
|
+ <svg-icon
|
|
|
|
+ prefix="icon-icon-fill"
|
|
|
|
+ :name="item.meta.icon"
|
|
|
|
+ :color="
|
|
|
|
+ userStore.curPageModule === item.name ? '#165DFF' : undefined
|
|
|
|
+ "
|
|
|
|
+ ></svg-icon>
|
|
|
|
+ <p>{{ item.meta.title }}</p>
|
|
|
|
+ </div>
|
|
</div>
|
|
</div>
|
|
- <div class="header-right flex items-center">
|
|
|
|
- <t-dropdown
|
|
|
|
- class="m-r-20px"
|
|
|
|
- trigger="hover"
|
|
|
|
- placement="bottom"
|
|
|
|
- @click="colorChoose"
|
|
|
|
- >
|
|
|
|
- <t-button theme="default" variant="outline" shape="square">
|
|
|
|
- <t-icon
|
|
|
|
- name="palette"
|
|
|
|
- size="26"
|
|
|
|
- color="#fff"
|
|
|
|
- :style="{ background: themeColor, borderRadius: '2px' }"
|
|
|
|
- /></t-button>
|
|
|
|
- <t-dropdown-menu>
|
|
|
|
- <t-dropdown-item
|
|
|
|
- v-for="item in colorOptions"
|
|
|
|
- :key="item.value"
|
|
|
|
- :value="item.value"
|
|
|
|
- >
|
|
|
|
- <div
|
|
|
|
- class="color-grid"
|
|
|
|
- :class="{ 'active-color-grid': themeColor === item.value }"
|
|
|
|
- >
|
|
|
|
- <div
|
|
|
|
- class="color-grid-center"
|
|
|
|
- :style="{
|
|
|
|
- backgroundColor: item.value,
|
|
|
|
- width: '100%',
|
|
|
|
- height: '100%',
|
|
|
|
- borderRadius: '2px',
|
|
|
|
- }"
|
|
|
|
- ></div>
|
|
|
|
- </div>
|
|
|
|
- </t-dropdown-item>
|
|
|
|
- </t-dropdown-menu>
|
|
|
|
- </t-dropdown>
|
|
|
|
|
|
+ <div class="app-menu-footer"></div>
|
|
|
|
+ </t-aside>
|
|
|
|
+ <t-content class="app-submenu">
|
|
|
|
+ <left-menu class="app-submenu-body"></left-menu>
|
|
|
|
+ <div class="app-submenu-footer">
|
|
<t-dropdown
|
|
<t-dropdown
|
|
trigger="hover"
|
|
trigger="hover"
|
|
:options="userOptions"
|
|
:options="userOptions"
|
|
@click="clickHandler"
|
|
@click="clickHandler"
|
|
>
|
|
>
|
|
- <div class="flex items-center cursor-pointer">
|
|
|
|
- <div class="head-img-box flex justify-center items-center">
|
|
|
|
- <img src="../assets/imgs/user_head.png" />
|
|
|
|
|
|
+ <div class="app-submenu-user">
|
|
|
|
+ <div class="app-submenu-user-content">
|
|
|
|
+ <svg-icon name="user-circle"></svg-icon>
|
|
|
|
+ <span class="real-name">{{ userStore.user?.realName }}</span>
|
|
|
|
+ <span v-if="userStore.user?.mobileNumber" class="real-name">{{
|
|
|
|
+ userStore.user?.mobileNumber
|
|
|
|
+ }}</span>
|
|
</div>
|
|
</div>
|
|
- <span class="real-name">{{ userStore.user?.realName }}</span>
|
|
|
|
<ChevronDownIcon size="16px" />
|
|
<ChevronDownIcon size="16px" />
|
|
</div>
|
|
</div>
|
|
</t-dropdown>
|
|
</t-dropdown>
|
|
</div>
|
|
</div>
|
|
- </div>
|
|
|
|
- </t-header>
|
|
|
|
- <t-content class="layout-content overflow-auto">
|
|
|
|
- <router-view v-slot="{ Component }">
|
|
|
|
- <transition name="fade-slide" mode="out-in" appear>
|
|
|
|
- <component :is="Component" />
|
|
|
|
- </transition>
|
|
|
|
- </router-view>
|
|
|
|
- </t-content>
|
|
|
|
- </t-layout>
|
|
|
|
|
|
+ </t-content>
|
|
|
|
+ </t-layout>
|
|
|
|
+ </t-aside>
|
|
|
|
+ <t-content class="layout-content overflow-au to">
|
|
|
|
+ <router-view v-slot="{ Component }">
|
|
|
|
+ <transition name="fade-slide" mode="out-in" appear>
|
|
|
|
+ <component :is="Component" />
|
|
|
|
+ </transition>
|
|
|
|
+ </router-view>
|
|
|
|
+ </t-content>
|
|
</t-layout>
|
|
</t-layout>
|
|
</template>
|
|
</template>
|
|
|
|
|
|
<script setup name="Layout" lang="jsx">
|
|
<script setup name="Layout" lang="jsx">
|
|
import { ref, onMounted } from 'vue';
|
|
import { ref, onMounted } from 'vue';
|
|
-import { useAppStore, useUserStore } from '@/store';
|
|
|
|
|
|
+import { useUserStore } from '@/store';
|
|
import { useRouter, useRoute } from 'vue-router';
|
|
import { useRouter, useRoute } from 'vue-router';
|
|
import LeftMenu from './left-menu.vue';
|
|
import LeftMenu from './left-menu.vue';
|
|
-import { Color } from 'tvision-color';
|
|
|
|
-import { generateColorMap, insertThemeStylesheet } from '@/config/color';
|
|
|
|
import { moduleMap } from '@/router/asyncRoutes';
|
|
import { moduleMap } from '@/router/asyncRoutes';
|
|
-import { ChevronDownIcon, UserIcon } from 'tdesign-icons-vue-next';
|
|
|
|
-import { clear, cookie } from '@/utils/tool';
|
|
|
|
|
|
+import { ChevronDownIcon } from 'tdesign-icons-vue-next';
|
|
|
|
|
|
const router = useRouter();
|
|
const router = useRouter();
|
|
const route = useRoute();
|
|
const route = useRoute();
|
|
-const appStore = useAppStore();
|
|
|
|
const userStore = useUserStore();
|
|
const userStore = useUserStore();
|
|
const moduleChange = (name) => {
|
|
const moduleChange = (name) => {
|
|
userStore.setCurPageModule(name);
|
|
userStore.setCurPageModule(name);
|
|
@@ -121,40 +81,9 @@ const setModuleByPath = () => {
|
|
let curModuleName = moduleMap[firstPath];
|
|
let curModuleName = moduleMap[firstPath];
|
|
userStore.setCurPageModule(curModuleName);
|
|
userStore.setCurPageModule(curModuleName);
|
|
};
|
|
};
|
|
-const themeColor = ref(cookie.get('themeColor'));
|
|
|
|
onMounted(() => {
|
|
onMounted(() => {
|
|
setModuleByPath();
|
|
setModuleByPath();
|
|
- setTheme(themeColor.value || '#0052d9');
|
|
|
|
});
|
|
});
|
|
-const colorOptions = ref([
|
|
|
|
- {
|
|
|
|
- value: '#0052d9',
|
|
|
|
- },
|
|
|
|
- {
|
|
|
|
- value: '#0091ff',
|
|
|
|
- },
|
|
|
|
- {
|
|
|
|
- value: '#35c1db',
|
|
|
|
- },
|
|
|
|
- {
|
|
|
|
- value: '#5dbe8a',
|
|
|
|
- },
|
|
|
|
- {
|
|
|
|
- value: '#f4b84a',
|
|
|
|
- },
|
|
|
|
- {
|
|
|
|
- value: '#f29e55',
|
|
|
|
- },
|
|
|
|
- {
|
|
|
|
- value: '#ac6ef6',
|
|
|
|
- },
|
|
|
|
- {
|
|
|
|
- value: '#7969f3',
|
|
|
|
- },
|
|
|
|
- {
|
|
|
|
- value: '#e65857',
|
|
|
|
- },
|
|
|
|
-]);
|
|
|
|
const userOptions = ref([
|
|
const userOptions = ref([
|
|
{ content: '修改密码', value: '1' },
|
|
{ content: '修改密码', value: '1' },
|
|
{ content: '退出', value: '2' },
|
|
{ content: '退出', value: '2' },
|
|
@@ -166,71 +95,127 @@ const clickHandler = (data) => {
|
|
userStore.logout();
|
|
userStore.logout();
|
|
}
|
|
}
|
|
};
|
|
};
|
|
-const setTheme = (hex) => {
|
|
|
|
- const newPalette = Color.getPaletteByGradation({
|
|
|
|
- colors: [hex],
|
|
|
|
- step: 10,
|
|
|
|
- })[0];
|
|
|
|
- const colorMap = generateColorMap(hex, newPalette);
|
|
|
|
- insertThemeStylesheet(hex, colorMap);
|
|
|
|
- cookie.set('themeColor', hex);
|
|
|
|
- themeColor.value = hex;
|
|
|
|
-};
|
|
|
|
-const colorChoose = (data) => {
|
|
|
|
- const hex = data.value;
|
|
|
|
- setTheme(hex);
|
|
|
|
-};
|
|
|
|
</script>
|
|
</script>
|
|
-<style lang="less">
|
|
|
|
-.color-grid {
|
|
|
|
- margin-left: auto;
|
|
|
|
- margin-right: auto;
|
|
|
|
- width: 54px;
|
|
|
|
- height: 24px;
|
|
|
|
- border-radius: 2px;
|
|
|
|
- padding: 2px;
|
|
|
|
- border: 1px solid transparent;
|
|
|
|
- &.active-color-grid {
|
|
|
|
- border-color: #ccc;
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-</style>
|
|
|
|
|
|
+
|
|
<style lang="less" scoped>
|
|
<style lang="less" scoped>
|
|
.app-layout {
|
|
.app-layout {
|
|
- .right-view {
|
|
|
|
- overflow: auto;
|
|
|
|
|
|
+ background-color: #f2f3f5;
|
|
|
|
+ height: 100%;
|
|
|
|
+
|
|
|
|
+ &-side {
|
|
|
|
+ height: 100%;
|
|
}
|
|
}
|
|
- .t-layout__sider {
|
|
|
|
- //重写过渡时长,让其余menu的折叠动画保持同步
|
|
|
|
- transition: all 0.28s cubic-bezier(0.645, 0.045, 0.355, 1);
|
|
|
|
|
|
+
|
|
|
|
+ &-side-body {
|
|
|
|
+ height: 100%;
|
|
}
|
|
}
|
|
- .layout-header {
|
|
|
|
- border-bottom: 1px solid #eee;
|
|
|
|
- .header-wrap {
|
|
|
|
- padding: 0 10px;
|
|
|
|
- padding-right: 20px;
|
|
|
|
- .t-head-menu .t-menu__item {
|
|
|
|
- height: 44px;
|
|
|
|
|
|
+
|
|
|
|
+ .layout-content {
|
|
|
|
+ flex: 1;
|
|
|
|
+ }
|
|
|
|
+ .app-menu {
|
|
|
|
+ background-color: #f2f3f5;
|
|
|
|
+
|
|
|
|
+ &-list {
|
|
|
|
+ padding: 16px 8px 40px;
|
|
|
|
+ }
|
|
|
|
+ &-logo {
|
|
|
|
+ height: 52px;
|
|
|
|
+ padding: 12px 8px;
|
|
|
|
+ }
|
|
|
|
+ &-item {
|
|
|
|
+ margin: 4px 0;
|
|
|
|
+ padding: 8px 0;
|
|
|
|
+ text-align: center;
|
|
|
|
+ border-radius: 4px;
|
|
|
|
+ color: #4e5969;
|
|
|
|
+
|
|
|
|
+ cursor: pointer;
|
|
|
|
+ &:hover {
|
|
|
|
+ background-color: #e5e6eb;
|
|
|
|
+ }
|
|
|
|
+ &.is-actice {
|
|
|
|
+ background-color: #e5e6eb;
|
|
|
|
+ color: #165dff;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ > i {
|
|
|
|
+ display: inline-block;
|
|
|
|
+ vertical-align: middle;
|
|
|
|
+ width: 20px;
|
|
|
|
+ height: 20px;
|
|
|
|
+ }
|
|
|
|
+ > p {
|
|
|
|
+ margin: 0;
|
|
|
|
+ line-height: 18px;
|
|
|
|
+ font-size: 12px;
|
|
}
|
|
}
|
|
- .real-name {
|
|
|
|
- color: @light-text-color;
|
|
|
|
|
|
+
|
|
|
|
+ .svg-icon {
|
|
|
|
+ display: block;
|
|
|
|
+ margin: 0 auto 3px;
|
|
}
|
|
}
|
|
- .head-img-box {
|
|
|
|
- width: 32px;
|
|
|
|
- height: 32px;
|
|
|
|
- border-radius: 16px;
|
|
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ &-footer {
|
|
|
|
+ position: absolute;
|
|
|
|
+ height: 24px;
|
|
|
|
+ border-radius: 3px;
|
|
|
|
+ padding: 8px;
|
|
|
|
+ background-color: #f2f3f5;
|
|
|
|
+ z-index: 9;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ .app-submenu {
|
|
|
|
+ background-color: #fff;
|
|
|
|
+ padding-bottom: 78px;
|
|
|
|
+ position: relative;
|
|
|
|
+ border-right: 1px solid #e5e5e5;
|
|
|
|
+ color: #262626;
|
|
|
|
+
|
|
|
|
+ &-footer {
|
|
|
|
+ position: absolute;
|
|
|
|
+ width: 100%;
|
|
|
|
+ bottom: 0;
|
|
|
|
+ left: 0;
|
|
|
|
+ padding: 16px 8px;
|
|
|
|
+ background-color: #fff;
|
|
|
|
+ z-index: 9;
|
|
|
|
+ }
|
|
|
|
+ &-user {
|
|
|
|
+ padding: 8px 16px;
|
|
|
|
+ display: flex;
|
|
|
|
+ align-items: center;
|
|
|
|
+ justify-content: space-between;
|
|
|
|
+ border-radius: 4px;
|
|
|
|
+ cursor: pointer;
|
|
|
|
+
|
|
|
|
+ &:hover {
|
|
|
|
+ background-color: #f2f3f5;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ &-content {
|
|
|
|
+ line-height: 20px;
|
|
overflow: hidden;
|
|
overflow: hidden;
|
|
- margin-right: 5px;
|
|
|
|
|
|
+ white-space: nowrap;
|
|
|
|
+ text-overflow: ellipsis;
|
|
|
|
+ flex-grow: 2;
|
|
|
|
|
|
- img {
|
|
|
|
- width: 100%;
|
|
|
|
- height: 100%;
|
|
|
|
|
|
+ span {
|
|
|
|
+ margin-left: 8px;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- }
|
|
|
|
- .layout-content {
|
|
|
|
- flex: 1;
|
|
|
|
|
|
+ :deep(.t-menu__item .t-icon) {
|
|
|
|
+ width: 18px;
|
|
|
|
+ height: 18px;
|
|
|
|
+ }
|
|
|
|
+ :deep(.t-menu__item) {
|
|
|
|
+ color: #262626;
|
|
|
|
+ }
|
|
|
|
+ :deep(.t-menu__item.t-is-disabled) {
|
|
|
|
+ color: rgb(140, 140, 140);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
</style>
|
|
</style>
|