-
-
-
- {{ item.meta?.title }}
-
-
-
+
+
+
+ {{ item.meta?.title }}
+
+
diff --git a/src/layout/components/setting/index.vue b/src/layout/components/setting/index.vue
index b7e3544..6543f65 100644
--- a/src/layout/components/setting/index.vue
+++ b/src/layout/components/setting/index.vue
@@ -218,7 +218,6 @@ watch($storage, ({ layout }) => {
});
onBeforeMount(() => {
- dataThemeChange();
/* 初始化项目配置 */
nextTick(() => {
settings.greyVal &&
diff --git a/src/layout/components/sidebar/horizontal.vue b/src/layout/components/sidebar/horizontal.vue
index bf3f14c..f3e5b9b 100644
--- a/src/layout/components/sidebar/horizontal.vue
+++ b/src/layout/components/sidebar/horizontal.vue
@@ -19,6 +19,7 @@ const {
onPanel,
menuSelect,
username,
+ userAvatar,
avatarsStyle
} = useNav();
@@ -66,10 +67,7 @@ watch(
-
+
{{ username }}
diff --git a/src/layout/components/sidebar/logo.vue b/src/layout/components/sidebar/logo.vue
index 78a55be..9dec792 100644
--- a/src/layout/components/sidebar/logo.vue
+++ b/src/layout/components/sidebar/logo.vue
@@ -7,7 +7,6 @@ const props = defineProps({
});
const { title } = useNav();
-const topPath = getTopMenu().path;
@@ -18,7 +17,7 @@ const topPath = getTopMenu().path;
key="props.collapse"
:title="title"
class="sidebar-logo-link"
- :to="topPath"
+ :to="getTopMenu()?.path ?? '/'"
>
@@ -28,7 +27,7 @@ const topPath = getTopMenu().path;
key="expand"
:title="title"
class="sidebar-logo-link"
- :to="topPath"
+ :to="getTopMenu()?.path ?? '/'"
>
diff --git a/src/layout/components/sidebar/mixNav.vue b/src/layout/components/sidebar/mixNav.vue
index a45cf56..777e7df 100644
--- a/src/layout/components/sidebar/mixNav.vue
+++ b/src/layout/components/sidebar/mixNav.vue
@@ -22,6 +22,7 @@ const {
menuSelect,
resolvePath,
username,
+ userAvatar,
getDivStyle,
avatarsStyle
} = useNav();
@@ -97,10 +98,7 @@ watch(
-
+
{{ username }}
diff --git a/src/layout/components/tag/index.vue b/src/layout/components/tag/index.vue
index d3ccd14..4adc08a 100644
--- a/src/layout/components/tag/index.vue
+++ b/src/layout/components/tag/index.vue
@@ -48,7 +48,7 @@ const tabDom = ref();
const containerDom = ref();
const scrollbarDom = ref();
const isShowArrow = ref(false);
-const topPath = getTopMenu().path;
+const topPath = getTopMenu()?.path;
const { VITE_HIDE_HOME } = import.meta.env;
const { isFullscreen, toggle } = useFullscreen();
diff --git a/src/layout/hooks/useNav.ts b/src/layout/hooks/useNav.ts
index ed14d8e..c60c9ba 100644
--- a/src/layout/hooks/useNav.ts
+++ b/src/layout/hooks/useNav.ts
@@ -2,6 +2,7 @@ import { storeToRefs } from "pinia";
import { getConfig } from "@/config";
import { emitter } from "@/utils/mitt";
import { routeMetaType } from "../types";
+import userAvatar from "@/assets/user.jpg";
import { getTopMenu } from "@/router/utils";
import { useGlobal } from "@pureadmin/utils";
import { computed, CSSProperties } from "vue";
@@ -70,7 +71,7 @@ export function useNav() {
}
function backTopMenu() {
- router.push(getTopMenu().path);
+ router.push(getTopMenu()?.path);
}
function onPanel() {
@@ -150,6 +151,7 @@ export function useNav() {
isCollapse,
pureApp,
username,
+ userAvatar,
avatarsStyle,
tooltipEffect
};
diff --git a/src/layout/index.vue b/src/layout/index.vue
index f8ac54e..9103f4b 100644
--- a/src/layout/index.vue
+++ b/src/layout/index.vue
@@ -8,7 +8,15 @@ import { useLayout } from "./hooks/useLayout";
import { useAppStoreHook } from "@/store/modules/app";
import { useSettingStoreHook } from "@/store/modules/settings";
import { deviceDetection, useDark, useGlobal } from "@pureadmin/utils";
-import { h, reactive, computed, onMounted, defineComponent } from "vue";
+import { useDataThemeChange } from "@/layout/hooks/useDataThemeChange";
+import {
+ h,
+ reactive,
+ computed,
+ onMounted,
+ onBeforeMount,
+ defineComponent
+} from "vue";
import navbar from "./components/navbar.vue";
import tag from "./components/tag/index.vue";
@@ -88,11 +96,12 @@ emitter.on("resize", ({ detail }) => {
toggle("desktop", false);
isAutoCloseSidebar = false;
}
- } else if (width > 990) {
- if (!set.sidebar.isClickCollapse) {
- toggle("desktop", true);
- isAutoCloseSidebar = true;
- }
+ } else if (width > 990 && !set.sidebar.isClickCollapse) {
+ toggle("desktop", true);
+ isAutoCloseSidebar = true;
+ } else {
+ toggle("desktop", false);
+ isAutoCloseSidebar = false;
}
});
@@ -102,6 +111,10 @@ onMounted(() => {
}
});
+onBeforeMount(() => {
+ useDataThemeChange().dataThemeChange();
+});
+
const layoutHeader = defineComponent({
render() {
return h(
diff --git a/src/router/index.ts b/src/router/index.ts
index cc375ff..1e69915 100644
--- a/src/router/index.ts
+++ b/src/router/index.ts
@@ -22,7 +22,7 @@ import {
formatFlatteningRoutes
} from "./utils";
import { buildHierarchyTree } from "@/utils/tree";
-import { isUrl, openLink, storageSession } from "@pureadmin/utils";
+import { isUrl, openLink, storageSession, isAllEmpty } from "@pureadmin/utils";
import remainingRouter from "./modules/remaining";
@@ -46,13 +46,13 @@ Object.keys(modules).forEach(key => {
/** 导出处理后的静态路由(三级及以上的路由全部拍成二级) */
export const constantRoutes: Array = formatTwoStageRoutes(
- formatFlatteningRoutes(buildHierarchyTree(ascending(routes)))
+ formatFlatteningRoutes(buildHierarchyTree(ascending(routes.flat(Infinity))))
);
/** 用于渲染菜单,保持原始层级 */
-export const constantMenus: Array = ascending(routes).concat(
- ...remainingRouter
-);
+export const constantMenus: Array = ascending(
+ routes.flat(Infinity)
+).concat(...remainingRouter);
/** 不参与菜单的路由 */
export const remainingPaths = Object.keys(remainingRouter).map(v => {
@@ -86,7 +86,9 @@ export function resetRouter() {
if (name && router.hasRoute(name) && meta?.backstage) {
router.removeRoute(name);
router.options.routes = formatTwoStageRoutes(
- formatFlatteningRoutes(buildHierarchyTree(ascending(routes)))
+ formatFlatteningRoutes(
+ buildHierarchyTree(ascending(routes.flat(Infinity)))
+ )
);
}
});
@@ -154,11 +156,22 @@ router.beforeEach((to: toRouteType, _from, next) => {
getTopMenu(true);
// query、params模式路由传参数的标签页不在此处处理
if (route && route.meta?.title) {
- useMultiTagsStoreHook().handleTags("push", {
- path: route.path,
- name: route.name,
- meta: route.meta
- });
+ if (isAllEmpty(route.parentId) && route.meta?.backstage) {
+ // 此处为动态顶级路由(目录)
+ const { path, name, meta } = route.children[0];
+ useMultiTagsStoreHook().handleTags("push", {
+ path,
+ name,
+ meta
+ });
+ } else {
+ const { path, name, meta } = route;
+ useMultiTagsStoreHook().handleTags("push", {
+ path,
+ name,
+ meta
+ });
+ }
}
}
router.push(to.fullPath);
diff --git a/src/style/dark.scss b/src/style/dark.scss
index ec1da05..5954983 100644
--- a/src/style/dark.scss
+++ b/src/style/dark.scss
@@ -79,6 +79,10 @@ html.dark {
&:hover {
color: rgb(255 255 255 / 85%) !important;
background-color: rgb(255 255 255 / 12%);
+
+ .pure-dialog-svg {
+ color: rgb(255 255 255 / 85%) !important;
+ }
}
}
}
@@ -103,4 +107,35 @@ html.dark {
}
}
}
+
+ /* 自定义菜单搜索样式 */
+ .pure-search-dialog {
+ .el-dialog__footer {
+ box-shadow: 0 -1px 0 0 #555a64, 0 -3px 6px 0 rgb(69 98 155 / 12%);
+ }
+
+ .search-footer {
+ .search-footer-item {
+ color: rgb(235 235 235 / 60%);
+
+ .icon {
+ box-shadow: none;
+ }
+ }
+ }
+ }
+
+ /* ReSegmented 组件 */
+ .pure-segmented {
+ color: rgb(255 255 255 / 65%);
+ background-color: #000;
+
+ .pure-segmented-item-selected {
+ background-color: #1f1f1f;
+ }
+
+ .pure-segmented-item-disabled {
+ color: rgb(255 255 255 / 25%);
+ }
+ }
}
diff --git a/src/style/element-plus.scss b/src/style/element-plus.scss
index c3944e8..59b0c5f 100644
--- a/src/style/element-plus.scss
+++ b/src/style/element-plus.scss
@@ -69,6 +69,19 @@
}
}
+.pure-dialog {
+ .pure-dialog-svg {
+ color: var(--el-color-info);
+ }
+
+ .el-dialog__headerbtn {
+ top: 20px;
+ right: 14px;
+ width: 24px;
+ height: 24px;
+ }
+}
+
/* 全局覆盖element-plus的el-dialog、el-drawer、el-message-box、el-notification组件右上角关闭图标的样式,表现更鲜明 */
.el-dialog__headerbtn,
.el-message-box__headerbtn {
@@ -94,6 +107,10 @@
color: rgb(0 0 0 / 88%) !important;
text-decoration: none;
background-color: rgb(0 0 0 / 6%);
+
+ .pure-dialog-svg {
+ color: rgb(0 0 0 / 88%) !important;
+ }
}
}
}
@@ -131,3 +148,24 @@
}
}
}
+
+/* 自定义菜单搜索样式 */
+.pure-search-dialog {
+ .el-dialog__header {
+ display: none;
+ }
+
+ .el-dialog__body {
+ padding-top: 12px;
+ padding-bottom: 0;
+ }
+
+ .el-input__inner {
+ font-size: 1.2em;
+ }
+
+ .el-dialog__footer {
+ padding-bottom: 10px;
+ box-shadow: 0 -1px 0 0 #e0e3e8, 0 -3px 6px 0 rgb(69 98 155 / 12%);
+ }
+}
diff --git a/src/utils/http/index.ts b/src/utils/http/index.ts
index 7b7304b..3a39993 100644
--- a/src/utils/http/index.ts
+++ b/src/utils/http/index.ts
@@ -63,7 +63,7 @@ class PureHttp {
async (config: PureHttpRequestConfig): Promise => {
// 开启进度条动画
NProgress.start();
- // 优先判断post/get等方法是否传入回掉,否则执行初始化设置等回掉
+ // 优先判断post/get等方法是否传入回调,否则执行初始化设置等回调
if (typeof config.beforeRequestCallback === "function") {
config.beforeRequestCallback(config);
return config;
@@ -123,7 +123,7 @@ class PureHttp {
const $config = response.config;
// 关闭进度条动画
NProgress.done();
- // 优先判断post/get等方法是否传入回掉,否则执行初始化设置等回掉
+ // 优先判断post/get等方法是否传入回调,否则执行初始化设置等回调
if (typeof $config.beforeResponseCallback === "function") {
$config.beforeResponseCallback(response);
return response.data;
@@ -159,7 +159,7 @@ class PureHttp {
...axiosConfig
} as PureHttpRequestConfig;
- // 单独处理自定义请求/响应回掉
+ // 单独处理自定义请求/响应回调
return new Promise((resolve, reject) => {
PureHttp.axiosInstance
.request(config)
diff --git a/tsconfig.json b/tsconfig.json
index 623c869..038dd01 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -28,8 +28,7 @@
"element-plus/global",
"@pureadmin/table/volar",
"@pureadmin/descriptions/volar"
- ],
- "typeRoots": ["./types", "./node_modules/@types/"]
+ ]
},
"include": [
"mock/*.ts",
diff --git a/types/index.d.ts b/types/index.d.ts
index b6b4518..404601a 100644
--- a/types/index.d.ts
+++ b/types/index.d.ts
@@ -41,6 +41,10 @@ type DeepPartial = {
[P in keyof T]?: DeepPartial;
};
+type Without = { [P in Exclude]?: never };
+
+type Exclusive = (Without & U) | (Without & T);
+
type TimeoutHandle = ReturnType;
type IntervalHandle = ReturnType;