diff --git a/CHANGELOG.md b/CHANGELOG.md index 8d619d2e..7d7068a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,19 @@ # CHANGE LOG +## 4.0.1 + +### Feats + +- 更改自定义路由暴露形式(由变量暴露改为方法获取) +- 模板所有方法进行检查,重命名部分方法(使其更加贴切其逻辑) +- 部分逻辑进行重写,使代码更容易阅读与维护 +- 模板类型进一步完善 + +### Fixes + +- 修复了内存高占用问题(路由模块) +- 修复类型导入错误问题 + ## 4.0.0 ### Feats diff --git a/cfg.ts b/cfg.ts index b5e1283b..9ec373fd 100644 --- a/cfg.ts +++ b/cfg.ts @@ -18,7 +18,7 @@ * - 系统: 根路由、标题、浏览器标题、别名等 * - 请求: 代理配置 * - * 如果需要新增相关内容, 需要在 src/types/cfg.ts 中进行类型配置 + * 如果需要新增相关内容, 需要在 src/types/modules/cfg.ts 中进行类型配置 * ``` * interface Config // config 内容类型配置 * @@ -43,7 +43,7 @@ import { buildOptions, mixinCSSPlugin, } from './vite-plugin/index' -import { APP_PRIMARY_COLOR } from './src/appConfig/designConfig' +import { APP_THEME } from './src/appConfig/designConfig' import { PRE_LOADING_CONFIG, ROOT_ROUTE, @@ -58,7 +58,7 @@ const config: AppConfigExport = { /** 配置首屏加载信息 */ preloadingConfig: PRE_LOADING_CONFIG, /** 默认主题色(不可省略, 必填), 也用于 ejs 注入 */ - appPrimaryColor: APP_PRIMARY_COLOR, + appPrimaryColor: APP_THEME.APP_PRIMARY_COLOR, sideBarLogo: SIDE_BAR_LOGO, /** * diff --git a/src/appConfig/appConfig.ts b/src/appConfig/appConfig.ts index c75814f8..992e827c 100644 --- a/src/appConfig/appConfig.ts +++ b/src/appConfig/appConfig.ts @@ -16,10 +16,7 @@ import type { PreloadingConfig, RootRoute, } from '@/types/modules/cfg' -import type { - MenuCollapsedConfig, - AppKeepAlive, -} from '@/types/modules/appConfig' +import type { AppMenuConfig, AppKeepAlive } from '@/types/modules/appConfig' /** * @@ -80,21 +77,18 @@ export const SIDE_BAR_LOGO: LayoutSideBarLogo = { * MENU_COLLAPSED_MODE: * - transform: 边栏将只会移动它的位置而不会改变宽度 * - width: Sider 的内容宽度将会被实际改变 - * * MENU_COLLAPSED_ICON_SIZE 配置菜单未折叠时图标的大小 - * * MENU_COLLAPSED_INDENT 配置菜单每级的缩进 + * MENU_ACCORDION 手风琴模式 */ -export const MENU_COLLAPSED_CONFIG: Readonly = { +export const APP_MENU_CONFIG: Readonly = { MENU_COLLAPSED_WIDTH: 64, MENU_COLLAPSED_MODE: 'width', MENU_COLLAPSED_ICON_SIZE: 22, MENU_COLLAPSED_INDENT: 24, + MENU_ACCORDION: false, } -/** 是否启用菜单手风琴模式 */ -export const MENU_ACCORDION = false - /** * * 系统默认缓存 key 配置 diff --git a/src/appConfig/designConfig.ts b/src/appConfig/designConfig.ts index 5d5ca5b3..013d2d67 100644 --- a/src/appConfig/designConfig.ts +++ b/src/appConfig/designConfig.ts @@ -11,54 +11,53 @@ /** 系统颜色风格配置入口 */ -import type { AppPrimaryColor } from '@/types/modules/cfg' -import type { GlobalThemeOverrides } from 'naive-ui' +import type { AppTheme } from '@/types/modules/cfg' -/** - * - * 系统主题颜色预设色盘 - * 支持 RGBA、RGB、十六进制 - */ -export const APP_THEME_COLOR = [ - '#2d8cf0', - '#0960bd', - '#536dfe', - '#ff5c93', - '#ee4f12', - '#9c27b0', - '#ff9800', - '#18A058', -] - -/** 系统主题色 */ -export const APP_PRIMARY_COLOR: AppPrimaryColor = { - /** 主题色 */ - primaryColor: '#2d8cf0', - /** 主题辅助色(用于整体 hover、active 等之类颜色) */ - primaryFadeColor: 'rgba(45, 140, 240, 0.3)', +export const APP_THEME: AppTheme = { + /** + * + * 系统主题颜色预设色盘 + * 支持 RGBA、RGB、十六进制 + */ + APP_THEME_COLOR: [ + '#2d8cf0', + '#0960bd', + '#536dfe', + '#ff5c93', + '#ee4f12', + '#9c27b0', + '#ff9800', + '#18A058', + ], + /** 系统主题色 */ + APP_PRIMARY_COLOR: { + /** 主题色 */ + primaryColor: '#2d8cf0', + /** 主题辅助色(用于整体 hover、active 等之类颜色) */ + primaryFadeColor: 'rgba(45, 140, 240, 0.3)', + }, + /** + * + * 配置系统 naive-ui 主题色 + * 官网文档地址: + * + * 注意: + * - APP_PRIMARY_COLOR common 配置优先级大于该配置 + * + * 如果需要定制化整体组件样式, 配置示例 + * ``` + * const themeOverrides: GlobalThemeOverrides = { + * common: { + * primaryColor: '#FF0000', + * }, + * Button: { + * textColor: '#FF0000', + * }, + * } + * ``` + * + * 具体自行查看官网, 还有模式更佳丰富的 peers 主题变量配置 + * 地址: + */ + APP_NAIVE_UI_THEME_OVERRIDES: {}, } - -/** - * - * 配置系统 naive-ui 主题色 - * 官网文档地址: - * - * 注意: - * - APP_PRIMARY_COLOR common 配置优先级大于该配置 - * - * 如果需要定制化整体组件样式, 配置示例 - * ``` - * const themeOverrides: GlobalThemeOverrides = { - * common: { - * primaryColor: '#FF0000', - * }, - * Button: { - * textColor: '#FF0000', - * }, - * } - * ``` - * - * 具体自行查看官网, 还有模式更佳丰富的 peers 主题变量配置 - * 地址: - */ -export const APP_NAIVE_UI_THEME_OVERRIDES: GlobalThemeOverrides = {} diff --git a/src/appConfig/regConfig.ts b/src/appConfig/regConfig.ts index 6fe34539..1c0c5b06 100644 --- a/src/appConfig/regConfig.ts +++ b/src/appConfig/regConfig.ts @@ -15,6 +15,8 @@ * 系统公共正则, 配置在该文件中 */ -/** css 尺寸单位匹配 */ -export const ELEMENT_UNIT = - /^\d+(\.\d+)?(px|em|rem|%|vw|vh|vmin|vmax|cm|mm|in|pt|pc|ch|ex|q|s|ms|deg|rad|turn|grad|hz|khz|dpi|dpcm|dppx|fr|auto)$/ +export const APP_REGEX: Record = { + /** css 尺寸单位匹配 */ + validerCSSUnit: + /^\d+(\.\d+)?(px|em|rem|%|vw|vh|vmin|vmax|cm|mm|in|pt|pc|ch|ex|q|s|ms|deg|rad|turn|grad|hz|khz|dpi|dpcm|dppx|fr|auto)$/, +} diff --git a/src/appConfig/routerConfig.ts b/src/appConfig/routerConfig.ts index 47128ab0..b4258828 100644 --- a/src/appConfig/routerConfig.ts +++ b/src/appConfig/routerConfig.ts @@ -13,9 +13,6 @@ import type { LayoutInst } from 'naive-ui' -/** 路由切换容器区域 id 配置 */ -export const viewScrollContainerId = 'rayLayoutContentWrapperScopeSelector' - /** * * 内容区域 ref 注册 diff --git a/src/axios/helper/axiosCopilot.ts b/src/axios/helper/axiosCopilot.ts index 65ba5ab5..60150dc5 100644 --- a/src/axios/helper/axiosCopilot.ts +++ b/src/axios/helper/axiosCopilot.ts @@ -21,8 +21,8 @@ import type { RequestHeaderOptions } from '../type' * * @remark 自定义 `axios` 请求头配置 */ -export const appendRequestHeaders = ( - instance: AxiosRequestConfig, +export const appendRequestHeaders = ( + instance: AxiosRequestConfig, options: RequestHeaderOptions[], ) => { if (instance) { diff --git a/src/axios/helper/canceler.ts b/src/axios/helper/canceler.ts index 04f1cf95..02e32c90 100644 --- a/src/axios/helper/canceler.ts +++ b/src/axios/helper/canceler.ts @@ -56,12 +56,11 @@ export default class RequestCanceler { const controller = new AbortController() config.signal = controller.signal + this.pendingRequest.set(requestKey, controller) } else { // 如果已经有该 key 则重新挂载 signal - config.signal = ( - this.pendingRequest.get(requestKey) as AbortController - ).signal + config.signal = this.pendingRequest.get(requestKey)?.signal } } diff --git a/src/axios/helper/interceptor.ts b/src/axios/helper/interceptor.ts index 2badc7d0..7a6c2e54 100644 --- a/src/axios/helper/interceptor.ts +++ b/src/axios/helper/interceptor.ts @@ -29,17 +29,20 @@ import type { ImplementQueue, ErrorImplementQueue, FetchType, + AxiosFetchInstance, + AxiosFetchError, } from '@/axios/type' import type { AnyFunc } from '@/types/modules/utils' /** 当前请求的实例 */ -const axiosFetchInstance = { - requestInstance: null as RequestInterceptorConfig | null, - responseInstance: null as ResponseInterceptorConfig | null, +const axiosFetchInstance: AxiosFetchInstance = { + requestInstance: null, + responseInstance: null, } -const axiosFetchError = { - requestError: null as null | unknown, - responseError: null as null | unknown, +/** 请求失败返回值 */ +const axiosFetchError: AxiosFetchError = { + requestError: null, + responseError: null, } /** 请求队列(区分 reslove 与 reject 状态) */ const implement: ImplementQueue = { @@ -57,7 +60,7 @@ export const useAxiosInterceptor = () => { /** 创建拦截器实例 */ const createAxiosInstance = ( instance: RequestInterceptorConfig | ResponseInterceptorConfig, - instanceKey: keyof typeof axiosFetchInstance, + instanceKey: keyof AxiosFetchInstance, ) => { instanceKey === 'requestInstance' ? (axiosFetchInstance['requestInstance'] = @@ -67,7 +70,7 @@ export const useAxiosInterceptor = () => { } /** 获取当前实例 */ - const getAxiosInstance = (instanceKey: keyof typeof axiosFetchInstance) => { + const getAxiosInstance = (instanceKey: keyof AxiosFetchInstance) => { return axiosFetchInstance[instanceKey] } @@ -101,7 +104,7 @@ export const useAxiosInterceptor = () => { /** 请求、响应前执行拦截器队列中的所有方法 */ const beforeFetch = ( - key: keyof typeof axiosFetchInstance, + key: keyof AxiosFetchInstance, implementKey: keyof ImplementQueue | keyof ErrorImplementQueue, fetchType: FetchType, ) => { @@ -119,7 +122,7 @@ export const useAxiosInterceptor = () => { /** 请求、响应错误时执行队列中所有方法 */ const fetchError = ( - key: keyof typeof axiosFetchError, + key: keyof AxiosFetchError, error: unknown, errorImplementKey: keyof ErrorImplementQueue, ) => { diff --git a/src/axios/inject/requestInject.ts b/src/axios/inject/requestInject.ts index b2231b6a..0cdb700e 100644 --- a/src/axios/inject/requestInject.ts +++ b/src/axios/inject/requestInject.ts @@ -28,6 +28,7 @@ import type { BeforeFetchFunction, FetchErrorFunction, } from '@/axios/type' + const { setImplement } = useAxiosInterceptor() /** @@ -74,6 +75,7 @@ const injectCanceler: BeforeFetchFunction = ( axiosCanceler.addPendingRequest(ins) // 把当前的请求信息添加到 pendingRequest 表中 } +/** 请求发生错误示例 */ const requestError: FetchErrorFunction = (error, mode) => { console.log(error, mode) } diff --git a/src/axios/instance.ts b/src/axios/instance.ts index 7959a583..56d7663d 100644 --- a/src/axios/instance.ts +++ b/src/axios/instance.ts @@ -33,22 +33,29 @@ import type { AxiosInstanceExpand } from './type' const server: AxiosInstanceExpand = axios.create(AXIOS_CONFIG) const { createAxiosInstance, beforeFetch, fetchError } = useAxiosInterceptor() +// 请求拦截器 server.interceptors.request.use( (request) => { + // 生成 request instance createAxiosInstance(request, 'requestInstance') + // 初始化拦截器所有已注入方法 setupRequestInterceptor() + // 执行拦截器所有已注入方法 beforeFetch('requestInstance', 'implementRequestInterceptorArray', 'ok') return request }, (error) => { + // 初始化拦截器所有已注入方法(错误状态) setupRequestErrorInterceptor() + // 执行所有已注入方法 fetchError('requestError', error, 'implementRequestInterceptorErrorArray') return Promise.reject(error) }, ) +// 响应拦截器 server.interceptors.response.use( (response) => { createAxiosInstance(response, 'responseInstance') @@ -63,6 +70,7 @@ server.interceptors.response.use( setupResponseErrorInterceptor() fetchError('responseError', error, 'implementResponseInterceptorErrorArray') + // 注销该失败请求的取消器 axiosCanceler.removePendingRequest(error.config || {}) return Promise.reject(error) diff --git a/src/axios/type.ts b/src/axios/type.ts index d954a08e..c05d1184 100644 --- a/src/axios/type.ts +++ b/src/axios/type.ts @@ -104,3 +104,13 @@ export type FetchErrorFunction = ( error: K, mode: string, ) => void + +export interface AxiosFetchInstance { + requestInstance: RequestInterceptorConfig | null + responseInstance: ResponseInterceptorConfig | null +} + +export interface AxiosFetchError { + requestError: T | null + responseError: T | null +} diff --git a/src/directives/helper/merger.ts b/src/directives/helper/combine.ts similarity index 95% rename from src/directives/helper/merger.ts rename to src/directives/helper/combine.ts index 4f21604f..ea0647ab 100644 --- a/src/directives/helper/merger.ts +++ b/src/directives/helper/combine.ts @@ -11,7 +11,7 @@ import type { DirectiveModules } from '@/directives/type' -export const mergerDirective = < +export const combineDirective = < T extends Record, K extends keyof T, >( diff --git a/src/directives/index.ts b/src/directives/index.ts index d4d6b1b2..a1495b2c 100644 --- a/src/directives/index.ts +++ b/src/directives/index.ts @@ -9,23 +9,41 @@ * @remark 今天也是元气满满撸代码的一天 */ -import { mergerDirective } from './helper/merger' +import { combineDirective } from './helper/combine' import { forIn } from 'lodash-es' +import { isValueType } from '@/utils/hook' import type { App } from 'vue' import type { DirectiveModules } from '@/directives/type' -/** 初始化全局自定义指令 */ +/** + * + * 初始化全局自定义指令 + * + * 该方法会将 modules 下每个文件夹视为一个指令 + * 并且会将文件夹名称识别为指令名称 + * 每个文件下的 index.ts 文件视为每个指令的入口(也就是指令的处理逻辑, 需要暴露出一个 Directive 类型的对象) + */ export const setupDirective = (app: App) => { - const modules = import.meta.glob('./modules/**/index.ts', { - eager: true, - }) as Record - const directives = mergerDirective(modules) + // 获取 modules 包下所有的 index.ts 文件 + const directiveRawModules: Record = + import.meta.glob('./modules/**/index.ts', { + eager: true, + }) + // 将所有的包提取出来(./modules/[file-name]/index.ts) + const directivesModules = combineDirective(directiveRawModules) + // 提取文件名(./modules/copy/index.ts => copy) const reg = /(?<=modules\/).*(?=\/index\.ts)/ - forIn(directives, (value, key) => { - const directiveName = key.match(reg)?.[0] as string + forIn(directivesModules, (value, key) => { + const dname = key.match(reg)?.[0] - app.directive(directiveName, value) + if (isValueType(dname, 'String')) { + app.directive(dname, value) + } else { + throw new Error( + 'directiveName is not string, please check your directive file name', + ) + } }) } diff --git a/src/layout/components/Menu/index.tsx b/src/layout/components/Menu/index.tsx index 3bc1f9a5..7e5ec5c5 100644 --- a/src/layout/components/Menu/index.tsx +++ b/src/layout/components/Menu/index.tsx @@ -4,7 +4,7 @@ import { NMenu, NLayoutSider, NEllipsis } from 'naive-ui' import RayIcon from '@/components/RayIcon/index' import { useMenu } from '@/store' -import { MENU_COLLAPSED_CONFIG, MENU_ACCORDION } from '@/appConfig/appConfig' +import { APP_MENU_CONFIG } from '@/appConfig/appConfig' import { useVueRouter } from '@/router/helper/useVueRouter' import type { MenuInst } from 'naive-ui' @@ -18,7 +18,7 @@ const LayoutMenu = defineComponent({ const menuStore = useMenu() const { router } = useVueRouter() - const { menuModelValueChange, collapsedMenu } = menuStore + const { changeMenuModelValue, collapsedMenu } = menuStore const modelMenuKey = computed({ get: () => { nextTick().then(() => { @@ -46,7 +46,7 @@ const LayoutMenu = defineComponent({ return { modelMenuKey, - menuModelValueChange, + changeMenuModelValue, modelMenuOptions, modelCollapsed, collapsedMenu, @@ -60,8 +60,8 @@ const LayoutMenu = defineComponent({ @@ -94,12 +94,12 @@ const LayoutMenu = defineComponent({ ref="menuRef" v-model:value={this.modelMenuKey} options={this.modelMenuOptions as NaiveMenuOptions[]} - indent={MENU_COLLAPSED_CONFIG.MENU_COLLAPSED_INDENT} + indent={APP_MENU_CONFIG.MENU_COLLAPSED_INDENT} collapsed={this.modelCollapsed} - collapsedIconSize={MENU_COLLAPSED_CONFIG.MENU_COLLAPSED_ICON_SIZE} - collapsedWidth={MENU_COLLAPSED_CONFIG.MENU_COLLAPSED_WIDTH} - onUpdateValue={this.menuModelValueChange.bind(this)} - accordion={MENU_ACCORDION} + collapsedIconSize={APP_MENU_CONFIG.MENU_COLLAPSED_ICON_SIZE} + collapsedWidth={APP_MENU_CONFIG.MENU_COLLAPSED_WIDTH} + onUpdateValue={this.changeMenuModelValue.bind(this)} + accordion={APP_MENU_CONFIG.MENU_ACCORDION} /> ) diff --git a/src/layout/components/MenuTag/index.tsx b/src/layout/components/MenuTag/index.tsx index e068c7d1..91971841 100644 --- a/src/layout/components/MenuTag/index.tsx +++ b/src/layout/components/MenuTag/index.tsx @@ -48,7 +48,7 @@ const MenuTag = defineComponent({ const { menuKey, menuTagOptions } = storeToRefs(menuStore) const { - menuModelValueChange, + changeMenuModelValue, spliceMenTagOptions, emptyMenuTagOptions, setMenuTagOptions, @@ -180,7 +180,7 @@ const MenuTag = defineComponent({ spliceMenTagOptions(currentContentmenuIndex + 1, length - 1) if (menuKey.value !== routeItem.key) { - menuModelValueChange(routeItem.key, routeItem) + changeMenuModelValue(routeItem.key, routeItem) } }, closeLeft: () => { @@ -197,7 +197,7 @@ const MenuTag = defineComponent({ if (menuKey.value !== routeItem.key) { emptyMenuTagOptions() - menuModelValueChange(routeItem.key, routeItem) + changeMenuModelValue(routeItem.key, routeItem) } else { setMenuTagOptions(routeItem, false) } @@ -226,7 +226,7 @@ const MenuTag = defineComponent({ const tag = options[length - 1] - menuModelValueChange(tag.key as string, tag) + changeMenuModelValue(tag.key as string, tag) } } @@ -248,7 +248,7 @@ const MenuTag = defineComponent({ * @param item 当前菜单值 */ const handleTagClick = (item: MenuOption) => { - menuModelValueChange(item.key as string, item) + changeMenuModelValue(item.key as string, item) } const getScrollElement = () => { @@ -430,7 +430,7 @@ const MenuTag = defineComponent({ return { modelMenuTagOptions, - menuModelValueChange, + changeMenuModelValue, closeCurrentMenuTag, menuKey, handleTagClick, diff --git a/src/layout/components/SiderBar/Components/Breadcrumb/index.tsx b/src/layout/components/SiderBar/Components/Breadcrumb/index.tsx index 986b81e4..accdd8ad 100644 --- a/src/layout/components/SiderBar/Components/Breadcrumb/index.tsx +++ b/src/layout/components/SiderBar/Components/Breadcrumb/index.tsx @@ -29,14 +29,14 @@ const Breadcrumb = defineComponent({ setup() { const menuStore = useMenu() - const { menuModelValueChange } = menuStore + const { changeMenuModelValue } = menuStore const modelBreadcrumbOptions = computed(() => menuStore.breadcrumbOptions) const handleDropdownSelect = ( key: string | number, option: DropdownOption, ) => { - menuModelValueChange(key, option) + changeMenuModelValue(key, option) } return { diff --git a/src/layout/components/SiderBar/Components/GlobalSeach/index.tsx b/src/layout/components/SiderBar/Components/GlobalSeach/index.tsx index 6bb352d4..1efc8192 100644 --- a/src/layout/components/SiderBar/Components/GlobalSeach/index.tsx +++ b/src/layout/components/SiderBar/Components/GlobalSeach/index.tsx @@ -35,7 +35,7 @@ const GlobalSeach = defineComponent({ setup(props, { emit }) { const menuStore = useMenu() - const { menuModelValueChange } = menuStore + const { changeMenuModelValue } = menuStore const modelShow = computed({ get: () => props.show, set: (val) => { @@ -117,7 +117,7 @@ const GlobalSeach = defineComponent({ } else { modelShow.value = false - menuModelValueChange(option.key as string, option) + changeMenuModelValue(option.key as string, option) } } diff --git a/src/layout/components/SiderBar/Components/SettingDrawer/index.tsx b/src/layout/components/SiderBar/Components/SettingDrawer/index.tsx index 1d1f82d9..ebed3dbf 100644 --- a/src/layout/components/SiderBar/Components/SettingDrawer/index.tsx +++ b/src/layout/components/SiderBar/Components/SettingDrawer/index.tsx @@ -11,7 +11,7 @@ import { } from 'naive-ui' import ThemeSwitch from '@/layout/components/SiderBar/components/SettingDrawer/components/ThemeSwitch/index' -import { APP_THEME_COLOR } from '@/appConfig/designConfig' +import { APP_THEME } from '@/appConfig/designConfig' import { useSetting } from '@/store' import { useI18n } from '@/locales/useI18n' @@ -86,7 +86,7 @@ const SettingDrawer = defineComponent({ {t('headerSettingOptions.ThemeOptions.PrimaryColorConfig')} diff --git a/src/layout/default/FooterWrapper/index.tsx b/src/layout/default/FooterWrapper/index.tsx index ecdd85fc..96eef486 100644 --- a/src/layout/default/FooterWrapper/index.tsx +++ b/src/layout/default/FooterWrapper/index.tsx @@ -26,7 +26,7 @@ const FooterWrapper = defineComponent({ return this.copyright ? ( ) : ( - <> + '' ) }, }) diff --git a/src/layout/index.tsx b/src/layout/index.tsx index dbbbe72b..6905022c 100644 --- a/src/layout/index.tsx +++ b/src/layout/index.tsx @@ -19,10 +19,7 @@ import ContentWrapper from '@/layout/default/ContentWrapper' import FooterWrapper from '@/layout/default/FooterWrapper' import { useSetting, useMenu } from '@/store' -import { - viewScrollContainerId, - LAYOUT_CONTENT_REF, -} from '@/appConfig/routerConfig' +import { LAYOUT_CONTENT_REF } from '@/appConfig/routerConfig' import { layoutHeaderCssVars } from '@/layout/layoutResize' import useAppLockScreen from '@/components/AppComponents/AppLockScreen/appLockVar' @@ -33,19 +30,18 @@ const Layout = defineComponent({ const layoutMenuTagRef = ref() const settingStore = useSetting() - const menuStore = useMenu() const { height: windowHeight } = useWindowSize() const { menuTagSwitch: modelMenuTagSwitch } = storeToRefs(settingStore) - const { setupAppRoutes } = menuStore const { getLockAppScreen } = useAppLockScreen() const cssVarsRef = layoutHeaderCssVars([ layoutSiderBarRef, layoutMenuTagRef, ]) + const { setupAppMenu } = useMenu() nextTick().then(() => { - setupAppRoutes() + setupAppMenu() }) return { @@ -78,7 +74,6 @@ const Layout = defineComponent({ ref="LAYOUT_CONTENT_REF" class="layout-content__router-view" nativeScrollbar={false} - {...{ id: viewScrollContainerId }} > diff --git a/src/locales/README.md b/src/locales/README.md index 0d3b8433..e9d1227d 100644 --- a/src/locales/README.md +++ b/src/locales/README.md @@ -17,14 +17,14 @@ #### 拓展方法 - 配置语言包文件(文件名为语言包名称) -- 配置文件入口(使用 `mergeMessage` 方法进行自动合并处理) +- 配置文件入口(使用 `combineI18nMessages` 方法进行自动合并处理) - 语言包名称应该全局唯一 ### helper 文件说明 -- `getAppLocales` 获取系统所有语言包(该方法强制依赖 LOCAL_OPTIONS key 配置,意味着你在配置语言包的时候,key 必须与 `src/locales/lang/xxx.ts` 一一对应匹配) +- `getAppLocalMessages` 获取系统所有语言包(该方法强制依赖 LOCAL_OPTIONS key 配置,意味着你在配置语言包的时候,key 必须与 `src/locales/lang/xxx.ts` 一一对应匹配) - `naiveLocales` 获取 `naive-ui` 组件库对应语言包文件 -- `getDefaultLocal` 获取系统当前默认语言包 +- `getAppDefaultLanguage` 获取系统当前默认语言包 ### useI18n 文件说明 diff --git a/src/locales/helper.ts b/src/locales/helper.ts index e00dbef6..421a87be 100644 --- a/src/locales/helper.ts +++ b/src/locales/helper.ts @@ -12,8 +12,8 @@ /** * * 国际化辅助方法: - * - mergeMessage: 合并对应文件下语言包 - * - getAppLocales: 获取所有语言 + * - combineI18nMessages: 合并对应文件下语言包 + * - getAppLocalMessages: 获取所有语言 */ import { set } from 'lodash-es' @@ -27,6 +27,7 @@ import type { AppLocalesModules, AppLocalesDropdownMixedOption, CurrentAppMessages, + I18nModules, } from '@/locales/type' /** @@ -36,13 +37,12 @@ import type { * * @remark 合并处理语言包内容, prefix 必填 */ -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export const mergeMessage = (langs: Record, prefix: string) => { - if (!prefix) { - throw new Error('Expected prefix to be string, got undefined instead') +export const combineI18nMessages = (langs: I18nModules, prefix: string) => { + if (typeof prefix !== 'string' || !prefix.trim()) { + throw new Error('Expected prefix to be a non-empty string') } - const langsGather: Recordable = {} + const langsGather: Record = {} Object.keys(langs).forEach((key) => { const langFileModule = langs[key].default @@ -70,13 +70,13 @@ export const mergeMessage = (langs: Record, prefix: string) => { } /** 获取所有语言 */ -export const getAppLocales = async ( +export const getAppLocalMessages = async ( LOCAL_OPTIONS: AppLocalesDropdownMixedOption[], ) => { const message = {} as CurrentAppMessages for (const curr of LOCAL_OPTIONS) { - const msg = (await import(`./lang/${curr.key}.ts`)) as AppLocalesModules + const msg: AppLocalesModules = await import(`./lang/${curr.key}.ts`) const key = curr.key if (key) { @@ -125,13 +125,11 @@ export const naiveLocales = (key: string) => { * * @remak 未避免出现加载语言错误问题, 故而在 `main.ts` 注册时, 应优先加载 `i18n` 避免出现该问题 */ -export const getDefaultLocal = () => { - const catchLanguage = getCache( +export const getAppDefaultLanguage = () => { + const language = getCache( APP_CATCH_KEY.localeLanguage, 'localStorage', ) - const locale = catchLanguage ? catchLanguage : SYSTEM_DEFAULT_LOCAL - - return locale + return language ? language : SYSTEM_DEFAULT_LOCAL } diff --git a/src/locales/index.ts b/src/locales/index.ts index 67077e1b..7b88d771 100644 --- a/src/locales/index.ts +++ b/src/locales/index.ts @@ -25,9 +25,9 @@ import { createI18n } from 'vue-i18n' import { LOCAL_OPTIONS } from '@/appConfig/localConfig' -import { getDefaultLocal } from '@/locales/helper' +import { getAppDefaultLanguage } from '@/locales/helper' -import { getAppLocales } from '@/locales/helper' +import { getAppLocalMessages } from '@/locales/helper' import type { App } from 'vue' import type { I18n, I18nOptions } from 'vue-i18n' @@ -37,8 +37,8 @@ export let i18n: I18n /** 创建 i18n 实例 */ const createI18nOptions = async () => { - const locale = getDefaultLocal() - const messages = await getAppLocales(LOCAL_OPTIONS) + const locale = getAppDefaultLanguage() + const messages = await getAppLocalMessages(LOCAL_OPTIONS) const i18nInstance = createI18n({ legacy: false, diff --git a/src/locales/lang/en-US.ts b/src/locales/lang/en-US.ts index 380ff207..01121baa 100644 --- a/src/locales/lang/en-US.ts +++ b/src/locales/lang/en-US.ts @@ -1,11 +1,13 @@ -import { mergeMessage } from '@/locales/helper' +import { combineI18nMessages } from '@/locales/helper' -const modules = import.meta.glob('./en-US/**/*.json', { +import type { I18nModules } from '@/locales/type' + +const modules: I18nModules = import.meta.glob('./en-US/**/*.json', { eager: true, }) export default { message: { - ...mergeMessage(modules, 'en-US'), + ...combineI18nMessages(modules, 'en-US'), }, } diff --git a/src/locales/lang/zh-CN.ts b/src/locales/lang/zh-CN.ts index c25dd991..b1f4924b 100644 --- a/src/locales/lang/zh-CN.ts +++ b/src/locales/lang/zh-CN.ts @@ -1,11 +1,13 @@ -import { mergeMessage } from '@/locales/helper' +import { combineI18nMessages } from '@/locales/helper' -const modules = import.meta.glob('./zh-CN/**/*.json', { +import type { I18nModules } from '@/locales/type' + +const modules: I18nModules = import.meta.glob('./zh-CN/**/*.json', { eager: true, }) export default { message: { - ...mergeMessage(modules, 'zh-CN'), + ...combineI18nMessages(modules, 'zh-CN'), }, } diff --git a/src/locales/type.ts b/src/locales/type.ts index 358b58d9..03492fa1 100644 --- a/src/locales/type.ts +++ b/src/locales/type.ts @@ -4,6 +4,7 @@ import type { DropdownDividerOption, DropdownRenderOption, } from 'naive-ui' +import type { Recordable } from '@/types/modules/helper' export interface CurrentAppMessages { 'zh-CN': object @@ -21,3 +22,5 @@ export interface AppLocalesModules { message: UnknownObjectKey } } + +export type I18nModules = Record diff --git a/src/locales/useI18n.ts b/src/locales/useI18n.ts index c2145e6e..32da32a6 100644 --- a/src/locales/useI18n.ts +++ b/src/locales/useI18n.ts @@ -30,6 +30,7 @@ export const useI18n = (namespace?: string) => { return (t as any)(getI18nKey(namespace, key), ...args) } + /** 重写 locale 方法 */ const overrideLocaleFunc = (lang: string) => { const localeRef = locale as WritableComputedRef @@ -50,4 +51,4 @@ export const useI18n = (namespace?: string) => { * * 该插件识别 t 方法包裹 path 进行提示文案内容 */ -export const t = (key: T) => key +export const t = (key: string) => key diff --git a/src/router/helper/merge.ts b/src/router/helper/combine.ts similarity index 54% rename from src/router/helper/merge.ts rename to src/router/helper/combine.ts index c5e82731..12e35dcf 100644 --- a/src/router/helper/merge.ts +++ b/src/router/helper/combine.ts @@ -9,7 +9,7 @@ * @remark 今天也是元气满满撸代码的一天 */ -import type { AppRouteRecordRaw, AutoImportRouteModule } from '@/router/type' +import type { AppRouteRecordRaw, RouteModules } from '@/router/type' /** * @@ -17,15 +17,21 @@ import type { AppRouteRecordRaw, AutoImportRouteModule } from '@/router/type' * * @remark 自动合并所有路由模块, 每一个 ts 文件都视为一个 route module 与 views 一一对应 */ -export const autoMergeRoute = () => { - const modulesFiles = import.meta.glob('../modules/**/*.ts', { +export const combineRawRouteModules = () => { + const modulesFiles: RouteModules = import.meta.glob('../modules/**/*.ts', { eager: true, }) const modules = Object.keys(modulesFiles).reduce((modules, modulePath) => { - const value = modulesFiles[modulePath] as AutoImportRouteModule + const route = modulesFiles[modulePath].default - modules.push(value.default) + if (route) { + modules.push(route) + } else { + throw new Error( + 'router helper combine: an exception occurred while parsing the routing file!', + ) + } return modules }, [] as AppRouteRecordRaw[]) diff --git a/src/router/helper/routerCopilot.ts b/src/router/helper/routerCopilot.ts index 892bcac8..71d4458c 100644 --- a/src/router/helper/routerCopilot.ts +++ b/src/router/helper/routerCopilot.ts @@ -141,7 +141,6 @@ export const redirectRouterToDashboard = (isReplace = true) => { const { path } = ROOT_ROUTE setCache('menuKey', path) - console.log('path', path) isReplace ? push(path) : replace(path) } diff --git a/src/router/index.ts b/src/router/index.ts index c632978e..dbebfeb8 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -13,7 +13,7 @@ export let router: Router const createVueRouter = () => { return createRouter({ history: createWebHashHistory(), - routes: constantRoutes as unknown as RouteRecordRaw[], + routes: constantRoutes() as unknown as RouteRecordRaw[], scrollBehavior: (to) => { scrollViewToTop(to) diff --git a/src/router/routeModules.ts b/src/router/routeModules.ts index bc091c92..ab921679 100644 --- a/src/router/routeModules.ts +++ b/src/router/routeModules.ts @@ -20,11 +20,8 @@ * 如果不设置 order 属性, 则会默认排在前面 */ -import { autoMergeRoute } from '@/router/helper/merge' +import { combineRawRouteModules } from '@/router/helper/combine' import { orderRoutes } from '@/router/helper/orderRoutes' -import type { AppRouteRecordRaw } from '@/router/type' - -const routes: AppRouteRecordRaw[] = orderRoutes(autoMergeRoute()) - -export default routes +/** 获取所有被合并与排序的路由 */ +export const getAppRawRoutes = () => orderRoutes(combineRawRouteModules()) diff --git a/src/router/routes.ts b/src/router/routes.ts index fbf6aff8..37bc076d 100644 --- a/src/router/routes.ts +++ b/src/router/routes.ts @@ -1,11 +1,11 @@ import Layout from '@/layout/index' -import childrenRoutes from './routeModules' +import { getAppRawRoutes } from './routeModules' import { ROOT_ROUTE } from '@/appConfig/appConfig' import { expandRoutes } from '@/router/helper/expandRoutes' const { path } = ROOT_ROUTE -export default [ +export default () => [ { path: '/', name: 'login', @@ -16,7 +16,7 @@ export default [ name: 'layout', redirect: path, component: Layout, - children: expandRoutes(childrenRoutes), + children: expandRoutes(getAppRawRoutes()), }, { path: '/:catchAll(.*)', diff --git a/src/router/type.ts b/src/router/type.ts index f1d6ad32..90731dbd 100644 --- a/src/router/type.ts +++ b/src/router/type.ts @@ -32,6 +32,8 @@ export interface AppRouteRecordRaw extends Omit { fullPath?: string } -export interface AutoImportRouteModule extends Object { - default: AppRouteRecordRaw +export interface RouteModules { + [propName: string]: { + default: AppRouteRecordRaw + } } diff --git a/src/store/modules/menu/helper.ts b/src/store/modules/menu/helper.ts index 8c9cc594..3827b57b 100644 --- a/src/store/modules/menu/helper.ts +++ b/src/store/modules/menu/helper.ts @@ -11,7 +11,7 @@ /** 本方法感谢 的支持 */ -import { MENU_COLLAPSED_CONFIG, ROOT_ROUTE } from '@/appConfig/appConfig' +import { APP_MENU_CONFIG, ROOT_ROUTE } from '@/appConfig/appConfig' import RayIcon from '@/components/RayIcon/index' import { isValueType } from '@/utils/hook' import { getCache, setCache } from '@/utils/cache' @@ -31,12 +31,20 @@ import type { * * @remark 检查是否为所需项 */ -const check = ( +const isMatch = ( node: AppMenuOption, key: string | number, value: string | number, ) => { - return node[key] === value || node.key === value + if (!node || typeof node !== 'object') { + return false + } + + if (node[key] === value) { + return true + } + + return false } /** @@ -47,7 +55,7 @@ const check = ( * * @remark 匹配所有节点 */ -const process = ( +const findMatchingNodes = ( options: AppMenuOption, key: string | number, value: string | number, @@ -55,7 +63,7 @@ const process = ( const temp: AppMenuOption[] = [] // 检查当前节点是否匹配值 - if (check(options, key, value)) { + if (isMatch(options, key, value)) { temp.push(options) return temp @@ -65,7 +73,7 @@ const process = ( if (options.children && options.children.length > 0) { for (const it of options.children) { // 子节点递归调用 - const innerTemp = process(it, key, value) + const innerTemp = findMatchingNodes(it, key, value) // 如果子节点匹配到了,则将当前节点加入数组 if (innerTemp.length > 0) { @@ -83,7 +91,7 @@ const process = ( * @param key 动态字段 * @param value 匹配值 */ -export const parse = ( +export const parseAndFindMatchingNodes = ( options: AppMenuOption[], key: string | number, value: string | number, @@ -91,7 +99,7 @@ export const parse = ( const temp = [] for (const it of options) { - const innerTemp = process(it, key, value) + const innerTemp = findMatchingNodes(it, key, value) if (innerTemp.length > 0) { temp.push(...innerTemp) @@ -155,7 +163,7 @@ export const hasMenuIcon = (option: AppMenuOption) => { RayIcon, { name: meta!.icon as string, - size: MENU_COLLAPSED_CONFIG.MENU_COLLAPSED_ICON_SIZE, + size: APP_MENU_CONFIG.MENU_COLLAPSED_ICON_SIZE, }, {}, ) diff --git a/src/store/modules/menu/index.ts b/src/store/modules/menu/index.ts index d8130c28..25e74ea5 100644 --- a/src/store/modules/menu/index.ts +++ b/src/store/modules/menu/index.ts @@ -27,20 +27,21 @@ import { NEllipsis } from 'naive-ui' import { getCache, setCache } from '@/utils/cache' import { validMenuItemShow } from '@/router/helper/routerCopilot' import { - parse, + parseAndFindMatchingNodes, matchMenuOption, updateDocumentTitle, hasMenuIcon, getCatchMenuKey, } from './helper' import { useI18n } from '@/locales/useI18n' -import routeModules from '@/router/routeModules' +import { getAppRawRoutes } from '@/router/routeModules' import { useKeepAlive } from '@/store' import { useVueRouter } from '@/router/helper/useVueRouter' import type { MenuOption } from 'naive-ui' -import type { AppRouteMeta } from '@/router/type' +import type { AppRouteMeta, AppRouteRecordRaw } from '@/router/type' import type { AppMenuOption, MenuTagOptions } from '@/types/modules/app' +import type { MenuState } from '@/store/modules/menu/type' export const useMenu = defineStore( 'menu', @@ -50,12 +51,12 @@ export const useMenu = defineStore( const { t } = useI18n() const { setKeepAliveInclude } = useKeepAlive() - const menuState = reactive({ + const menuState = reactive({ menuKey: getCatchMenuKey(), // 当前菜单 `key` - options: [] as AppMenuOption[], // 菜单列表 + options: [], // 菜单列表 collapsed: false, // 是否折叠菜单 - menuTagOptions: [] as MenuTagOptions[], // tag 标签菜单 - breadcrumbOptions: [] as AppMenuOption[], // 面包屑菜单 + menuTagOptions: [], // tag 标签菜单 + breadcrumbOptions: [], // 面包屑菜单 }) /** @@ -69,21 +70,21 @@ export const useMenu = defineStore( options: AppMenuOption[], key: string | number, ) => { - const ops = parse(options, 'key', key) + const ops = parseAndFindMatchingNodes(options, 'key', key) return ops } /** * - * @param key 菜单更新后的 `key` - * @param item 菜单当前 `item` + * @param key 菜单更新后的 key + * @param option 菜单当前 option 项 * * @remark 修改 `menu key` 后的回调函数 * @remark 修改后, 缓存当前选择 key 并且存储标签页与跳转页面(router push 操作) */ - const menuModelValueChange = (key: string | number, item: MenuOption) => { - const meta = item.meta as AppRouteMeta + const changeMenuModelValue = (key: string | number, option: MenuOption) => { + const { meta, path } = option as unknown as AppRouteRecordRaw if (meta.windowOpen) { window.open(meta.windowOpen) @@ -91,26 +92,30 @@ export const useMenu = defineStore( // 防止重复点击做重复操作处理 if (menuState.menuKey !== key) { matchMenuOption( - item as unknown as MenuTagOptions, + option as unknown as MenuTagOptions, menuState.menuKey, menuState.menuTagOptions, ) - updateDocumentTitle(item as unknown as AppMenuOption) - setKeepAliveInclude(item as unknown as AppMenuOption) + updateDocumentTitle(option as unknown as AppMenuOption) + setKeepAliveInclude(option as unknown as AppMenuOption) - menuState.breadcrumbOptions = parse(menuState.options, 'key', key) // 获取面包屑 + menuState.breadcrumbOptions = parseAndFindMatchingNodes( + menuState.options, + 'key', + key, + ) // 获取面包屑 /** 是否为根路由 */ - if (key[0] !== '/') { + if (!String(key).startsWith('/')) { /** 如果不是根路由, 则拼接完整路由并跳转 */ - const path = getCompleteRoutePath(menuState.options, key) + const _path = getCompleteRoutePath(menuState.options, key) .map((curr) => curr.key) .join('/') - router.push(path) + router.push(_path) } else { /** 根路由直接跳转 */ - router.push(item.path as string) + router.push(path) } menuState.menuKey = key @@ -136,7 +141,7 @@ export const useMenu = defineStore( } if (path === i.path) { - menuModelValueChange(i.path, i) + changeMenuModelValue(i.path, i) break } @@ -168,69 +173,76 @@ export const useMenu = defineStore( * @remark 初始化菜单列表, 并且按照权限过滤 * @remark 如果权限发生变动, 则会触发强制弹出页面并且重新登陆 */ - const setupAppRoutes = () => { - const resolveOption = (option: AppMenuOption) => { - const { meta } = option + const setupAppMenu = () => { + return new Promise((resolve) => { + const resolveOption = (option: AppMenuOption) => { + const { meta } = option - /** 设置 label, i18nKey 优先级最高 */ - const label = computed(() => - meta?.i18nKey ? t(`${meta!.i18nKey}`) : meta?.noLocalTitle, - ) - /** 拼装菜单项 */ - const route = { - ...option, - key: option.path, - label: () => - h(NEllipsis, null, { - default: () => label.value, - }), - breadcrumbLabel: label.value, - } as AppMenuOption - /** 合并 icon */ - const attr: AppMenuOption = Object.assign({}, route, { - icon: hasMenuIcon(option), - }) + /** 设置 label, i18nKey 优先级最高 */ + const label = computed(() => + meta?.i18nKey ? t(`${meta!.i18nKey}`) : meta?.noLocalTitle, + ) + /** 拼装菜单项 */ + const route = { + ...option, + key: option.path, + label: () => + h(NEllipsis, null, { + default: () => label.value, + }), + breadcrumbLabel: label.value, + } as AppMenuOption + /** 合并 icon */ + const attr: AppMenuOption = Object.assign({}, route, { + icon: hasMenuIcon(option), + }) - if (option.path === getCatchMenuKey()) { - /** 设置菜单标签 */ - setMenuTagOptions(attr) - /** 设置浏览器标题 */ - updateDocumentTitle(attr) - } - - /** 检查该菜单项是否展示 */ - attr.show = validMenuItemShow(option) - - return attr - } - - const resolveRoutes = (routes: AppMenuOption[], index: number) => { - const catchArr: AppMenuOption[] = [] - - for (const curr of routes) { - if (curr.children?.length && validMenuItemShow(curr)) { - curr.children = resolveRoutes(curr.children, index++) - } else if (!validMenuItemShow(curr)) { - /** 如果校验失败, 则不会添加进 menu options */ - continue + if (option.path === getCatchMenuKey()) { + /** 设置菜单标签 */ + setMenuTagOptions(attr) + /** 设置浏览器标题 */ + updateDocumentTitle(attr) } - catchArr.push(resolveOption(curr)) + /** 检查该菜单项是否展示 */ + attr.show = validMenuItemShow(option) + + return attr } - return catchArr - } + const resolveRoutes = (routes: AppMenuOption[], index: number) => { + const catchArr: AppMenuOption[] = [] - /** 缓存菜单列表 */ - menuState.options = resolveRoutes(routeModules as AppMenuOption[], 0) + for (const curr of routes) { + if (curr.children?.length && validMenuItemShow(curr)) { + curr.children = resolveRoutes(curr.children, index++) + } else if (!validMenuItemShow(curr)) { + /** 如果校验失败, 则不会添加进 menu options */ + continue + } - /** 初始化后渲染面包屑 */ - nextTick(() => { - menuState.breadcrumbOptions = parse( - menuState.options, - 'key', - menuState.menuKey as string, + catchArr.push(resolveOption(curr)) + } + + return catchArr + } + + /** 缓存菜单列表 */ + menuState.options = resolveRoutes( + getAppRawRoutes() as AppMenuOption[], + 0, ) + + resolve() + + /** 初始化后渲染面包屑 */ + nextTick(() => { + menuState.breadcrumbOptions = parseAndFindMatchingNodes( + menuState.options, + 'key', + menuState.menuKey as string, + ) + }) }) } @@ -275,8 +287,8 @@ export const useMenu = defineStore( return { ...toRefs(menuState), - menuModelValueChange, - setupAppRoutes, + changeMenuModelValue, + setupAppMenu, collapsedMenu, spliceMenTagOptions, emptyMenuTagOptions, diff --git a/src/store/modules/menu/type.ts b/src/store/modules/menu/type.ts new file mode 100644 index 00000000..c1cc0cfc --- /dev/null +++ b/src/store/modules/menu/type.ts @@ -0,0 +1,13 @@ +import type { + AppMenuOption, + MenuTagOptions, + AppMenuKey, +} from '@/types/modules/app' + +export interface MenuState { + menuKey: AppMenuKey + options: AppMenuOption[] + collapsed: boolean + menuTagOptions: MenuTagOptions[] + breadcrumbOptions: AppMenuOption[] +} diff --git a/src/store/modules/setting/index.ts b/src/store/modules/setting/index.ts index bc17ef60..b60d3d67 100644 --- a/src/store/modules/setting/index.ts +++ b/src/store/modules/setting/index.ts @@ -1,9 +1,9 @@ -import { getDefaultLocal } from '@/locales/helper' +import { getAppDefaultLanguage } from '@/locales/helper' import { setCache } from '@use-utils/cache' import { set } from 'lodash-es' import { addClass, removeClass, colorToRgba } from '@/utils/element' import { useI18n } from '@/locales/useI18n' -import { APP_NAIVE_UI_THEME_OVERRIDES } from '@/appConfig/designConfig' +import { APP_THEME } from '@/appConfig/designConfig' import { useDayjs } from '@/dayjs/index' import type { ConditionalPick } from '@/types/modules/helper' @@ -22,7 +22,7 @@ export const useSetting = defineStore( const settingState = reactive({ drawerPlacement: 'right', primaryColorOverride: { - ...APP_NAIVE_UI_THEME_OVERRIDES, + ...APP_THEME.APP_NAIVE_UI_THEME_OVERRIDES, common: { primaryColor: primaryColor, // 主题色 primaryColorHover: primaryColor, @@ -34,7 +34,7 @@ export const useSetting = defineStore( spinSwitch: false, // 全屏加载 invertSwitch: false, // 反转色模式 breadcrumbSwitch: true, // 面包屑开关 - localeLanguage: getDefaultLocal(), + localeLanguage: getAppDefaultLanguage(), lockScreenSwitch: false, // 锁屏开关 lockScreenInputSwitch: false, // 锁屏输入状态开关(预留该字段是为了方便拓展用, 但是舍弃了该字段, 改为使用 useAppLockScreen 方法) }) diff --git a/src/types/modules/appConfig.ts b/src/types/modules/appConfig.ts index a21c47c1..d5226619 100644 --- a/src/types/modules/appConfig.ts +++ b/src/types/modules/appConfig.ts @@ -2,11 +2,12 @@ import type { CreateAxiosDefaults } from 'axios' export type CollapsedMode = 'transform' | 'width' -export interface MenuCollapsedConfig { +export interface AppMenuConfig { MENU_COLLAPSED_WIDTH: number MENU_COLLAPSED_MODE: CollapsedMode MENU_COLLAPSED_ICON_SIZE: number MENU_COLLAPSED_INDENT: number + MENU_ACCORDION: boolean } export interface AppKeepAlive { diff --git a/src/types/modules/cfg.ts b/src/types/modules/cfg.ts index 91b54f53..aadb2165 100644 --- a/src/types/modules/cfg.ts +++ b/src/types/modules/cfg.ts @@ -6,6 +6,7 @@ import type { UserConfigExport, } from 'vite' import type { Recordable } from '@/types/modules/helper' +import type { GlobalThemeOverrides } from 'naive-ui' export interface LayoutSideBarLogo { icon?: string @@ -73,3 +74,9 @@ export interface AppConfig { } export type AppConfigExport = Config & UserConfigExport + +export interface AppTheme { + APP_THEME_COLOR: string[] + APP_PRIMARY_COLOR: AppPrimaryColor + APP_NAIVE_UI_THEME_OVERRIDES: GlobalThemeOverrides +} diff --git a/src/utils/element.ts b/src/utils/element.ts index 6145efbd..780930e8 100644 --- a/src/utils/element.ts +++ b/src/utils/element.ts @@ -1,5 +1,5 @@ import { isValueType } from '@use-utils/hook' -import { ELEMENT_UNIT } from '@/appConfig/regConfig' +import { APP_REGEX } from '@/appConfig/regConfig' import type { EventListenerOrEventListenerObject } from '@/types/modules/utils' @@ -132,9 +132,9 @@ export const hasClass = (element: HTMLElement, className: string) => { * addStyle(styles) * ``` */ -export const addStyle = ( +export const addStyle = ( el: HTMLElement, - styles: string | Partial, + styles: K | Partial, ) => { if (el) { if (isValueType(styles, 'Object')) { @@ -160,10 +160,13 @@ export const addStyle = ( * @param el Target element dom * @param styles 所需卸载样式 */ -export const removeStyle = (el: HTMLElement, styles: string[]) => { +export const removeStyle = ( + el: HTMLElement, + styles: K[], +) => { if (el) { - styles.forEach((item) => { - el.style[item] = null + styles.forEach((curr) => { + el.style.removeProperty(curr) }) } } @@ -259,7 +262,10 @@ export const getElement = (element: string) => { export const completeSize = (size: number | string, unit = 'px') => { if (typeof size === 'number') { return size.toString() + unit - } else if (isValueType(size, 'String') && ELEMENT_UNIT.test(size)) { + } else if ( + isValueType(size, 'String') && + APP_REGEX.validerCSSUnit.test(size) + ) { return size } else { return size + unit