diff --git a/.prettierrc b/.prettierrc
index f3d6ad5..7af6cc9 100644
--- a/.prettierrc
+++ b/.prettierrc
@@ -1,7 +1,7 @@
{
"printWidth": 100,
- "tabWidth": 2,
- "useTabs": false,
+ "tabWidth": 4,
+ "useTabs": true,
"semi": false,
"vueIndentScriptAndStyle": true,
"singleQuote": true,
diff --git a/.stylelintrc.cjs b/.stylelintrc.cjs
index 9dbea0b..cf344d4 100644
--- a/.stylelintrc.cjs
+++ b/.stylelintrc.cjs
@@ -1,82 +1,82 @@
module.exports = {
- // 继承推荐规范配置
- extends: [
- 'stylelint-config-standard',
- 'stylelint-config-recommended-scss',
- 'stylelint-config-recommended-vue/scss',
- 'stylelint-config-html/vue',
- 'stylelint-config-recess-order'
- ],
- // 指定不同文件对应的解析器
- overrides: [
- {
- files: ['**/*.{vue,html}'],
- customSyntax: 'postcss-html'
- },
- {
- files: ['**/*.{css,scss}'],
- customSyntax: 'postcss-scss'
- }
- ],
- // 自定义规则
- rules: {
- 'import-notation': 'string', // 指定导入CSS文件的方式("string"|"url")
- 'selector-class-pattern': null, // 选择器类名命名规则
- 'custom-property-pattern': null, // 自定义属性命名规则
- 'keyframes-name-pattern': null, // 动画帧节点样式命名规则
- 'no-descending-specificity': null, // 允许无降序特异性
- 'no-empty-source': null, // 允许空样式
- 'property-no-vendor-prefix': null, // 允许属性前缀
- // 允许 global 、export 、deep伪类
- 'selector-pseudo-class-no-unknown': [
- true,
- {
- ignorePseudoClasses: ['global', 'export', 'deep']
- }
- ],
- // 允许未知属性
- 'property-no-unknown': [
- true,
- {
- ignoreProperties: []
- }
- ],
- // 允许未知规则
- 'at-rule-no-unknown': [
- true,
- {
- ignoreAtRules: [
- 'apply',
- 'use',
- 'mixin',
- 'include',
- 'extend',
- 'each',
- 'if',
- 'else',
- 'for',
- 'while',
- 'reference'
- ]
- }
- ],
- 'scss/at-rule-no-unknown': [
- true,
- {
- ignoreAtRules: [
- 'apply',
- 'use',
- 'mixin',
- 'include',
- 'extend',
- 'each',
- 'if',
- 'else',
- 'for',
- 'while',
- 'reference'
- ]
- }
- ]
- }
+ // 继承推荐规范配置
+ extends: [
+ 'stylelint-config-standard',
+ 'stylelint-config-recommended-scss',
+ 'stylelint-config-recommended-vue/scss',
+ 'stylelint-config-html/vue',
+ 'stylelint-config-recess-order'
+ ],
+ // 指定不同文件对应的解析器
+ overrides: [
+ {
+ files: ['**/*.{vue,html}'],
+ customSyntax: 'postcss-html'
+ },
+ {
+ files: ['**/*.{css,scss}'],
+ customSyntax: 'postcss-scss'
+ }
+ ],
+ // 自定义规则
+ rules: {
+ 'import-notation': 'string', // 指定导入CSS文件的方式("string"|"url")
+ 'selector-class-pattern': null, // 选择器类名命名规则
+ 'custom-property-pattern': null, // 自定义属性命名规则
+ 'keyframes-name-pattern': null, // 动画帧节点样式命名规则
+ 'no-descending-specificity': null, // 允许无降序特异性
+ 'no-empty-source': null, // 允许空样式
+ 'property-no-vendor-prefix': null, // 允许属性前缀
+ // 允许 global 、export 、deep伪类
+ 'selector-pseudo-class-no-unknown': [
+ true,
+ {
+ ignorePseudoClasses: ['global', 'export', 'deep']
+ }
+ ],
+ // 允许未知属性
+ 'property-no-unknown': [
+ true,
+ {
+ ignoreProperties: []
+ }
+ ],
+ // 允许未知规则
+ 'at-rule-no-unknown': [
+ true,
+ {
+ ignoreAtRules: [
+ 'apply',
+ 'use',
+ 'mixin',
+ 'include',
+ 'extend',
+ 'each',
+ 'if',
+ 'else',
+ 'for',
+ 'while',
+ 'reference'
+ ]
+ }
+ ],
+ 'scss/at-rule-no-unknown': [
+ true,
+ {
+ ignoreAtRules: [
+ 'apply',
+ 'use',
+ 'mixin',
+ 'include',
+ 'extend',
+ 'each',
+ 'if',
+ 'else',
+ 'for',
+ 'while',
+ 'reference'
+ ]
+ }
+ ]
+ }
}
diff --git a/index.html b/index.html
index ba51ce5..9983b8c 100644
--- a/index.html
+++ b/index.html
@@ -1,47 +1,47 @@
-
- Art Design Pro
-
-
-
-
+
+ Art Design Pro
+
+
+
+
-
+ html.dark {
+ background-color: #070707;
+ }
+
-
-
+ const themeType = localStorage.getItem('sys-theme')
+ if (themeType === 'dark') {
+ document.documentElement.classList.add('dark')
+ }
+ } catch (e) {
+ console.warn('Failed to apply initial theme:', e)
+ }
+ })()
+
+
-
-
-
-
+
+
+
+
diff --git a/package.json b/package.json
index f1c5621..80da018 100644
--- a/package.json
+++ b/package.json
@@ -1,118 +1,108 @@
{
- "name": "art-design-pro",
- "version": "0.0.0",
- "type": "module",
- "engines": {
- "node": ">=20.19.0",
- "pnpm": ">=8.8.0"
- },
- "scripts": {
- "dev": "vite --open",
- "build": "vue-tsc --noEmit && vite build",
- "serve": "vite preview",
- "lint": "eslint",
- "fix": "eslint --fix",
- "lint:prettier": "prettier --write \"**/*.{js,cjs,ts,json,tsx,css,less,scss,vue,html,md}\"",
- "lint:stylelint": "stylelint \"**/*.{css,scss,vue}\" --fix",
- "lint:lint-staged": "lint-staged",
- "prepare": "husky",
- "commit": "git-cz",
- "clean:dev": "tsx scripts/clean-dev.ts"
- },
- "config": {
- "commitizen": {
- "path": "node_modules/cz-git"
- }
- },
- "lint-staged": {
- "*.{js,ts,mjs,mts,tsx}": [
- "eslint --fix",
- "prettier --write"
- ],
- "*.{cjs,json,jsonc}": [
- "prettier --write"
- ],
- "*.vue": [
- "eslint --fix",
- "stylelint --fix --allow-empty-input",
- "prettier --write"
- ],
- "*.{html,htm}": [
- "prettier --write"
- ],
- "*.{scss,css,less}": [
- "stylelint --fix --allow-empty-input",
- "prettier --write"
- ],
- "*.{md,mdx}": [
- "prettier --write"
- ],
- "*.{yaml,yml}": [
- "prettier --write"
- ]
- },
- "dependencies": {
- "@element-plus/icons-vue": "^2.3.2",
- "@iconify/vue": "^5.0.0",
- "@tailwindcss/vite": "^4.1.14",
- "@vue/reactivity": "^3.5.21",
- "@vueuse/core": "^13.9.0",
- "@wangeditor/editor": "^5.1.23",
- "@wangeditor/editor-for-vue": "next",
- "axios": "^1.12.2",
- "crypto-js": "^4.2.0",
- "echarts": "^6.0.0",
- "element-plus": "^2.11.2",
- "file-saver": "^2.0.5",
- "highlight.js": "^11.10.0",
- "mitt": "^3.0.1",
- "nprogress": "^0.2.0",
- "ohash": "^2.0.11",
- "pinia": "^3.0.3",
- "pinia-plugin-persistedstate": "^4.3.0",
- "qrcode.vue": "^3.6.0",
- "tailwindcss": "^4.1.14",
- "vue": "^3.5.21",
- "vue-draggable-plus": "^0.6.0",
- "vue-i18n": "^9.14.0",
- "vue-router": "^4.5.1",
- "xgplayer": "^3.0.20",
- "xlsx": "^0.18.5"
- },
- "devDependencies": {
- "@eslint/js": "^9.9.1",
- "@types/node": "^24.0.5",
- "@typescript-eslint/eslint-plugin": "^8.3.0",
- "@typescript-eslint/parser": "^8.3.0",
- "@vitejs/plugin-vue": "^6.0.1",
- "@vue/compiler-sfc": "^3.0.5",
- "eslint": "^9.9.1",
- "eslint-config-prettier": "^9.1.0",
- "eslint-plugin-prettier": "^5.2.1",
- "eslint-plugin-vue": "^9.27.0",
- "globals": "^15.9.0",
- "lint-staged": "^15.5.2",
- "prettier": "^3.5.3",
- "rollup-plugin-visualizer": "^5.12.0",
- "sass": "^1.81.0",
- "stylelint": "^16.20.0",
- "stylelint-config-html": "^1.1.0",
- "stylelint-config-recess-order": "^4.6.0",
- "stylelint-config-recommended-scss": "^14.1.0",
- "stylelint-config-recommended-vue": "^1.5.0",
- "stylelint-config-standard": "^36.0.1",
- "terser": "^5.36.0",
- "tsx": "^4.20.3",
- "typescript": "~5.6.3",
- "typescript-eslint": "^8.9.0",
- "unplugin-auto-import": "^20.2.0",
- "unplugin-element-plus": "^0.10.0",
- "unplugin-vue-components": "^29.1.0",
- "vite": "^7.1.5",
- "vite-plugin-compression": "^0.5.1",
- "vite-plugin-vue-devtools": "^7.7.6",
- "vue-demi": "^0.14.9",
- "vue-img-cutter": "^3.0.5",
- "vue-tsc": "~2.1.6"
- }
+ "name": "art-design-pro",
+ "version": "0.1.0",
+ "type": "module",
+ "engines": {
+ "node": ">=20.19.0"
+ },
+ "scripts": {
+ "dev": "vite --open",
+ "build": "vue-tsc --noEmit && vite build",
+ "serve": "vite preview",
+ "lint": "eslint",
+ "fix": "eslint --fix",
+ "lint:prettier": "prettier --write \"**/*.{js,cjs,ts,json,tsx,css,less,scss,vue,html,md}\"",
+ "lint:stylelint": "stylelint \"**/*.{css,scss,vue}\" --fix"
+ },
+ "lint-staged": {
+ "*.{js,ts,mjs,mts,tsx}": [
+ "eslint --fix",
+ "prettier --write"
+ ],
+ "*.{cjs,json,jsonc}": [
+ "prettier --write"
+ ],
+ "*.vue": [
+ "eslint --fix",
+ "stylelint --fix --allow-empty-input",
+ "prettier --write"
+ ],
+ "*.{html,htm}": [
+ "prettier --write"
+ ],
+ "*.{scss,css,less}": [
+ "stylelint --fix --allow-empty-input",
+ "prettier --write"
+ ],
+ "*.{md,mdx}": [
+ "prettier --write"
+ ],
+ "*.{yaml,yml}": [
+ "prettier --write"
+ ]
+ },
+ "dependencies": {
+ "@element-plus/icons-vue": "^2.3.2",
+ "@iconify/vue": "^5.0.0",
+ "@tailwindcss/vite": "^4.1.14",
+ "@vue/reactivity": "^3.5.21",
+ "@vueuse/core": "^13.9.0",
+ "@wangeditor/editor": "^5.1.23",
+ "@wangeditor/editor-for-vue": "next",
+ "axios": "^1.12.2",
+ "crypto-js": "^4.2.0",
+ "echarts": "^6.0.0",
+ "element-plus": "^2.11.2",
+ "file-saver": "^2.0.5",
+ "highlight.js": "^11.10.0",
+ "mitt": "^3.0.1",
+ "nprogress": "^0.2.0",
+ "ohash": "^2.0.11",
+ "pinia": "^3.0.3",
+ "pinia-plugin-persistedstate": "^4.3.0",
+ "qrcode.vue": "^3.6.0",
+ "tailwindcss": "^4.1.14",
+ "vue": "^3.5.21",
+ "vue-draggable-plus": "^0.6.0",
+ "vue-i18n": "^9.14.0",
+ "vue-router": "^4.5.1",
+ "xgplayer": "^3.0.20",
+ "xlsx": "^0.18.5"
+ },
+ "devDependencies": {
+ "@eslint/js": "^9.9.1",
+ "@types/node": "^24.0.5",
+ "@typescript-eslint/eslint-plugin": "^8.3.0",
+ "@typescript-eslint/parser": "^8.3.0",
+ "@vitejs/plugin-vue": "^6.0.1",
+ "@vue/compiler-sfc": "^3.0.5",
+ "eslint": "^9.9.1",
+ "eslint-config-prettier": "^9.1.0",
+ "eslint-plugin-prettier": "^5.2.1",
+ "eslint-plugin-vue": "^9.27.0",
+ "globals": "^15.9.0",
+ "lint-staged": "^15.5.2",
+ "prettier": "^3.5.3",
+ "rollup-plugin-visualizer": "^5.12.0",
+ "sass": "^1.81.0",
+ "stylelint": "^16.20.0",
+ "stylelint-config-html": "^1.1.0",
+ "stylelint-config-recess-order": "^4.6.0",
+ "stylelint-config-recommended-scss": "^14.1.0",
+ "stylelint-config-recommended-vue": "^1.5.0",
+ "stylelint-config-standard": "^36.0.1",
+ "terser": "^5.36.0",
+ "tsx": "^4.20.3",
+ "typescript": "~5.6.3",
+ "typescript-eslint": "^8.9.0",
+ "unplugin-auto-import": "^20.2.0",
+ "unplugin-element-plus": "^0.10.0",
+ "unplugin-vue-components": "^29.1.0",
+ "vite": "^7.1.5",
+ "vite-plugin-compression": "^0.5.1",
+ "vite-plugin-vue-devtools": "^7.7.6",
+ "vue-demi": "^0.14.9",
+ "vue-img-cutter": "^3.0.5",
+ "vue-tsc": "~2.1.6"
+ }
}
diff --git a/src/App.vue b/src/App.vue
index 3433913..2a4cef1 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -1,34 +1,34 @@
-
-
-
+
+
+
diff --git a/src/api/auth.ts b/src/api/auth.ts
index 9dc7b6a..e6a8de4 100644
--- a/src/api/auth.ts
+++ b/src/api/auth.ts
@@ -6,12 +6,12 @@ import request from '@/utils/http'
* @returns 登录响应
*/
export function fetchLogin(params: Api.Auth.LoginParams) {
- return request.post({
- url: '/api/auth/login',
- params
- // showSuccessMessage: true // 显示成功消息
- // showErrorMessage: false // 不显示错误消息
- })
+ return request.post({
+ url: '/api/auth/login',
+ params
+ // showSuccessMessage: true // 显示成功消息
+ // showErrorMessage: false // 不显示错误消息
+ })
}
/**
@@ -19,11 +19,11 @@ export function fetchLogin(params: Api.Auth.LoginParams) {
* @returns 用户信息
*/
export function fetchGetUserInfo() {
- return request.get({
- url: '/api/user/info'
- // 自定义请求头
- // headers: {
- // 'X-Custom-Header': 'your-custom-value'
- // }
- })
+ return request.get({
+ url: '/api/user/info'
+ // 自定义请求头
+ // headers: {
+ // 'X-Custom-Header': 'your-custom-value'
+ // }
+ })
}
diff --git a/src/api/system-manage.ts b/src/api/system-manage.ts
index 8f4a8e6..8bf9c68 100644
--- a/src/api/system-manage.ts
+++ b/src/api/system-manage.ts
@@ -3,23 +3,23 @@ import { AppRouteRecord } from '@/types/router'
// 获取用户列表
export function fetchGetUserList(params: Api.SystemManage.UserSearchParams) {
- return request.get({
- url: '/api/user/list',
- params
- })
+ return request.get({
+ url: '/api/user/list',
+ params
+ })
}
// 获取角色列表
export function fetchGetRoleList(params: Api.SystemManage.RoleSearchParams) {
- return request.get({
- url: '/api/role/list',
- params
- })
+ return request.get({
+ url: '/api/role/list',
+ params
+ })
}
// 获取菜单列表
export function fetchGetMenuList() {
- return request.get({
- url: '/api/v3/system/menus/simple'
- })
+ return request.get({
+ url: '/api/v3/system/menus/simple'
+ })
}
diff --git a/src/assets/styles/core/app.scss b/src/assets/styles/core/app.scss
index c0efeed..91283be 100644
--- a/src/assets/styles/core/app.scss
+++ b/src/assets/styles/core/app.scss
@@ -1,292 +1,292 @@
// 全局样式
// 顶部进度条颜色
#nprogress .bar {
- z-index: 2400;
- background-color: color-mix(in srgb, var(--theme-color) 70%, white);
+ z-index: 2400;
+ background-color: color-mix(in srgb, var(--theme-color) 70%, white);
}
#nprogress .peg {
- box-shadow:
- 0 0 10px var(--theme-color),
- 0 0 5px var(--theme-color) !important;
+ box-shadow:
+ 0 0 10px var(--theme-color),
+ 0 0 5px var(--theme-color) !important;
}
#nprogress .spinner-icon {
- border-top-color: var(--theme-color) !important;
- border-left-color: var(--theme-color) !important;
+ border-top-color: var(--theme-color) !important;
+ border-left-color: var(--theme-color) !important;
}
// 处理移动端组件兼容性
@media screen and (max-width: 640px) {
- * {
- cursor: default !important;
- }
+ * {
+ cursor: default !important;
+ }
}
// 背景滤镜
*,
::before,
::after {
- --tw-backdrop-blur: ;
- --tw-backdrop-brightness: ;
- --tw-backdrop-contrast: ;
- --tw-backdrop-grayscale: ;
- --tw-backdrop-hue-rotate: ;
- --tw-backdrop-invert: ;
- --tw-backdrop-opacity: ;
- --tw-backdrop-saturate: ;
- --tw-backdrop-sepia: ;
+ --tw-backdrop-blur: ;
+ --tw-backdrop-brightness: ;
+ --tw-backdrop-contrast: ;
+ --tw-backdrop-grayscale: ;
+ --tw-backdrop-hue-rotate: ;
+ --tw-backdrop-invert: ;
+ --tw-backdrop-opacity: ;
+ --tw-backdrop-saturate: ;
+ --tw-backdrop-sepia: ;
}
// 色弱模式
.color-weak {
- filter: invert(80%);
- -webkit-filter: invert(80%);
+ filter: invert(80%);
+ -webkit-filter: invert(80%);
}
#noop {
- display: none;
+ display: none;
}
// 语言切换选中样式
.langDropDownStyle {
- // 选中项背景颜色
- .is-selected {
- background-color: var(--art-el-active-color) !important;
- }
+ // 选中项背景颜色
+ .is-selected {
+ background-color: var(--art-el-active-color) !important;
+ }
- // 语言切换按钮菜单样式优化
- .lang-btn-item {
- .el-dropdown-menu__item {
- padding-left: 13px !important;
- padding-right: 6px !important;
- margin-bottom: 3px !important;
- }
+ // 语言切换按钮菜单样式优化
+ .lang-btn-item {
+ .el-dropdown-menu__item {
+ padding-left: 13px !important;
+ padding-right: 6px !important;
+ margin-bottom: 3px !important;
+ }
- &:last-child {
- .el-dropdown-menu__item {
- margin-bottom: 0 !important;
- }
- }
+ &:last-child {
+ .el-dropdown-menu__item {
+ margin-bottom: 0 !important;
+ }
+ }
- .menu-txt {
- min-width: 60px;
- display: block;
- }
+ .menu-txt {
+ min-width: 60px;
+ display: block;
+ }
- i {
- font-size: 10px;
- margin-left: 10px;
- }
- }
+ i {
+ font-size: 10px;
+ margin-left: 10px;
+ }
+ }
}
// 盒子默认边框
.page-content {
- border: 1px solid var(--art-card-border) !important;
+ border: 1px solid var(--art-card-border) !important;
}
@mixin art-card-base($border-color, $shadow: none, $radius-diff: 4px) {
- background: var(--default-box-color);
- border: 1px solid #{$border-color} !important;
- border-radius: calc(var(--custom-radius) + #{$radius-diff}) !important;
- box-shadow: #{$shadow} !important;
+ background: var(--default-box-color);
+ border: 1px solid #{$border-color} !important;
+ border-radius: calc(var(--custom-radius) + #{$radius-diff}) !important;
+ box-shadow: #{$shadow} !important;
- --el-card-border-color: var(--default-border) !important;
+ --el-card-border-color: var(--default-border) !important;
}
.art-card,
.art-card-sm,
.art-card-xs {
- border: 1px solid var(--art-card-border);
+ border: 1px solid var(--art-card-border);
}
// 盒子边框
[data-box-mode='border-mode'] {
- .page-content,
- .art-table-card {
- border: 1px solid var(--art-card-border) !important;
- }
+ .page-content,
+ .art-table-card {
+ border: 1px solid var(--art-card-border) !important;
+ }
- .art-card {
- @include art-card-base(var(--art-card-border), none, 4px);
- }
+ .art-card {
+ @include art-card-base(var(--art-card-border), none, 4px);
+ }
- .art-card-sm {
- @include art-card-base(var(--art-card-border), none, 0px);
- }
+ .art-card-sm {
+ @include art-card-base(var(--art-card-border), none, 0px);
+ }
- .art-card-xs {
- @include art-card-base(var(--art-card-border), none, -4px);
- }
+ .art-card-xs {
+ @include art-card-base(var(--art-card-border), none, -4px);
+ }
}
// 盒子阴影
[data-box-mode='shadow-mode'] {
- .page-content,
- .art-table-card {
- box-shadow: 0px 0px 4px 0px rgba(0, 0, 0, 0.04) !important;
- border: 1px solid var(--art-gray-200) !important;
- }
+ .page-content,
+ .art-table-card {
+ box-shadow: 0px 0px 4px 0px rgba(0, 0, 0, 0.04) !important;
+ border: 1px solid var(--art-gray-200) !important;
+ }
- .layout-sidebar {
- border-right: 1px solid var(--art-card-border) !important;
- }
+ .layout-sidebar {
+ border-right: 1px solid var(--art-card-border) !important;
+ }
- .art-card {
- @include art-card-base(
- var(--art-gray-200),
- (0 1px 3px 0 rgba(0, 0, 0, 0.03), 0 1px 2px -1px rgba(0, 0, 0, 0.08)),
- 4px
- );
- }
+ .art-card {
+ @include art-card-base(
+ var(--art-gray-200),
+ (0 1px 3px 0 rgba(0, 0, 0, 0.03), 0 1px 2px -1px rgba(0, 0, 0, 0.08)),
+ 4px
+ );
+ }
- .art-card-sm {
- @include art-card-base(
- var(--art-gray-200),
- (0 1px 3px 0 rgba(0, 0, 0, 0.03), 0 1px 2px -1px rgba(0, 0, 0, 0.08)),
- 2px
- );
- }
+ .art-card-sm {
+ @include art-card-base(
+ var(--art-gray-200),
+ (0 1px 3px 0 rgba(0, 0, 0, 0.03), 0 1px 2px -1px rgba(0, 0, 0, 0.08)),
+ 2px
+ );
+ }
- .art-card-xs {
- @include art-card-base(
- var(--art-gray-200),
- (0 1px 2px 0 rgba(0, 0, 0, 0.03), 0 1px 1px -1px rgba(0, 0, 0, 0.08)),
- -4px
- );
- }
+ .art-card-xs {
+ @include art-card-base(
+ var(--art-gray-200),
+ (0 1px 2px 0 rgba(0, 0, 0, 0.03), 0 1px 1px -1px rgba(0, 0, 0, 0.08)),
+ -4px
+ );
+ }
}
// 元素全屏
.el-full-screen {
- position: fixed;
- top: 0;
- left: 0;
- right: 0;
- width: 100vw !important;
- height: 100% !important;
- z-index: 2300;
- margin-top: 0;
- padding: 15px;
- box-sizing: border-box;
- background-color: var(--default-box-color);
- display: flex;
- flex-direction: column;
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ width: 100vw !important;
+ height: 100% !important;
+ z-index: 2300;
+ margin-top: 0;
+ padding: 15px;
+ box-sizing: border-box;
+ background-color: var(--default-box-color);
+ display: flex;
+ flex-direction: column;
}
// 表格卡片
.art-table-card {
- flex: 1;
- display: flex;
- flex-direction: column;
- margin-top: 12px;
- border-radius: calc(var(--custom-radius) / 2 + 2px) !important;
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ margin-top: 12px;
+ border-radius: calc(var(--custom-radius) / 2 + 2px) !important;
- .el-card__body {
- height: 100%;
- overflow: hidden;
- }
+ .el-card__body {
+ height: 100%;
+ overflow: hidden;
+ }
}
// 容器全高
.art-full-height {
- height: var(--art-full-height);
- display: flex;
- flex-direction: column;
+ height: var(--art-full-height);
+ display: flex;
+ flex-direction: column;
- @media (max-width: 640px) {
- height: auto;
- }
+ @media (max-width: 640px) {
+ height: auto;
+ }
}
// 徽章样式
.art-badge {
- position: absolute;
- top: 0;
- right: 20px;
- bottom: 0;
- width: 6px;
- height: 6px;
- margin: auto;
- background: #ff3860;
- border-radius: 50%;
- animation: breathe 1.5s ease-in-out infinite;
+ position: absolute;
+ top: 0;
+ right: 20px;
+ bottom: 0;
+ width: 6px;
+ height: 6px;
+ margin: auto;
+ background: #ff3860;
+ border-radius: 50%;
+ animation: breathe 1.5s ease-in-out infinite;
- &.art-badge-horizontal {
- right: 0;
- }
+ &.art-badge-horizontal {
+ right: 0;
+ }
- &.art-badge-mixed {
- right: 0;
- }
+ &.art-badge-mixed {
+ right: 0;
+ }
- &.art-badge-dual {
- right: 5px;
- top: 5px;
- bottom: auto;
- }
+ &.art-badge-dual {
+ right: 5px;
+ top: 5px;
+ bottom: auto;
+ }
}
// 文字徽章样式
.art-text-badge {
- position: absolute;
- top: 0;
- right: 12px;
- bottom: 0;
- min-width: 20px;
- height: 18px;
- line-height: 17px;
- padding: 0 5px;
- margin: auto;
- font-size: 10px;
- color: #fff;
- text-align: center;
- background: #fd4e4e;
- border-radius: 4px;
+ position: absolute;
+ top: 0;
+ right: 12px;
+ bottom: 0;
+ min-width: 20px;
+ height: 18px;
+ line-height: 17px;
+ padding: 0 5px;
+ margin: auto;
+ font-size: 10px;
+ color: #fff;
+ text-align: center;
+ background: #fd4e4e;
+ border-radius: 4px;
}
@keyframes breathe {
- 0% {
- opacity: 0.7;
- transform: scale(1);
- }
+ 0% {
+ opacity: 0.7;
+ transform: scale(1);
+ }
- 50% {
- opacity: 1;
- transform: scale(1.1);
- }
+ 50% {
+ opacity: 1;
+ transform: scale(1.1);
+ }
- 100% {
- opacity: 0.7;
- transform: scale(1);
- }
+ 100% {
+ opacity: 0.7;
+ transform: scale(1);
+ }
}
// 修复老机型 loading 定位问题
.art-loading-fix {
- position: fixed !important;
- top: 0 !important;
- left: 0 !important;
- right: 0 !important;
- bottom: 0 !important;
- width: 100vw !important;
- height: 100vh !important;
- display: flex !important;
- align-items: center !important;
- justify-content: center !important;
+ position: fixed !important;
+ top: 0 !important;
+ left: 0 !important;
+ right: 0 !important;
+ bottom: 0 !important;
+ width: 100vw !important;
+ height: 100vh !important;
+ display: flex !important;
+ align-items: center !important;
+ justify-content: center !important;
}
.art-loading-fix .el-loading-spinner {
- position: static !important;
- top: auto !important;
- left: auto !important;
- transform: none !important;
+ position: static !important;
+ top: auto !important;
+ left: auto !important;
+ transform: none !important;
}
// 去除移动端点击背景色
@media screen and (max-width: 1180px) {
- * {
- -webkit-tap-highlight-color: transparent;
- }
+ * {
+ -webkit-tap-highlight-color: transparent;
+ }
}
diff --git a/src/assets/styles/core/dark.scss b/src/assets/styles/core/dark.scss
index c52abc3..bbb53f2 100644
--- a/src/assets/styles/core/dark.scss
+++ b/src/assets/styles/core/dark.scss
@@ -7,87 +7,87 @@ $font-color: rgba(#ffffff, 0.85);
/* 覆盖element-plus默认深色背景色 */
html.dark {
- // element-plus
- --el-bg-color: var(--default-box-color);
- --el-text-color-regular: #{$font-color};
+ // element-plus
+ --el-bg-color: var(--default-box-color);
+ --el-text-color-regular: #{$font-color};
- // 富文本编辑器
- // 工具栏背景颜色
- --w-e-toolbar-bg-color: #18191c;
- // 输入区域背景颜色
- --w-e-textarea-bg-color: #090909;
- // 工具栏文字颜色
- --w-e-toolbar-color: var(--art-gray-600);
- // 选中菜单颜色
- --w-e-toolbar-active-bg-color: #25262b;
- // 弹窗边框颜色
- --w-e-toolbar-border-color: var(--default-border-dashed);
- // 分割线颜色
- --w-e-textarea-border-color: var(--default-border-dashed);
- // 链接输入框边框颜色
- --w-e-modal-button-border-color: var(--default-border-dashed);
- // 表格头颜色
- --w-e-textarea-slight-bg-color: #090909;
- // 按钮背景颜色
- --w-e-modal-button-bg-color: #090909;
- // hover toolbar 背景颜色
- --w-e-toolbar-active-color: var(--art-gray-800);
+ // 富文本编辑器
+ // 工具栏背景颜色
+ --w-e-toolbar-bg-color: #18191c;
+ // 输入区域背景颜色
+ --w-e-textarea-bg-color: #090909;
+ // 工具栏文字颜色
+ --w-e-toolbar-color: var(--art-gray-600);
+ // 选中菜单颜色
+ --w-e-toolbar-active-bg-color: #25262b;
+ // 弹窗边框颜色
+ --w-e-toolbar-border-color: var(--default-border-dashed);
+ // 分割线颜色
+ --w-e-textarea-border-color: var(--default-border-dashed);
+ // 链接输入框边框颜色
+ --w-e-modal-button-border-color: var(--default-border-dashed);
+ // 表格头颜色
+ --w-e-textarea-slight-bg-color: #090909;
+ // 按钮背景颜色
+ --w-e-modal-button-bg-color: #090909;
+ // hover toolbar 背景颜色
+ --w-e-toolbar-active-color: var(--art-gray-800);
}
.dark {
- .page-content .article-list .item .left .outer > div {
- border-right-color: var(--dark-border-color) !important;
- }
+ .page-content .article-list .item .left .outer > div {
+ border-right-color: var(--dark-border-color) !important;
+ }
- // 富文本编辑器
- .editor-wrapper {
- *:not(pre code *) {
- color: inherit !important;
- }
- }
- // 分隔线
- .w-e-bar-divider {
- background-color: var(--art-gray-300) !important;
- }
+ // 富文本编辑器
+ .editor-wrapper {
+ *:not(pre code *) {
+ color: inherit !important;
+ }
+ }
+ // 分隔线
+ .w-e-bar-divider {
+ background-color: var(--art-gray-300) !important;
+ }
- .w-e-select-list,
- .w-e-drop-panel,
- .w-e-bar-item-group .w-e-bar-item-menus-container,
- .w-e-text-container [data-slate-editor] pre > code {
- border: 1px solid var(--default-border) !important;
- }
+ .w-e-select-list,
+ .w-e-drop-panel,
+ .w-e-bar-item-group .w-e-bar-item-menus-container,
+ .w-e-text-container [data-slate-editor] pre > code {
+ border: 1px solid var(--default-border) !important;
+ }
- // 下拉选择框
- .w-e-select-list {
- background-color: var(--default-box-color) !important;
- }
+ // 下拉选择框
+ .w-e-select-list {
+ background-color: var(--default-box-color) !important;
+ }
- /* 下拉选择框 hover 样式调整 */
- .w-e-select-list ul li:hover,
+ /* 下拉选择框 hover 样式调整 */
+ .w-e-select-list ul li:hover,
/* 工具栏 hover 按钮背景颜色 */
.w-e-bar-item button:hover {
- background-color: #090909 !important;
- }
+ background-color: #090909 !important;
+ }
- /* 代码块 */
- .w-e-text-container [data-slate-editor] pre > code {
- background-color: #25262b !important;
- text-shadow: none !important;
- }
+ /* 代码块 */
+ .w-e-text-container [data-slate-editor] pre > code {
+ background-color: #25262b !important;
+ text-shadow: none !important;
+ }
- /* 引用 */
- .w-e-text-container [data-slate-editor] blockquote {
- border-left: 4px solid var(--default-border-dashed) !important;
- background-color: var(--art-color);
- }
+ /* 引用 */
+ .w-e-text-container [data-slate-editor] blockquote {
+ border-left: 4px solid var(--default-border-dashed) !important;
+ background-color: var(--art-color);
+ }
- .editor-wrapper {
- .w-e-text-container [data-slate-editor] .table-container th:last-of-type {
- border-right: 1px solid var(--default-border-dashed) !important;
- }
+ .editor-wrapper {
+ .w-e-text-container [data-slate-editor] .table-container th:last-of-type {
+ border-right: 1px solid var(--default-border-dashed) !important;
+ }
- .w-e-modal {
- background-color: var(--art-color);
- }
- }
+ .w-e-modal {
+ background-color: var(--art-color);
+ }
+ }
}
diff --git a/src/assets/styles/core/el-light.scss b/src/assets/styles/core/el-light.scss
index ddf2bc5..73a5117 100644
--- a/src/assets/styles/core/el-light.scss
+++ b/src/assets/styles/core/el-light.scss
@@ -2,33 +2,33 @@
// 自定义Element 亮色主题
@forward 'element-plus/theme-chalk/src/common/var.scss' with (
- $colors: (
- 'white': #ffffff,
- 'black': #000000,
- 'success': (
- 'base': #13deb9
- ),
- 'warning': (
- 'base': #ffae1f
- ),
- 'danger': (
- 'base': #ff4d4f
- ),
- 'error': (
- 'base': #fa896b
- )
- ),
- $button: (
- 'hover-bg-color': var(--el-color-primary-light-9),
- 'hover-border-color': var(--el-color-primary),
- 'border-color': var(--el-color-primary),
- 'text-color': var(--el-color-primary)
- ),
- $messagebox: (
- 'border-radius': '12px'
- ),
- $popover: (
- 'padding': '14px',
- 'border-radius': '10px'
- )
+ $colors: (
+ 'white': #ffffff,
+ 'black': #000000,
+ 'success': (
+ 'base': #13deb9
+ ),
+ 'warning': (
+ 'base': #ffae1f
+ ),
+ 'danger': (
+ 'base': #ff4d4f
+ ),
+ 'error': (
+ 'base': #fa896b
+ )
+ ),
+ $button: (
+ 'hover-bg-color': var(--el-color-primary-light-9),
+ 'hover-border-color': var(--el-color-primary),
+ 'border-color': var(--el-color-primary),
+ 'text-color': var(--el-color-primary)
+ ),
+ $messagebox: (
+ 'border-radius': '12px'
+ ),
+ $popover: (
+ 'padding': '14px',
+ 'border-radius': '10px'
+ )
);
diff --git a/src/assets/styles/core/el-ui.scss b/src/assets/styles/core/el-ui.scss
index 44429a1..cb50356 100644
--- a/src/assets/styles/core/el-ui.scss
+++ b/src/assets/styles/core/el-ui.scss
@@ -1,519 +1,519 @@
// 优化 Element Plus 组件库默认样式
:root {
- // 系统主色
- --main-color: var(--el-color-primary);
- --el-color-white: white !important;
- --el-color-black: white !important;
- // 输入框边框颜色
- // --el-border-color: #E4E4E7 !important; // DCDFE6
- // 按钮粗度
- --el-font-weight-primary: 400 !important;
+ // 系统主色
+ --main-color: var(--el-color-primary);
+ --el-color-white: white !important;
+ --el-color-black: white !important;
+ // 输入框边框颜色
+ // --el-border-color: #E4E4E7 !important; // DCDFE6
+ // 按钮粗度
+ --el-font-weight-primary: 400 !important;
- --el-component-custom-height: 36px !important;
+ --el-component-custom-height: 36px !important;
- --el-component-size: var(--el-component-custom-height) !important;
+ --el-component-size: var(--el-component-custom-height) !important;
- // 边框、按钮圆角...
- --el-border-radius-base: calc(var(--custom-radius) / 3 + 2px) !important;
+ // 边框、按钮圆角...
+ --el-border-radius-base: calc(var(--custom-radius) / 3 + 2px) !important;
- --el-border-radius-small: calc(var(--custom-radius) / 3 + 4px) !important;
- --el-messagebox-border-radius: calc(var(--custom-radius) / 3 + 4px) !important;
- --el-popover-border-radius: calc(var(--custom-radius) / 3 + 4px) !important;
+ --el-border-radius-small: calc(var(--custom-radius) / 3 + 4px) !important;
+ --el-messagebox-border-radius: calc(var(--custom-radius) / 3 + 4px) !important;
+ --el-popover-border-radius: calc(var(--custom-radius) / 3 + 4px) !important;
- .region .el-radio-button__original-radio:checked + .el-radio-button__inner {
- color: var(--theme-color);
- }
+ .region .el-radio-button__original-radio:checked + .el-radio-button__inner {
+ color: var(--theme-color);
+ }
}
// 优化 el-form-item 标签高度
.el-form-item__label {
- height: var(--el-component-custom-height) !important;
- line-height: var(--el-component-custom-height) !important;
+ height: var(--el-component-custom-height) !important;
+ line-height: var(--el-component-custom-height) !important;
}
// 日期选择器
.el-date-range-picker {
- --el-datepicker-inrange-bg-color: var(--art-gray-200) !important;
+ --el-datepicker-inrange-bg-color: var(--art-gray-200) !important;
}
// el-card 背景色跟系统背景色保持一致
html.dark .el-card {
- --el-card-bg-color: var(--default-box-color) !important;
+ --el-card-bg-color: var(--default-box-color) !important;
}
// 修改 el-pagination 大小
.el-pagination--default {
- & {
- --el-pagination-button-width: 32px !important;
- --el-pagination-button-height: var(--el-pagination-button-width) !important;
- }
+ & {
+ --el-pagination-button-width: 32px !important;
+ --el-pagination-button-height: var(--el-pagination-button-width) !important;
+ }
- @media (max-width: 1180px) {
- & {
- --el-pagination-button-width: 28px !important;
- }
- }
+ @media (max-width: 1180px) {
+ & {
+ --el-pagination-button-width: 28px !important;
+ }
+ }
- .el-select--default .el-select__wrapper {
- min-height: var(--el-pagination-button-width) !important;
- }
+ .el-select--default .el-select__wrapper {
+ min-height: var(--el-pagination-button-width) !important;
+ }
- .el-pagination__jump .el-input {
- height: var(--el-pagination-button-width) !important;
- }
+ .el-pagination__jump .el-input {
+ height: var(--el-pagination-button-width) !important;
+ }
}
.el-pager li {
- padding: 0 10px !important;
- // border: 1px solid red !important;
+ padding: 0 10px !important;
+ // border: 1px solid red !important;
}
// 优化菜单折叠展开动画(提升动画流畅度)
.el-menu.el-menu--inline {
- transition: max-height 0.26s cubic-bezier(0.4, 0, 0.2, 1) !important;
+ transition: max-height 0.26s cubic-bezier(0.4, 0, 0.2, 1) !important;
}
// 优化菜单 item hover 动画(提升鼠标跟手感)
.el-sub-menu__title,
.el-menu-item {
- transition: background-color 0s !important;
+ transition: background-color 0s !important;
}
// -------------------------------- 修改 el-size=default 组件默认高度 start --------------------------------
// 修改 el-button 高度
.el-button--default {
- height: var(--el-component-custom-height) !important;
+ height: var(--el-component-custom-height) !important;
}
// circle 按钮宽度优化
.el-button--default.is-circle {
- width: var(--el-component-custom-height) !important;
+ width: var(--el-component-custom-height) !important;
}
// 修改 el-select 高度
.el-select--default {
- .el-select__wrapper {
- min-height: var(--el-component-custom-height) !important;
- }
+ .el-select__wrapper {
+ min-height: var(--el-component-custom-height) !important;
+ }
}
// 修改 el-checkbox-button 高度
.el-checkbox-button--default .el-checkbox-button__inner,
// 修改 el-radio-button 高度
.el-radio-button--default .el-radio-button__inner {
- padding: 10px 15px !important;
+ padding: 10px 15px !important;
}
// -------------------------------- 修改 el-size=default 组件默认高度 end --------------------------------
.el-pagination.is-background .btn-next,
.el-pagination.is-background .btn-prev,
.el-pagination.is-background .el-pager li {
- border-radius: 6px;
+ border-radius: 6px;
}
.el-popover {
- min-width: 80px;
- border-radius: var(--el-border-radius-small) !important;
+ min-width: 80px;
+ border-radius: var(--el-border-radius-small) !important;
}
.el-dialog {
- border-radius: 100px !important;
- border-radius: calc(var(--custom-radius) / 1.2 + 2px) !important;
- overflow: hidden;
+ border-radius: 100px !important;
+ border-radius: calc(var(--custom-radius) / 1.2 + 2px) !important;
+ overflow: hidden;
}
.el-dialog__header {
- .el-dialog__title {
- font-size: 16px;
- }
+ .el-dialog__title {
+ font-size: 16px;
+ }
}
.el-dialog__body {
- padding: 25px 0 !important;
- position: relative; // 为了兼容 el-pagination 样式,需要设置 relative,不然会影响 el-pagination 的样式,比如 el-pagination__jump--small 会被影响,导致 el-pagination__jump--small 按钮无法点击,详见 URL_ADDRESS.com/element-plus/element-plus/issues/5684#issuecomment-1176299275;
+ padding: 25px 0 !important;
+ position: relative; // 为了兼容 el-pagination 样式,需要设置 relative,不然会影响 el-pagination 的样式,比如 el-pagination__jump--small 会被影响,导致 el-pagination__jump--small 按钮无法点击,详见 URL_ADDRESS.com/element-plus/element-plus/issues/5684#issuecomment-1176299275;
}
.el-dialog.el-dialog-border {
- .el-dialog__body {
- // 上边框
- &::before,
+ .el-dialog__body {
+ // 上边框
+ &::before,
// 下边框
&::after {
- content: '';
- position: absolute;
- left: -16px;
- width: calc(100% + 32px);
- height: 1px;
- background-color: var(--art-gray-300);
- }
+ content: '';
+ position: absolute;
+ left: -16px;
+ width: calc(100% + 32px);
+ height: 1px;
+ background-color: var(--art-gray-300);
+ }
- &::before {
- top: 0;
- }
+ &::before {
+ top: 0;
+ }
- &::after {
- bottom: 0;
- }
- }
+ &::after {
+ bottom: 0;
+ }
+ }
}
// el-message 样式优化
.el-message {
- background-color: var(--default-box-color) !important;
- border: 0 !important;
- box-shadow:
- 0 6px 16px 0 rgba(0, 0, 0, 0.08),
- 0 3px 6px -4px rgba(0, 0, 0, 0.12),
- 0 9px 28px 8px rgba(0, 0, 0, 0.05) !important;
+ background-color: var(--default-box-color) !important;
+ border: 0 !important;
+ box-shadow:
+ 0 6px 16px 0 rgba(0, 0, 0, 0.08),
+ 0 3px 6px -4px rgba(0, 0, 0, 0.12),
+ 0 9px 28px 8px rgba(0, 0, 0, 0.05) !important;
- p {
- font-size: 13px;
- }
+ p {
+ font-size: 13px;
+ }
}
// 修改 el-dropdown 样式
.el-dropdown-menu {
- padding: 6px !important;
- border-radius: 10px !important;
- border: none !important;
+ padding: 6px !important;
+ border-radius: 10px !important;
+ border: none !important;
- .el-dropdown-menu__item {
- padding: 6px 16px !important;
- border-radius: 6px !important;
+ .el-dropdown-menu__item {
+ padding: 6px 16px !important;
+ border-radius: 6px !important;
- &:hover:not(.is-disabled) {
- color: var(--art-gray-900) !important;
- background-color: var(--art-el-active-color) !important;
- }
+ &:hover:not(.is-disabled) {
+ color: var(--art-gray-900) !important;
+ background-color: var(--art-el-active-color) !important;
+ }
- &:focus:not(.is-disabled) {
- color: var(--art-gray-900) !important;
- background-color: var(--art-gray-200) !important;
- }
- }
+ &:focus:not(.is-disabled) {
+ color: var(--art-gray-900) !important;
+ background-color: var(--art-gray-200) !important;
+ }
+ }
}
// 隐藏 select、dropdown 的三角
.el-select__popper,
.el-dropdown__popper {
- margin-top: -6px !important;
+ margin-top: -6px !important;
- .el-popper__arrow {
- display: none;
- }
+ .el-popper__arrow {
+ display: none;
+ }
}
.el-dropdown-selfdefine:focus {
- outline: none !important;
+ outline: none !important;
}
// 处理移动端组件兼容性
@media screen and (max-width: 640px) {
- .el-message-box,
- .el-dialog {
- width: calc(100% - 24px) !important;
- }
+ .el-message-box,
+ .el-dialog {
+ width: calc(100% - 24px) !important;
+ }
- .el-date-picker.has-sidebar.has-time {
- width: calc(100% - 24px);
- left: 12px !important;
- }
+ .el-date-picker.has-sidebar.has-time {
+ width: calc(100% - 24px);
+ left: 12px !important;
+ }
- .el-picker-panel *[slot='sidebar'],
- .el-picker-panel__sidebar {
- display: none;
- }
+ .el-picker-panel *[slot='sidebar'],
+ .el-picker-panel__sidebar {
+ display: none;
+ }
- .el-picker-panel *[slot='sidebar'] + .el-picker-panel__body,
- .el-picker-panel__sidebar + .el-picker-panel__body {
- margin-left: 0;
- }
+ .el-picker-panel *[slot='sidebar'] + .el-picker-panel__body,
+ .el-picker-panel__sidebar + .el-picker-panel__body {
+ margin-left: 0;
+ }
}
// 修改el-button样式
.el-button {
- &.el-button--text {
- background-color: transparent !important;
- padding: 0 !important;
+ &.el-button--text {
+ background-color: transparent !important;
+ padding: 0 !important;
- span {
- margin-left: 0 !important;
- }
- }
+ span {
+ margin-left: 0 !important;
+ }
+ }
}
// 修改el-tag样式
.el-tag {
- font-weight: 500;
- transition: all 0s !important;
+ font-weight: 500;
+ transition: all 0s !important;
- &.el-tag--default {
- height: 26px !important;
- }
+ &.el-tag--default {
+ height: 26px !important;
+ }
}
.el-checkbox-group {
- &.el-table-filter__checkbox-group label.el-checkbox {
- height: 17px !important;
+ &.el-table-filter__checkbox-group label.el-checkbox {
+ height: 17px !important;
- .el-checkbox__label {
- font-weight: 400 !important;
- }
- }
+ .el-checkbox__label {
+ font-weight: 400 !important;
+ }
+ }
}
.el-radio--default {
- // 优化单选按钮大小
- .el-radio__input {
- .el-radio__inner {
- width: 16px;
- height: 16px;
+ // 优化单选按钮大小
+ .el-radio__input {
+ .el-radio__inner {
+ width: 16px;
+ height: 16px;
- &::after {
- width: 6px;
- height: 6px;
- }
- }
- }
+ &::after {
+ width: 6px;
+ height: 6px;
+ }
+ }
+ }
}
.el-checkbox {
- .el-checkbox__inner {
- border-radius: 2px !important;
- }
+ .el-checkbox__inner {
+ border-radius: 2px !important;
+ }
}
// 优化复选框样式
.el-checkbox--default {
- .el-checkbox__inner {
- width: 16px !important;
- height: 16px !important;
- border-radius: 4px !important;
+ .el-checkbox__inner {
+ width: 16px !important;
+ height: 16px !important;
+ border-radius: 4px !important;
- &::before {
- content: '';
- height: 4px !important;
- top: 5px !important;
- background-color: #fff !important;
- transform: scale(0.6) !important;
- }
- }
+ &::before {
+ content: '';
+ height: 4px !important;
+ top: 5px !important;
+ background-color: #fff !important;
+ transform: scale(0.6) !important;
+ }
+ }
- .is-checked {
- .el-checkbox__inner {
- &::after {
- width: 3px;
- height: 8px;
- margin: auto;
- border: 2px solid var(--el-checkbox-checked-icon-color);
- border-left: 0;
- border-top: 0;
- transform: translate(-45%, -60%) rotate(45deg) scale(0.86) !important;
- transform-origin: center;
- }
- }
- }
+ .is-checked {
+ .el-checkbox__inner {
+ &::after {
+ width: 3px;
+ height: 8px;
+ margin: auto;
+ border: 2px solid var(--el-checkbox-checked-icon-color);
+ border-left: 0;
+ border-top: 0;
+ transform: translate(-45%, -60%) rotate(45deg) scale(0.86) !important;
+ transform-origin: center;
+ }
+ }
+ }
}
.el-notification .el-notification__icon {
- font-size: 22px !important;
+ font-size: 22px !important;
}
// 修改 el-message-box 样式
.el-message-box__headerbtn .el-message-box__close,
.el-dialog__headerbtn .el-dialog__close {
- top: 7px;
- right: 7px;
- width: 30px;
- height: 30px;
- border-radius: 5px;
- transition: all 0.3s;
+ top: 7px;
+ right: 7px;
+ width: 30px;
+ height: 30px;
+ border-radius: 5px;
+ transition: all 0.3s;
- &:hover {
- background-color: var(--art-hover-color) !important;
- color: var(--art-gray-900) !important;
- }
+ &:hover {
+ background-color: var(--art-hover-color) !important;
+ color: var(--art-gray-900) !important;
+ }
}
.el-message-box {
- padding: 25px 20px !important;
+ padding: 25px 20px !important;
}
.el-message-box__title {
- font-weight: 500 !important;
+ font-weight: 500 !important;
}
.el-table__column-filter-trigger i {
- color: var(--theme-color) !important;
- margin: -3px 0 0 2px;
+ color: var(--theme-color) !important;
+ margin: -3px 0 0 2px;
}
// 去除 el-dropdown 鼠标放上去出现的边框
.el-tooltip__trigger:focus-visible {
- outline: unset;
+ outline: unset;
}
// ipad 表单右侧按钮优化
@media screen and (max-width: 1180px) {
- .el-table-fixed-column--right {
- padding-right: 0 !important;
- }
+ .el-table-fixed-column--right {
+ padding-right: 0 !important;
+ }
}
.login-out-dialog {
- padding: 30px 20px !important;
- border-radius: 10px !important;
+ padding: 30px 20px !important;
+ border-radius: 10px !important;
}
// 修改 dialog 动画
.dialog-fade-enter-active {
- .el-dialog:not(.is-draggable) {
- animation: dialog-open 0.3s cubic-bezier(0.32, 0.14, 0.15, 0.86);
+ .el-dialog:not(.is-draggable) {
+ animation: dialog-open 0.3s cubic-bezier(0.32, 0.14, 0.15, 0.86);
- // 修复 el-dialog 动画后宽度不自适应问题
- .el-select__selected-item {
- display: inline-block;
- }
- }
+ // 修复 el-dialog 动画后宽度不自适应问题
+ .el-select__selected-item {
+ display: inline-block;
+ }
+ }
}
.dialog-fade-leave-active {
- animation: fade-out 0.2s linear;
+ animation: fade-out 0.2s linear;
- .el-dialog:not(.is-draggable) {
- animation: dialog-close 0.5s;
- }
+ .el-dialog:not(.is-draggable) {
+ animation: dialog-close 0.5s;
+ }
}
@keyframes dialog-open {
- 0% {
- opacity: 0;
- transform: scale(0.2);
- }
+ 0% {
+ opacity: 0;
+ transform: scale(0.2);
+ }
- 100% {
- opacity: 1;
- transform: scale(1);
- }
+ 100% {
+ opacity: 1;
+ transform: scale(1);
+ }
}
@keyframes dialog-close {
- 0% {
- opacity: 1;
- transform: scale(1);
- }
+ 0% {
+ opacity: 1;
+ transform: scale(1);
+ }
- 100% {
- opacity: 0;
- transform: scale(0.2);
- }
+ 100% {
+ opacity: 0;
+ transform: scale(0.2);
+ }
}
// 遮罩层动画
@keyframes fade-out {
- 0% {
- opacity: 1;
- }
+ 0% {
+ opacity: 1;
+ }
- 100% {
- opacity: 0;
- }
+ 100% {
+ opacity: 0;
+ }
}
// 修改 el-select 样式
.el-select__popper:not(.el-tree-select__popper) {
- .el-select-dropdown__list {
- padding: 5px !important;
+ .el-select-dropdown__list {
+ padding: 5px !important;
- .el-select-dropdown__item {
- height: 34px !important;
- line-height: 34px !important;
- border-radius: 6px !important;
+ .el-select-dropdown__item {
+ height: 34px !important;
+ line-height: 34px !important;
+ border-radius: 6px !important;
- &.is-selected {
- color: var(--art-gray-900) !important;
- font-weight: 400 !important;
- background-color: var(--art-el-active-color) !important;
- margin-bottom: 4px !important;
- }
+ &.is-selected {
+ color: var(--art-gray-900) !important;
+ font-weight: 400 !important;
+ background-color: var(--art-el-active-color) !important;
+ margin-bottom: 4px !important;
+ }
- &:hover {
- background-color: var(--art-hover-color) !important;
- }
- }
+ &:hover {
+ background-color: var(--art-hover-color) !important;
+ }
+ }
- .el-select-dropdown__item:hover ~ .is-selected,
- .el-select-dropdown__item.is-selected:has(~ .el-select-dropdown__item:hover) {
- background-color: transparent !important;
- }
- }
+ .el-select-dropdown__item:hover ~ .is-selected,
+ .el-select-dropdown__item.is-selected:has(~ .el-select-dropdown__item:hover) {
+ background-color: transparent !important;
+ }
+ }
}
// 修改 el-tree-select 样式
.el-tree-select__popper {
- .el-select-dropdown__list {
- padding: 5px !important;
+ .el-select-dropdown__list {
+ padding: 5px !important;
- .el-tree-node {
- .el-tree-node__content {
- height: 36px !important;
- border-radius: 6px !important;
+ .el-tree-node {
+ .el-tree-node__content {
+ height: 36px !important;
+ border-radius: 6px !important;
- &:hover {
- background-color: var(--art-gray-200) !important;
- }
- }
- }
- }
+ &:hover {
+ background-color: var(--art-gray-200) !important;
+ }
+ }
+ }
+ }
}
// 实现水波纹在文字下面效果
.el-button > span {
- position: relative;
- z-index: 10;
+ position: relative;
+ z-index: 10;
}
// 优化颜色选择器圆角
.el-color-picker__color {
- border-radius: 2px !important;
+ border-radius: 2px !important;
}
// 优化日期时间选择器底部圆角
.el-picker-panel {
- .el-picker-panel__footer {
- border-radius: 0 0 var(--el-border-radius-base) var(--el-border-radius-base);
- }
+ .el-picker-panel__footer {
+ border-radius: 0 0 var(--el-border-radius-base) var(--el-border-radius-base);
+ }
}
// 优化树型菜单样式
.el-tree-node__content {
- border-radius: 4px;
- margin-bottom: 4px;
- padding: 1px 0;
+ border-radius: 4px;
+ margin-bottom: 4px;
+ padding: 1px 0;
- &:hover {
- background-color: var(--art-hover-color) !important;
- }
+ &:hover {
+ background-color: var(--art-hover-color) !important;
+ }
}
.dark {
- .el-tree--highlight-current .el-tree-node.is-current > .el-tree-node__content {
- background-color: var(--art-gray-300) !important;
- }
+ .el-tree--highlight-current .el-tree-node.is-current > .el-tree-node__content {
+ background-color: var(--art-gray-300) !important;
+ }
}
// 隐藏折叠菜单弹窗 hover 出现的边框
.menu-left-popper:focus-within,
.horizontal-menu-popper:focus-within {
- box-shadow: none !important;
- outline: none !important;
+ box-shadow: none !important;
+ outline: none !important;
}
// 数字输入组件右侧按钮高度跟随自定义组件高度
.el-input-number--default.is-controls-right {
- .el-input-number__decrease,
- .el-input-number__increase {
- height: calc((var(--el-component-size) / 2)) !important;
- }
+ .el-input-number__decrease,
+ .el-input-number__increase {
+ height: calc((var(--el-component-size) / 2)) !important;
+ }
}
diff --git a/src/assets/styles/core/md.scss b/src/assets/styles/core/md.scss
index b22fdc2..c92fea5 100644
--- a/src/assets/styles/core/md.scss
+++ b/src/assets/styles/core/md.scss
@@ -8,152 +8,152 @@ $font-color: #24292e;
.markdown-body h4,
.markdown-body h5,
.markdown-body h6 {
- color: var(--art-gray-800) !important;
- margin: 30px 0 10px 0;
- font-weight: 600;
+ color: var(--art-gray-800) !important;
+ margin: 30px 0 10px 0;
+ font-weight: 600;
}
.markdown-body h1 {
- font-size: 30px;
+ font-size: 30px;
}
@media only screen and (max-width: 550px) {
- .markdown-body h1 {
- font-size: 26px;
- }
+ .markdown-body h1 {
+ font-size: 26px;
+ }
- .markdown-body h2 {
- font-size: 22px;
- }
+ .markdown-body h2 {
+ font-size: 22px;
+ }
- .markdown-body h3 {
- font-size: 18px;
- }
+ .markdown-body h3 {
+ font-size: 18px;
+ }
}
/* 块引用 */
/* ------------------------------------------------ */
.markdown-body blockquote {
- color: rgba(60, 60, 67, 0.7);
- font-size: 15px !important;
- border-left: 0.18em solid #e7e7e8;
- background: #f8f8f8;
- padding: 15px 1em;
- font-weight: 400 !important;
+ color: rgba(60, 60, 67, 0.7);
+ font-size: 15px !important;
+ border-left: 0.18em solid #e7e7e8;
+ background: #f8f8f8;
+ padding: 15px 1em;
+ font-weight: 400 !important;
}
/* 详情页文章字体颜色 */
/* ------------------------------------------------ */
.markdown-body p {
- line-height: 28px;
- margin-bottom: 10px;
+ line-height: 28px;
+ margin-bottom: 10px;
}
.markdown-body li,
.markdown-body p {
- color: var(--art-gray-800) !important;
- font-size: 16px !important;
+ color: var(--art-gray-800) !important;
+ font-size: 16px !important;
}
.dark .markdown-body li span {
- color: var(--art-gray-800) !important;
- background-color: transparent !important;
+ color: var(--art-gray-800) !important;
+ background-color: transparent !important;
}
.dark .markdown-body p span {
- color: var(--art-gray-800) !important;
- background-color: transparent !important;
+ color: var(--art-gray-800) !important;
+ background-color: transparent !important;
}
.line-numbers-mode {
- background-color: var(--art-code-bg);
- border-radius: 8px;
- position: relative;
- padding-left: 32px;
- box-sizing: border-box;
+ background-color: var(--art-code-bg);
+ border-radius: 8px;
+ position: relative;
+ padding-left: 32px;
+ box-sizing: border-box;
}
.line-numbers-mode pre {
- flex: 1;
- border-radius: 0 8px 8px 0;
- background-color: var(--art-code-bg);
+ flex: 1;
+ border-radius: 0 8px 8px 0;
+ background-color: var(--art-code-bg);
}
.line-numbers-mode .line-numbers-wrapper {
- width: 32px;
- height: 100%;
- text-align: center;
- padding: 16px 0;
- box-sizing: border-box;
- border-right: 1px solid #000000;
- position: absolute;
- left: 0;
- top: 0;
+ width: 32px;
+ height: 100%;
+ text-align: center;
+ padding: 16px 0;
+ box-sizing: border-box;
+ border-right: 1px solid #000000;
+ position: absolute;
+ left: 0;
+ top: 0;
}
.line-numbers-mode .line-numbers-wrapper span {
- height: 23.6px;
- line-height: 23.6px;
- display: block;
- color: #72747b;
- font-size: 13px;
- box-sizing: border-box;
+ height: 23.6px;
+ line-height: 23.6px;
+ display: block;
+ color: #72747b;
+ font-size: 13px;
+ box-sizing: border-box;
}
.line-numbers-mode .copy-btn {
- display: inline-block;
- display: flex;
- position: absolute;
- right: 10px;
- top: 10px;
- cursor: pointer;
- opacity: 0;
- background-color: #000;
- border-radius: 5px;
- text-align: center;
- color: rgba(255, 255, 255, 0.6);
- transition: opacity 0.3s;
+ display: inline-block;
+ display: flex;
+ position: absolute;
+ right: 10px;
+ top: 10px;
+ cursor: pointer;
+ opacity: 0;
+ background-color: #000;
+ border-radius: 5px;
+ text-align: center;
+ color: rgba(255, 255, 255, 0.6);
+ transition: opacity 0.3s;
}
.line-numbers-mode .copy-btn div {
- width: 34px;
- height: 34px;
- line-height: 34px;
- cursor: pointer;
- text-align: center;
- font-size: 20px;
+ width: 34px;
+ height: 34px;
+ line-height: 34px;
+ cursor: pointer;
+ text-align: center;
+ font-size: 20px;
}
.line-numbers-mode:hover .copy-btn {
- opacity: 1;
+ opacity: 1;
}
.line-numbers-mode .copy-btn span {
- height: 34px;
- line-height: 34px;
- font-size: 13px;
- padding-left: 10px;
- display: none;
+ height: 34px;
+ line-height: 34px;
+ font-size: 13px;
+ padding-left: 10px;
+ display: none;
}
.line-numbers-mode .copy-btn .show-copy {
- opacity: 1;
- display: block;
+ opacity: 1;
+ display: block;
}
.line-numbers-mode ::-webkit-scrollbar-track {
- background-color: #292b30 !important;
+ background-color: #292b30 !important;
}
.markdown-body .anchor {
- float: left;
- line-height: 1;
- margin-left: -20px;
- padding-right: 4px;
+ float: left;
+ line-height: 1;
+ margin-left: -20px;
+ padding-right: 4px;
}
.markdown-body .anchor:focus {
- outline: none;
+ outline: none;
}
.markdown-body h1 .octicon-link,
@@ -162,9 +162,9 @@ $font-color: #24292e;
.markdown-body h4 .octicon-link,
.markdown-body h5 .octicon-link,
.markdown-body h6 .octicon-link {
- color: #1b1f23;
- vertical-align: middle;
- visibility: hidden;
+ color: #1b1f23;
+ vertical-align: middle;
+ visibility: hidden;
}
.markdown-body h1:hover .anchor,
@@ -173,7 +173,7 @@ $font-color: #24292e;
.markdown-body h4:hover .anchor,
.markdown-body h5:hover .anchor,
.markdown-body h6:hover .anchor {
- text-decoration: none;
+ text-decoration: none;
}
.markdown-body h1:hover .anchor .octicon-link,
@@ -182,7 +182,7 @@ $font-color: #24292e;
.markdown-body h4:hover .anchor .octicon-link,
.markdown-body h5:hover .anchor .octicon-link,
.markdown-body h6:hover .anchor .octicon-link {
- visibility: visible;
+ visibility: visible;
}
.markdown-body h1:hover .anchor .octicon-link:before,
@@ -191,324 +191,324 @@ $font-color: #24292e;
.markdown-body h4:hover .anchor .octicon-link:before,
.markdown-body h5:hover .anchor .octicon-link:before,
.markdown-body h6:hover .anchor .octicon-link:before {
- width: 16px;
- height: 16px;
- content: ' ';
- display: inline-block;
+ width: 16px;
+ height: 16px;
+ content: ' ';
+ display: inline-block;
}
.markdown-body {
- -ms-text-size-adjust: 100%;
- -webkit-text-size-adjust: 100%;
- line-height: 1.5;
- color: $font-color;
- font-size: 16px;
- line-height: 1.5;
- word-wrap: break-word;
+ -ms-text-size-adjust: 100%;
+ -webkit-text-size-adjust: 100%;
+ line-height: 1.5;
+ color: $font-color;
+ font-size: 16px;
+ line-height: 1.5;
+ word-wrap: break-word;
}
.markdown-body details {
- display: block;
+ display: block;
}
.markdown-body summary {
- display: list-item;
+ display: list-item;
}
.markdown-body a {
- background-color: initial;
+ background-color: initial;
}
.markdown-body a:active,
.markdown-body a:hover {
- outline-width: 0;
+ outline-width: 0;
}
.markdown-body strong {
- font-weight: inherit;
- font-weight: bolder;
+ font-weight: inherit;
+ font-weight: bolder;
}
.markdown-body p br {
- display: inline;
- line-height: 11px;
+ display: inline;
+ line-height: 11px;
}
.markdown-body img {
- border-style: none;
+ border-style: none;
}
.markdown-body hr {
- box-sizing: initial;
- height: 0;
- overflow: visible;
+ box-sizing: initial;
+ height: 0;
+ overflow: visible;
}
.markdown-body input {
- font: inherit;
- margin: 0;
+ font: inherit;
+ margin: 0;
}
.markdown-body input {
- overflow: visible;
+ overflow: visible;
}
.markdown-body [type='checkbox'] {
- box-sizing: border-box;
- padding: 0;
+ box-sizing: border-box;
+ padding: 0;
}
.markdown-body * {
- box-sizing: border-box;
+ box-sizing: border-box;
}
.markdown-body input {
- font-size: inherit;
- line-height: inherit;
+ font-size: inherit;
+ line-height: inherit;
}
.markdown-body a {
- color: #0366d6;
- text-decoration: none;
+ color: #0366d6;
+ text-decoration: none;
}
.markdown-body a:hover {
- text-decoration: underline;
+ text-decoration: underline;
}
.markdown-body strong {
- font-weight: 600;
+ font-weight: 600;
}
.markdown-body hr {
- height: 0;
- margin: 15px 0;
- overflow: hidden;
- background: transparent;
- border: 0;
- border-bottom: 1px solid #dfe2e5;
+ height: 0;
+ margin: 15px 0;
+ overflow: hidden;
+ background: transparent;
+ border: 0;
+ border-bottom: 1px solid #dfe2e5;
}
.markdown-body hr:after,
.markdown-body hr:before {
- display: table;
- content: '';
+ display: table;
+ content: '';
}
.markdown-body hr:after {
- clear: both;
+ clear: both;
}
.markdown-body table {
- border-spacing: 0;
- border-collapse: collapse;
+ border-spacing: 0;
+ border-collapse: collapse;
}
.markdown-body td,
.markdown-body th {
- padding: 0;
+ padding: 0;
}
.markdown-body details summary {
- cursor: pointer;
+ cursor: pointer;
}
.markdown-body kbd {
- display: inline-block;
- padding: 3px 5px;
- font:
- 11px SFMono-Regular,
- Consolas,
- Liberation Mono,
- Menlo,
- monospace;
- line-height: 10px;
- color: #444d56;
- vertical-align: middle;
- background-color: #fafbfc;
- border: 1px solid #d1d5da;
- border-radius: 3px;
- box-shadow: inset 0 -1px 0 #d1d5da;
+ display: inline-block;
+ padding: 3px 5px;
+ font:
+ 11px SFMono-Regular,
+ Consolas,
+ Liberation Mono,
+ Menlo,
+ monospace;
+ line-height: 10px;
+ color: #444d56;
+ vertical-align: middle;
+ background-color: #fafbfc;
+ border: 1px solid #d1d5da;
+ border-radius: 3px;
+ box-shadow: inset 0 -1px 0 #d1d5da;
}
.markdown-body blockquote {
- margin: 0;
+ margin: 0;
}
.markdown-body ol,
.markdown-body ul {
- padding-left: 0;
- margin-top: 0;
- margin-bottom: 0;
+ padding-left: 0;
+ margin-top: 0;
+ margin-bottom: 0;
}
.markdown-body ol ol,
.markdown-body ul ol {
- list-style-type: lower-roman;
+ list-style-type: lower-roman;
}
.markdown-body ol ol ol,
.markdown-body ol ul ol,
.markdown-body ul ol ol,
.markdown-body ul ul ol {
- list-style-type: lower-alpha;
+ list-style-type: lower-alpha;
}
.markdown-body dd {
- margin-left: 0;
+ margin-left: 0;
}
.markdown-body code,
.markdown-body pre,
.markdown-body .line-number {
- font-size: 14px !important;
- border-radius: 8px;
- background-color: #282c34;
+ font-size: 14px !important;
+ border-radius: 8px;
+ background-color: #282c34;
}
.dark {
- .markdown-body code,
- .markdown-body pre,
- .markdown-body .line-number {
- background-color: #252525;
- }
+ .markdown-body code,
+ .markdown-body pre,
+ .markdown-body .line-number {
+ background-color: #252525;
+ }
}
.markdown-body pre {
- margin-top: 0;
- margin-bottom: 0;
+ margin-top: 0;
+ margin-bottom: 0;
}
.markdown-body input::-webkit-inner-spin-button,
.markdown-body input::-webkit-outer-spin-button {
- margin: 0;
- -webkit-appearance: none;
- appearance: none;
+ margin: 0;
+ -webkit-appearance: none;
+ appearance: none;
}
.markdown-body :checked + .radio-label {
- position: relative;
- z-index: 1;
- border-color: #0366d6;
+ position: relative;
+ z-index: 1;
+ border-color: #0366d6;
}
.markdown-body .border {
- border: 1px solid #e1e4e8 !important;
+ border: 1px solid #e1e4e8 !important;
}
.markdown-body .border-0 {
- border: 0 !important;
+ border: 0 !important;
}
.markdown-body .border-bottom {
- border-bottom: 1px solid #e1e4e8 !important;
+ border-bottom: 1px solid #e1e4e8 !important;
}
.markdown-body .rounded-1 {
- border-radius: 3px !important;
+ border-radius: 3px !important;
}
.markdown-body .bg-white {
- background-color: #fff !important;
+ background-color: #fff !important;
}
.markdown-body .bg-gray-light {
- background-color: #fafbfc !important;
+ background-color: #fafbfc !important;
}
.markdown-body .text-gray-light {
- color: #6a737d !important;
+ color: #6a737d !important;
}
.markdown-body .mb-0 {
- margin-bottom: 0 !important;
+ margin-bottom: 0 !important;
}
.markdown-body .my-2 {
- margin-top: 8px !important;
- margin-bottom: 8px !important;
+ margin-top: 8px !important;
+ margin-bottom: 8px !important;
}
.markdown-body .pl-0 {
- padding-left: 0 !important;
+ padding-left: 0 !important;
}
.markdown-body .py-0 {
- padding-top: 0 !important;
- padding-bottom: 0 !important;
+ padding-top: 0 !important;
+ padding-bottom: 0 !important;
}
.markdown-body .pl-1 {
- padding-left: 4px !important;
+ padding-left: 4px !important;
}
.markdown-body .pl-2 {
- padding-left: 8px !important;
+ padding-left: 8px !important;
}
.markdown-body .py-2 {
- padding-top: 8px !important;
- padding-bottom: 8px !important;
+ padding-top: 8px !important;
+ padding-bottom: 8px !important;
}
.markdown-body .pl-3,
.markdown-body .px-3 {
- padding-left: 16px !important;
+ padding-left: 16px !important;
}
.markdown-body .px-3 {
- padding-right: 16px !important;
+ padding-right: 16px !important;
}
.markdown-body .pl-4 {
- padding-left: 24px !important;
+ padding-left: 24px !important;
}
.markdown-body .pl-5 {
- padding-left: 32px !important;
+ padding-left: 32px !important;
}
.markdown-body .pl-6 {
- padding-left: 40px !important;
+ padding-left: 40px !important;
}
.markdown-body .f6 {
- font-size: 12px !important;
+ font-size: 12px !important;
}
.markdown-body .lh-condensed {
- line-height: 1.25 !important;
+ line-height: 1.25 !important;
}
.markdown-body .text-bold {
- font-weight: 600 !important;
+ font-weight: 600 !important;
}
.markdown-body .pl-c {
- color: #6a737d;
+ color: #6a737d;
}
.markdown-body .pl-c1,
.markdown-body .pl-s .pl-v {
- color: #005cc5;
+ color: #005cc5;
}
.markdown-body .pl-e,
.markdown-body .pl-en {
- color: #6f42c1;
+ color: #6f42c1;
}
.markdown-body .pl-s .pl-s1,
.markdown-body .pl-smi {
- color: $font-color;
+ color: $font-color;
}
.markdown-body .pl-ent {
- color: #22863a;
+ color: #22863a;
}
.markdown-body .pl-k {
- color: #d73a49;
+ color: #d73a49;
}
.markdown-body .pl-pds,
@@ -518,213 +518,213 @@ $font-color: #24292e;
.markdown-body .pl-sr .pl-cce,
.markdown-body .pl-sr .pl-sra,
.markdown-body .pl-sr .pl-sre {
- color: #032f62;
+ color: #032f62;
}
.markdown-body .pl-smw,
.markdown-body .pl-v {
- color: #e36209;
+ color: #e36209;
}
.markdown-body .pl-bu {
- color: #b31d28;
+ color: #b31d28;
}
.markdown-body .pl-ii {
- color: #fafbfc;
- background-color: #b31d28;
+ color: #fafbfc;
+ background-color: #b31d28;
}
.markdown-body .pl-c2 {
- color: #fafbfc;
- background-color: #d73a49;
+ color: #fafbfc;
+ background-color: #d73a49;
}
.markdown-body .pl-c2:before {
- content: '^M';
+ content: '^M';
}
.markdown-body .pl-sr .pl-cce {
- font-weight: 700;
- color: #22863a;
+ font-weight: 700;
+ color: #22863a;
}
.markdown-body .pl-ml {
- color: #735c0f;
+ color: #735c0f;
}
.markdown-body .pl-mh,
.markdown-body .pl-mh .pl-en,
.markdown-body .pl-ms {
- font-weight: 700;
- color: #005cc5;
+ font-weight: 700;
+ color: #005cc5;
}
.markdown-body .pl-mi {
- font-style: italic;
- color: $font-color;
+ font-style: italic;
+ color: $font-color;
}
.markdown-body .pl-mb {
- font-weight: 700;
- color: $font-color;
+ font-weight: 700;
+ color: $font-color;
}
.markdown-body .pl-md {
- color: #b31d28;
- background-color: #ffeef0;
+ color: #b31d28;
+ background-color: #ffeef0;
}
.markdown-body .pl-mi1 {
- color: #22863a;
- background-color: #f0fff4;
+ color: #22863a;
+ background-color: #f0fff4;
}
.markdown-body .pl-mc {
- color: #e36209;
- background-color: #ffebda;
+ color: #e36209;
+ background-color: #ffebda;
}
.markdown-body .pl-mi2 {
- color: #f6f8fa;
- background-color: #005cc5;
+ color: #f6f8fa;
+ background-color: #005cc5;
}
.markdown-body .pl-mdr {
- font-weight: 700;
- color: #6f42c1;
+ font-weight: 700;
+ color: #6f42c1;
}
.markdown-body .pl-ba {
- color: #586069;
+ color: #586069;
}
.markdown-body .pl-sg {
- color: #959da5;
+ color: #959da5;
}
.markdown-body .pl-corl {
- text-decoration: underline;
- color: #032f62;
+ text-decoration: underline;
+ color: #032f62;
}
.markdown-body .mb-0 {
- margin-bottom: 0 !important;
+ margin-bottom: 0 !important;
}
.markdown-body .my-2 {
- margin-bottom: 8px !important;
+ margin-bottom: 8px !important;
}
.markdown-body .my-2 {
- margin-top: 8px !important;
+ margin-top: 8px !important;
}
.markdown-body .pl-0 {
- padding-left: 0 !important;
+ padding-left: 0 !important;
}
.markdown-body .py-0 {
- padding-top: 0 !important;
- padding-bottom: 0 !important;
+ padding-top: 0 !important;
+ padding-bottom: 0 !important;
}
.markdown-body .pl-1 {
- padding-left: 4px !important;
+ padding-left: 4px !important;
}
.markdown-body .pl-2 {
- padding-left: 8px !important;
+ padding-left: 8px !important;
}
.markdown-body .py-2 {
- padding-top: 8px !important;
- padding-bottom: 8px !important;
+ padding-top: 8px !important;
+ padding-bottom: 8px !important;
}
.markdown-body .pl-3 {
- padding-left: 16px !important;
+ padding-left: 16px !important;
}
.markdown-body .pl-4 {
- padding-left: 24px !important;
+ padding-left: 24px !important;
}
.markdown-body .pl-5 {
- padding-left: 32px !important;
+ padding-left: 32px !important;
}
.markdown-body .pl-6 {
- padding-left: 40px !important;
+ padding-left: 40px !important;
}
.markdown-body .pl-7 {
- padding-left: 48px !important;
+ padding-left: 48px !important;
}
.markdown-body .pl-8 {
- padding-left: 64px !important;
+ padding-left: 64px !important;
}
.markdown-body .pl-9 {
- padding-left: 80px !important;
+ padding-left: 80px !important;
}
.markdown-body .pl-10 {
- padding-left: 96px !important;
+ padding-left: 96px !important;
}
.markdown-body .pl-11 {
- padding-left: 112px !important;
+ padding-left: 112px !important;
}
.markdown-body .pl-12 {
- padding-left: 128px !important;
+ padding-left: 128px !important;
}
.markdown-body hr {
- border-bottom-color: #eee;
+ border-bottom-color: #eee;
}
.markdown-body kbd {
- display: inline-block;
- padding: 3px 5px;
- font:
- 11px SFMono-Regular,
- Consolas,
- Liberation Mono,
- Menlo,
- monospace;
- line-height: 10px;
- color: #444d56;
- vertical-align: middle;
- background-color: #fafbfc;
- border: 1px solid #d1d5da;
- border-radius: 3px;
- box-shadow: inset 0 -1px 0 #d1d5da;
+ display: inline-block;
+ padding: 3px 5px;
+ font:
+ 11px SFMono-Regular,
+ Consolas,
+ Liberation Mono,
+ Menlo,
+ monospace;
+ line-height: 10px;
+ color: #444d56;
+ vertical-align: middle;
+ background-color: #fafbfc;
+ border: 1px solid #d1d5da;
+ border-radius: 3px;
+ box-shadow: inset 0 -1px 0 #d1d5da;
}
.markdown-body:after,
.markdown-body:before {
- display: table;
- content: '';
+ display: table;
+ content: '';
}
.markdown-body:after {
- clear: both;
+ clear: both;
}
.markdown-body > :first-child {
- margin-top: 0 !important;
+ margin-top: 0 !important;
}
.markdown-body > :last-child {
- margin-bottom: 0 !important;
+ margin-bottom: 0 !important;
}
.markdown-body a:not([href]) {
- color: inherit;
- text-decoration: none;
+ color: inherit;
+ text-decoration: none;
}
.markdown-body blockquote,
@@ -734,303 +734,303 @@ $font-color: #24292e;
.markdown-body pre,
.markdown-body table,
.markdown-body ul {
- margin-top: 0;
- margin-bottom: 16px;
+ margin-top: 0;
+ margin-bottom: 16px;
}
.markdown-body hr {
- height: 0.25em;
- padding: 0;
- margin: 24px 0;
- background-color: #e1e4e8;
- border: 0;
+ height: 0.25em;
+ padding: 0;
+ margin: 24px 0;
+ background-color: #e1e4e8;
+ border: 0;
}
.markdown-body blockquote > :first-child {
- margin-top: 0;
+ margin-top: 0;
}
.markdown-body blockquote > :last-child {
- margin-bottom: 0;
+ margin-bottom: 0;
}
.markdown-body ol,
.markdown-body ul {
- padding-left: 1em;
+ padding-left: 1em;
}
.markdown-body ol ol,
.markdown-body ol ul,
.markdown-body ul ol,
.markdown-body ul ul {
- margin-top: 0;
- margin-bottom: 0;
+ margin-top: 0;
+ margin-bottom: 0;
}
.markdown-body li {
- line-height: 28px;
- font-size: 14px;
- word-wrap: break-all;
- list-style: disc;
- margin-left: 10px;
+ line-height: 28px;
+ font-size: 14px;
+ word-wrap: break-all;
+ list-style: disc;
+ margin-left: 10px;
}
.markdown-body li > p {
- margin-top: 16px;
+ margin-top: 16px;
}
.markdown-body li + li {
- margin-top: 0.25em;
+ margin-top: 0.25em;
}
.markdown-body dl {
- padding: 0;
+ padding: 0;
}
.markdown-body dl dt {
- padding: 0;
- margin-top: 16px;
- font-size: 1em;
- font-style: italic;
- font-weight: 600;
+ padding: 0;
+ margin-top: 16px;
+ font-size: 1em;
+ font-style: italic;
+ font-weight: 600;
}
.markdown-body dl dd {
- padding: 0 16px;
- margin-bottom: 16px;
+ padding: 0 16px;
+ margin-bottom: 16px;
}
.markdown-body table {
- display: block;
- width: 100%;
- overflow: auto;
+ display: block;
+ width: 100%;
+ overflow: auto;
}
.markdown-body table th {
- font-weight: 600;
+ font-weight: 600;
}
.markdown-body table td,
.markdown-body table th {
- padding: 6px 13px;
- border: 1px solid #dfe2e5;
+ padding: 6px 13px;
+ border: 1px solid #dfe2e5;
}
.markdown-body table tr {
- background-color: #fff;
- border-top: 1px solid #c6cbd1;
+ background-color: #fff;
+ border-top: 1px solid #c6cbd1;
}
.markdown-body table tr:nth-child(2n) {
- background-color: #f6f8fa;
+ background-color: #f6f8fa;
}
.markdown-body img {
- max-width: 100%;
- box-sizing: initial;
- background-color: #fff;
- border: 1px solid #eee;
- border: 1px solid var(--art-c-border-2);
- cursor: zoom-in;
+ max-width: 100%;
+ box-sizing: initial;
+ background-color: #fff;
+ border: 1px solid #eee;
+ border: 1px solid var(--art-c-border-2);
+ cursor: zoom-in;
}
.markdown-body img[align='right'] {
- padding-left: 20px;
+ padding-left: 20px;
}
.markdown-body img[align='left'] {
- padding-right: 20px;
+ padding-right: 20px;
}
.markdown-body code {
- padding: 0.2em 0.4em;
- margin: 0;
- font-size: 85%;
- background-color: rgba(27, 31, 35, 0.05);
- border-radius: 3px;
+ padding: 0.2em 0.4em;
+ margin: 0;
+ font-size: 85%;
+ background-color: rgba(27, 31, 35, 0.05);
+ border-radius: 3px;
}
.markdown-body pre {
- word-wrap: normal;
+ word-wrap: normal;
}
.markdown-body pre > code {
- padding: 0;
- margin: 0;
- font-size: 100%;
- word-break: normal;
- white-space: pre;
- background: transparent;
- border: 0;
+ padding: 0;
+ margin: 0;
+ font-size: 100%;
+ word-break: normal;
+ white-space: pre;
+ background: transparent;
+ border: 0;
}
.markdown-body .highlight {
- margin-bottom: 16px;
+ margin-bottom: 16px;
}
.markdown-body .highlight pre {
- margin-bottom: 0;
- word-break: normal;
+ margin-bottom: 0;
+ word-break: normal;
}
.markdown-body .highlight pre,
.markdown-body pre {
- padding: 15px 20px 15px 0;
- overflow: auto;
- font-size: 92%;
- line-height: 1.6;
+ padding: 15px 20px 15px 0;
+ overflow: auto;
+ font-size: 92%;
+ line-height: 1.6;
}
.markdown-body pre code {
- display: inline;
- max-width: auto;
- padding: 0;
- margin: 0;
- overflow: visible;
- line-height: inherit;
- word-wrap: normal;
- background-color: initial;
- border: 0;
+ display: inline;
+ max-width: auto;
+ padding: 0;
+ margin: 0;
+ overflow: visible;
+ line-height: inherit;
+ word-wrap: normal;
+ background-color: initial;
+ border: 0;
}
.markdown-body .commit-tease-sha {
- display: inline-block;
- font-size: 90%;
- color: #444d56;
+ display: inline-block;
+ font-size: 90%;
+ color: #444d56;
}
.markdown-body .full-commit .btn-outline:not(:disabled):hover {
- color: #005cc5;
- border-color: #005cc5;
+ color: #005cc5;
+ border-color: #005cc5;
}
.markdown-body .blob-wrapper {
- overflow-x: auto;
- overflow-y: hidden;
+ overflow-x: auto;
+ overflow-y: hidden;
}
.markdown-body .blob-wrapper-embedded {
- max-height: 240px;
- overflow-y: auto;
+ max-height: 240px;
+ overflow-y: auto;
}
.markdown-body .blob-num {
- width: 1%;
- min-width: 50px;
- padding-right: 10px;
- padding-left: 10px;
- font-size: 12px;
- line-height: 20px;
- color: rgba(27, 31, 35, 0.3);
- text-align: right;
- white-space: nowrap;
- vertical-align: top;
- cursor: pointer;
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
+ width: 1%;
+ min-width: 50px;
+ padding-right: 10px;
+ padding-left: 10px;
+ font-size: 12px;
+ line-height: 20px;
+ color: rgba(27, 31, 35, 0.3);
+ text-align: right;
+ white-space: nowrap;
+ vertical-align: top;
+ cursor: pointer;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
}
.markdown-body .blob-num:hover {
- color: rgba(27, 31, 35, 0.6);
+ color: rgba(27, 31, 35, 0.6);
}
.markdown-body .blob-num:before {
- content: attr(data-line-number);
+ content: attr(data-line-number);
}
.markdown-body .blob-code {
- position: relative;
- padding-right: 10px;
- padding-left: 10px;
- line-height: 20px;
- vertical-align: top;
+ position: relative;
+ padding-right: 10px;
+ padding-left: 10px;
+ line-height: 20px;
+ vertical-align: top;
}
.markdown-body .blob-code-inner {
- overflow: visible;
- font-size: 12px;
- color: $font-color;
- word-wrap: normal;
- white-space: pre;
+ overflow: visible;
+ font-size: 12px;
+ color: $font-color;
+ word-wrap: normal;
+ white-space: pre;
}
.markdown-body .pl-token.active,
.markdown-body .pl-token:hover {
- cursor: pointer;
- background: #ffea7f;
+ cursor: pointer;
+ background: #ffea7f;
}
.markdown-body .tab-size[data-tab-size='1'] {
- -moz-tab-size: 1;
- tab-size: 1;
+ -moz-tab-size: 1;
+ tab-size: 1;
}
.markdown-body .tab-size[data-tab-size='2'] {
- -moz-tab-size: 2;
- tab-size: 2;
+ -moz-tab-size: 2;
+ tab-size: 2;
}
.markdown-body .tab-size[data-tab-size='3'] {
- -moz-tab-size: 3;
- tab-size: 3;
+ -moz-tab-size: 3;
+ tab-size: 3;
}
.markdown-body .tab-size[data-tab-size='4'] {
- -moz-tab-size: 4;
- tab-size: 4;
+ -moz-tab-size: 4;
+ tab-size: 4;
}
.markdown-body .tab-size[data-tab-size='5'] {
- -moz-tab-size: 5;
- tab-size: 5;
+ -moz-tab-size: 5;
+ tab-size: 5;
}
.markdown-body .tab-size[data-tab-size='6'] {
- -moz-tab-size: 6;
- tab-size: 6;
+ -moz-tab-size: 6;
+ tab-size: 6;
}
.markdown-body .tab-size[data-tab-size='7'] {
- -moz-tab-size: 7;
- tab-size: 7;
+ -moz-tab-size: 7;
+ tab-size: 7;
}
.markdown-body .tab-size[data-tab-size='8'] {
- -moz-tab-size: 8;
- tab-size: 8;
+ -moz-tab-size: 8;
+ tab-size: 8;
}
.markdown-body .tab-size[data-tab-size='9'] {
- -moz-tab-size: 9;
- tab-size: 9;
+ -moz-tab-size: 9;
+ tab-size: 9;
}
.markdown-body .tab-size[data-tab-size='10'] {
- -moz-tab-size: 10;
- tab-size: 10;
+ -moz-tab-size: 10;
+ tab-size: 10;
}
.markdown-body .tab-size[data-tab-size='11'] {
- -moz-tab-size: 11;
- tab-size: 11;
+ -moz-tab-size: 11;
+ tab-size: 11;
}
.markdown-body .tab-size[data-tab-size='12'] {
- -moz-tab-size: 12;
- tab-size: 12;
+ -moz-tab-size: 12;
+ tab-size: 12;
}
.markdown-body .task-list-item {
- list-style-type: none;
+ list-style-type: none;
}
.markdown-body .task-list-item + .task-list-item {
- margin-top: 3px;
+ margin-top: 3px;
}
.markdown-body .task-list-item input {
- margin: 0 0.2em 0.25em -1.6em;
- vertical-align: middle;
+ margin: 0 0.2em 0.25em -1.6em;
+ vertical-align: middle;
}
diff --git a/src/assets/styles/core/mixin.scss b/src/assets/styles/core/mixin.scss
index db36888..dfd6bc2 100644
--- a/src/assets/styles/core/mixin.scss
+++ b/src/assets/styles/core/mixin.scss
@@ -5,18 +5,18 @@
* @param {Number} 行数
*/
@mixin ellipsis($rowCount: 1) {
- @if $rowCount <=1 {
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- } @else {
- min-width: 0;
- overflow: hidden;
- text-overflow: ellipsis;
- display: -webkit-box;
- -webkit-line-clamp: $rowCount;
- -webkit-box-orient: vertical;
- }
+ @if $rowCount <=1 {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ } @else {
+ min-width: 0;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ display: -webkit-box;
+ -webkit-line-clamp: $rowCount;
+ -webkit-box-orient: vertical;
+ }
}
/**
@@ -24,20 +24,20 @@
* @param {String} 类型
*/
@mixin userSelect($value: none) {
- user-select: $value;
- -moz-user-select: $value;
- -ms-user-select: $value;
- -webkit-user-select: $value;
+ user-select: $value;
+ -moz-user-select: $value;
+ -ms-user-select: $value;
+ -webkit-user-select: $value;
}
// 绝对定位居中
@mixin absoluteCenter() {
- position: absolute;
- left: 0;
- right: 0;
- top: 0;
- bottom: 0;
- margin: auto;
+ position: absolute;
+ left: 0;
+ right: 0;
+ top: 0;
+ bottom: 0;
+ margin: auto;
}
/**
@@ -45,113 +45,114 @@
*
*/
@mixin animation(
- $from: (
- width: 0px
- ),
- $to: (
- width: 100px
- ),
- $name: mymove,
- $animate: mymove 2s 1 linear infinite
+ $from: (
+ width: 0px
+ ),
+ $to: (
+ width: 100px
+ ),
+ $name: mymove,
+ $animate: mymove 2s 1 linear infinite
) {
- -webkit-animation: $animate;
- -o-animation: $animate;
- animation: $animate;
+ -webkit-animation: $animate;
+ -o-animation: $animate;
+ animation: $animate;
- @keyframes #{$name} {
- from {
- @each $key, $value in $from {
- #{$key}: #{$value};
- }
- }
+ @keyframes #{$name} {
+ from {
+ @each $key, $value in $from {
+ #{$key}: #{$value};
+ }
+ }
- to {
- @each $key, $value in $to {
- #{$key}: #{$value};
- }
- }
- }
+ to {
+ @each $key, $value in $to {
+ #{$key}: #{$value};
+ }
+ }
+ }
- @-webkit-keyframes #{$name} {
- from {
- @each $key, $value in $from {
- $key: $value;
- }
- }
+ @-webkit-keyframes #{$name} {
+ from {
+ @each $key, $value in $from {
+ $key: $value;
+ }
+ }
- to {
- @each $key, $value in $to {
- $key: $value;
- }
- }
- }
+ to {
+ @each $key, $value in $to {
+ $key: $value;
+ }
+ }
+ }
}
// 圆形盒子
@mixin circle($size: 11px, $bg: #fff) {
- border-radius: 50%;
- width: $size;
- height: $size;
- line-height: $size;
- text-align: center;
- background: $bg;
+ border-radius: 50%;
+ width: $size;
+ height: $size;
+ line-height: $size;
+ text-align: center;
+ background: $bg;
}
// placeholder
@mixin placeholder($color: #bbb) {
- // Firefox
- &::-moz-placeholder {
- color: $color;
- opacity: 1;
- }
+ // Firefox
+ &::-moz-placeholder {
+ color: $color;
+ opacity: 1;
+ }
- // Internet Explorer 10+
- &:-ms-input-placeholder {
- color: $color;
- }
+ // Internet Explorer 10+
+ &:-ms-input-placeholder {
+ color: $color;
+ }
- // Safari and Chrome
- &::-webkit-input-placeholder {
- color: $color;
- }
+ // Safari and Chrome
+ &::-webkit-input-placeholder {
+ color: $color;
+ }
- &:placeholder-shown {
- text-overflow: ellipsis;
- }
+ &:placeholder-shown {
+ text-overflow: ellipsis;
+ }
}
//背景透明,文字不透明。兼容IE8
@mixin betterTransparentize($color, $alpha) {
- $c: rgba($color, $alpha);
- $ie_c: ie_hex_str($c);
- background: rgba($color, 1);
- background: $c;
- background: transparent \9;
- zoom: 1;
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#{$ie_c}, endColorstr=#{$ie_c});
- -ms-filter: 'progid:DXImageTransform.Microsoft.gradient(startColorstr=#{$ie_c}, endColorstr=#{$ie_c})';
+ $c: rgba($color, $alpha);
+ $ie_c: ie_hex_str($c);
+ background: rgba($color, 1);
+ background: $c;
+ background: transparent \9;
+ zoom: 1;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#{$ie_c}, endColorstr=#{$ie_c});
+ -ms-filter: 'progid:DXImageTransform.Microsoft.gradient(startColorstr=#{$ie_c}, endColorstr=#{$ie_c})';
}
//添加浏览器前缀
@mixin browserPrefix($propertyName, $value) {
- @each $prefix in -webkit-, -moz-, -ms-, -o-, '' {
- #{$prefix}#{$propertyName}: $value;
- }
+ @each $prefix in -webkit-, -moz-, -ms-, -o-, '' {
+ #{$prefix}#{$propertyName}: $value;
+ }
}
// 边框
@mixin border($color: red) {
- border: 1px solid $color;
+ border: 1px solid $color;
}
// 背景滤镜
@mixin backdropBlur() {
- --tw-backdrop-blur: blur(30px);
- -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness)
- var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate)
- var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate)
- var(--tw-backdrop-sepia);
- backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast)
- var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert)
- var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);
+ --tw-backdrop-blur: blur(30px);
+ -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness)
+ var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate)
+ var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate)
+ var(--tw-backdrop-sepia);
+ backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness)
+ var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate)
+ var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate)
+ var(--tw-backdrop-sepia);
}
diff --git a/src/assets/styles/core/reset.scss b/src/assets/styles/core/reset.scss
index 17a3bcf..b293567 100644
--- a/src/assets/styles/core/reset.scss
+++ b/src/assets/styles/core/reset.scss
@@ -3,39 +3,39 @@
/*滚动条*/
/*滚动条整体部分,必须要设置*/
::-webkit-scrollbar {
- width: 8px !important;
- height: 0 !important;
+ width: 8px !important;
+ height: 0 !important;
}
/*滚动条的轨道*/
::-webkit-scrollbar-track {
- background-color: var(--art-gray-200);
+ background-color: var(--art-gray-200);
}
/*滚动条的滑块按钮*/
::-webkit-scrollbar-thumb {
- border-radius: 5px;
- background-color: #cccccc !important;
- transition: all 0.2s;
- -webkit-transition: all 0.2s;
+ border-radius: 5px;
+ background-color: #cccccc !important;
+ transition: all 0.2s;
+ -webkit-transition: all 0.2s;
}
::-webkit-scrollbar-thumb:hover {
- background-color: #b0abab !important;
+ background-color: #b0abab !important;
}
/*滚动条的上下两端的按钮*/
::-webkit-scrollbar-button {
- height: 0px;
- width: 0;
+ height: 0px;
+ width: 0;
}
.dark {
- ::-webkit-scrollbar-track {
- background-color: var(--default-bg-color);
- }
+ ::-webkit-scrollbar-track {
+ background-color: var(--default-bg-color);
+ }
- ::-webkit-scrollbar-thumb {
- background-color: var(--art-gray-300) !important;
- }
+ ::-webkit-scrollbar-thumb {
+ background-color: var(--art-gray-300) !important;
+ }
}
diff --git a/src/assets/styles/core/router-transition.scss b/src/assets/styles/core/router-transition.scss
index f47c741..f96acf1 100644
--- a/src/assets/styles/core/router-transition.scss
+++ b/src/assets/styles/core/router-transition.scss
@@ -2,19 +2,19 @@
// === 变量区域 ===
$transition: (
- // 动画持续时间
- duration: 0.25s,
- // 滑动动画的移动距离
- distance: 15px,
- // 默认缓动函数
- easing: cubic-bezier(0.25, 0.1, 0.25, 1),
- // 淡入淡出专用的缓动函数
- fade-easing: cubic-bezier(0.4, 0, 0.6, 1)
+ // 动画持续时间
+ duration: 0.25s,
+ // 滑动动画的移动距离
+ distance: 15px,
+ // 默认缓动函数
+ easing: cubic-bezier(0.25, 0.1, 0.25, 1),
+ // 淡入淡出专用的缓动函数
+ fade-easing: cubic-bezier(0.4, 0, 0.6, 1)
);
// 抽取配置值函数,提高可复用性
@function transition-config($key) {
- @return map.get($transition, $key);
+ @return map.get($transition, $key);
}
// 变量简写
@@ -27,78 +27,78 @@ $fade-easing: transition-config('fade-easing');
// 淡入淡出动画
.fade {
- &-enter-active,
- &-leave-active {
- transition: opacity $duration $fade-easing;
- will-change: opacity;
- }
+ &-enter-active,
+ &-leave-active {
+ transition: opacity $duration $fade-easing;
+ will-change: opacity;
+ }
- &-enter-from,
- &-leave-to {
- opacity: 0;
- }
+ &-enter-from,
+ &-leave-to {
+ opacity: 0;
+ }
- &-enter-to,
- &-leave-from {
- opacity: 1;
- }
+ &-enter-to,
+ &-leave-from {
+ opacity: 1;
+ }
}
// 滑动动画通用样式
@mixin slide-transition($direction) {
- $distance-x: 0;
- $distance-y: 0;
+ $distance-x: 0;
+ $distance-y: 0;
- @if $direction == 'left' {
- $distance-x: -$distance;
- } @else if $direction == 'right' {
- $distance-x: $distance;
- } @else if $direction == 'top' {
- $distance-y: -$distance;
- } @else if $direction == 'bottom' {
- $distance-y: $distance;
- }
+ @if $direction == 'left' {
+ $distance-x: -$distance;
+ } @else if $direction == 'right' {
+ $distance-x: $distance;
+ } @else if $direction == 'top' {
+ $distance-y: -$distance;
+ } @else if $direction == 'bottom' {
+ $distance-y: $distance;
+ }
- &-enter-active {
- transition:
- opacity $duration $easing,
- transform $duration $easing;
- will-change: opacity, transform;
- }
+ &-enter-active {
+ transition:
+ opacity $duration $easing,
+ transform $duration $easing;
+ will-change: opacity, transform;
+ }
- &-leave-active {
- transition:
- opacity calc($duration * 0.7) $easing,
- transform calc($duration * 0.7) $easing;
- will-change: opacity, transform;
- }
+ &-leave-active {
+ transition:
+ opacity calc($duration * 0.7) $easing,
+ transform calc($duration * 0.7) $easing;
+ will-change: opacity, transform;
+ }
- &-enter-from {
- opacity: 0;
- transform: translate3d($distance-x, $distance-y, 0);
- }
+ &-enter-from {
+ opacity: 0;
+ transform: translate3d($distance-x, $distance-y, 0);
+ }
- &-enter-to {
- opacity: 1;
- transform: translate3d(0, 0, 0);
- }
+ &-enter-to {
+ opacity: 1;
+ transform: translate3d(0, 0, 0);
+ }
- &-leave-to {
- opacity: 0;
- transform: translate3d(-$distance-x, -$distance-y, 0);
- }
+ &-leave-to {
+ opacity: 0;
+ transform: translate3d(-$distance-x, -$distance-y, 0);
+ }
}
// 滑动动画方向类
.slide-left {
- @include slide-transition('left');
+ @include slide-transition('left');
}
.slide-right {
- @include slide-transition('right');
+ @include slide-transition('right');
}
.slide-top {
- @include slide-transition('top');
+ @include slide-transition('top');
}
.slide-bottom {
- @include slide-transition('bottom');
+ @include slide-transition('bottom');
}
diff --git a/src/assets/styles/core/tailwind.css b/src/assets/styles/core/tailwind.css
index 1a9e22c..3a33529 100644
--- a/src/assets/styles/core/tailwind.css
+++ b/src/assets/styles/core/tailwind.css
@@ -3,206 +3,206 @@
/* ==================== Light Mode Variables ==================== */
:root {
- /* Base Colors */
- --art-color: #ffffff;
- --theme-color: var(--main-color);
+ /* Base Colors */
+ --art-color: #ffffff;
+ --theme-color: var(--main-color);
- /* Theme Colors - OKLCH Format */
- --art-primary: oklch(0.7 0.23 260);
- --art-secondary: oklch(0.72 0.19 231.6);
- --art-error: oklch(0.73 0.15 25.3);
- --art-info: oklch(0.58 0.03 254.1);
- --art-success: oklch(0.78 0.17 166.1);
- --art-warning: oklch(0.78 0.14 75.5);
- --art-danger: oklch(0.68 0.22 25.3);
+ /* Theme Colors - OKLCH Format */
+ --art-primary: oklch(0.7 0.23 260);
+ --art-secondary: oklch(0.72 0.19 231.6);
+ --art-error: oklch(0.73 0.15 25.3);
+ --art-info: oklch(0.58 0.03 254.1);
+ --art-success: oklch(0.78 0.17 166.1);
+ --art-warning: oklch(0.78 0.14 75.5);
+ --art-danger: oklch(0.68 0.22 25.3);
- /* Gray Scale - Light Mode */
- --art-gray-100: #f9fafb;
- --art-gray-200: #f2f4f5;
- --art-gray-300: #e6eaeb;
- --art-gray-400: #dbdfe1;
- --art-gray-500: #949eb7;
- --art-gray-600: #7987a1;
- --art-gray-700: #4d5875;
- --art-gray-800: #383853;
- --art-gray-900: #323251;
+ /* Gray Scale - Light Mode */
+ --art-gray-100: #f9fafb;
+ --art-gray-200: #f2f4f5;
+ --art-gray-300: #e6eaeb;
+ --art-gray-400: #dbdfe1;
+ --art-gray-500: #949eb7;
+ --art-gray-600: #7987a1;
+ --art-gray-700: #4d5875;
+ --art-gray-800: #383853;
+ --art-gray-900: #323251;
- /* Border Colors */
- --art-card-border: rgba(0, 0, 0, 0.08);
+ /* Border Colors */
+ --art-card-border: rgba(0, 0, 0, 0.08);
- --default-border: #e2e8ee;
- --default-border-dashed: #dbdfe9;
+ --default-border: #e2e8ee;
+ --default-border-dashed: #dbdfe9;
- /* Background Colors */
- --default-bg-color: #fafbfc;
- --default-box-color: #ffffff;
+ /* Background Colors */
+ --default-bg-color: #fafbfc;
+ --default-box-color: #ffffff;
- /* Hover Color */
- --art-hover-color: #edeff0;
+ /* Hover Color */
+ --art-hover-color: #edeff0;
- /* Active Color */
- --art-active-color: #f2f4f5;
+ /* Active Color */
+ --art-active-color: #f2f4f5;
- /* Element Component Active Color */
- --art-el-active-color: #f2f4f5;
+ /* Element Component Active Color */
+ --art-el-active-color: #f2f4f5;
}
/* ==================== Dark Mode Variables ==================== */
.dark {
- /* Base Colors */
- --art-color: #000000;
+ /* Base Colors */
+ --art-color: #000000;
- /* Gray Scale - Dark Mode */
- --art-gray-100: #110f0f;
- --art-gray-200: #17171c;
- --art-gray-300: #393946;
- --art-gray-400: #505062;
- --art-gray-500: #73738c;
- --art-gray-600: #8f8fa3;
- --art-gray-700: #ababba;
- --art-gray-800: #c7c7d1;
- --art-gray-900: #e3e3e8;
+ /* Gray Scale - Dark Mode */
+ --art-gray-100: #110f0f;
+ --art-gray-200: #17171c;
+ --art-gray-300: #393946;
+ --art-gray-400: #505062;
+ --art-gray-500: #73738c;
+ --art-gray-600: #8f8fa3;
+ --art-gray-700: #ababba;
+ --art-gray-800: #c7c7d1;
+ --art-gray-900: #e3e3e8;
- /* Border Colors */
- --art-card-border: rgba(255, 255, 255, 0.08);
+ /* Border Colors */
+ --art-card-border: rgba(255, 255, 255, 0.08);
- --default-border: rgba(255, 255, 255, 0.1);
- --default-border-dashed: #363843;
+ --default-border: rgba(255, 255, 255, 0.1);
+ --default-border-dashed: #363843;
- /* Background Colors */
- --default-bg-color: #070707;
- --default-box-color: #161618;
+ /* Background Colors */
+ --default-bg-color: #070707;
+ --default-box-color: #161618;
- /* Hover Color */
- --art-hover-color: #252530;
+ /* Hover Color */
+ --art-hover-color: #252530;
- /* Active Color */
- --art-active-color: #202226;
+ /* Active Color */
+ --art-active-color: #202226;
- /* Element Component Active Color */
- --art-el-active-color: #2e2e38;
+ /* Element Component Active Color */
+ --art-el-active-color: #2e2e38;
}
/* ==================== Tailwind Theme Configuration ==================== */
@theme {
- /* Box Color (Light: white / Dark: black) */
- --color-box: var(--default-box-color);
+ /* Box Color (Light: white / Dark: black) */
+ --color-box: var(--default-box-color);
- /* System Theme Color */
- --color-theme: var(--theme-color);
+ /* System Theme Color */
+ --color-theme: var(--theme-color);
- /* Hover Color */
- --color-hover-color: var(--art-hover-color);
+ /* Hover Color */
+ --color-hover-color: var(--art-hover-color);
- /* Active Color */
- --color-active-color: var(--art-active-color);
+ /* Active Color */
+ --color-active-color: var(--art-active-color);
- /* Active Color */
- --color-el-active-color: var(--art-active-color);
+ /* Active Color */
+ --color-el-active-color: var(--art-active-color);
- /* ElementPlus Theme Colors */
- --color-primary: var(--art-primary);
- --color-secondary: var(--art-secondary);
- --color-error: var(--art-error);
- --color-info: var(--art-info);
- --color-success: var(--art-success);
- --color-warning: var(--art-warning);
- --color-danger: var(--art-danger);
+ /* ElementPlus Theme Colors */
+ --color-primary: var(--art-primary);
+ --color-secondary: var(--art-secondary);
+ --color-error: var(--art-error);
+ --color-info: var(--art-info);
+ --color-success: var(--art-success);
+ --color-warning: var(--art-warning);
+ --color-danger: var(--art-danger);
- /* Gray Scale Colors (Auto-adapts to dark mode) */
- --color-g-100: var(--art-gray-100);
- --color-g-200: var(--art-gray-200);
- --color-g-300: var(--art-gray-300);
- --color-g-400: var(--art-gray-400);
- --color-g-500: var(--art-gray-500);
- --color-g-600: var(--art-gray-600);
- --color-g-700: var(--art-gray-700);
- --color-g-800: var(--art-gray-800);
- --color-g-900: var(--art-gray-900);
+ /* Gray Scale Colors (Auto-adapts to dark mode) */
+ --color-g-100: var(--art-gray-100);
+ --color-g-200: var(--art-gray-200);
+ --color-g-300: var(--art-gray-300);
+ --color-g-400: var(--art-gray-400);
+ --color-g-500: var(--art-gray-500);
+ --color-g-600: var(--art-gray-600);
+ --color-g-700: var(--art-gray-700);
+ --color-g-800: var(--art-gray-800);
+ --color-g-900: var(--art-gray-900);
}
/* ==================== Custom Border Radius Utilities ==================== */
@utility rounded-custom-xs {
- border-radius: calc(var(--custom-radius) / 2);
+ border-radius: calc(var(--custom-radius) / 2);
}
@utility rounded-custom-sm {
- border-radius: calc(var(--custom-radius) / 2 + 2px);
+ border-radius: calc(var(--custom-radius) / 2 + 2px);
}
/* ==================== Custom Utility Classes ==================== */
@layer utilities {
- /* Flexbox Layout Utilities */
- .flex-c {
- @apply flex items-center;
- }
+ /* Flexbox Layout Utilities */
+ .flex-c {
+ @apply flex items-center;
+ }
- .flex-b {
- @apply flex justify-between;
- }
+ .flex-b {
+ @apply flex justify-between;
+ }
- .flex-cc {
- @apply flex items-center justify-center;
- }
+ .flex-cc {
+ @apply flex items-center justify-center;
+ }
- .flex-cb {
- @apply flex items-center justify-between;
- }
+ .flex-cb {
+ @apply flex items-center justify-between;
+ }
- /* Transition Utilities */
- .tad-200 {
- @apply transition-all duration-200;
- }
+ /* Transition Utilities */
+ .tad-200 {
+ @apply transition-all duration-200;
+ }
- .tad-300 {
- @apply transition-all duration-300;
- }
+ .tad-300 {
+ @apply transition-all duration-300;
+ }
- /* Border Utilities */
- .border-full-d {
- @apply border border-[var(--default-border)];
- }
+ /* Border Utilities */
+ .border-full-d {
+ @apply border border-[var(--default-border)];
+ }
- .border-b-d {
- @apply border-b border-[var(--default-border)];
- }
+ .border-b-d {
+ @apply border-b border-[var(--default-border)];
+ }
- .border-t-d {
- @apply border-t border-[var(--default-border)];
- }
+ .border-t-d {
+ @apply border-t border-[var(--default-border)];
+ }
- .border-l-d {
- @apply border-l border-[var(--default-border)];
- }
+ .border-l-d {
+ @apply border-l border-[var(--default-border)];
+ }
- .border-r-d {
- @apply border-r border-[var(--default-border)];
- }
+ .border-r-d {
+ @apply border-r border-[var(--default-border)];
+ }
- /* Cursor Utilities */
- .c-p {
- @apply cursor-pointer;
- }
+ /* Cursor Utilities */
+ .c-p {
+ @apply cursor-pointer;
+ }
}
/* ==================== Custom Component Classes ==================== */
@layer components {
- /* Art Card Header Component */
- .art-card-header {
- @apply flex justify-between pr-6 pb-1;
+ /* Art Card Header Component */
+ .art-card-header {
+ @apply flex justify-between pr-6 pb-1;
- .title {
- h4 {
- @apply text-lg font-medium text-g-900;
- }
+ .title {
+ h4 {
+ @apply text-lg font-medium text-g-900;
+ }
- p {
- @apply mt-1 text-sm text-g-600;
+ p {
+ @apply mt-1 text-sm text-g-600;
- span {
- @apply ml-2 font-medium;
- }
- }
- }
- }
+ span {
+ @apply ml-2 font-medium;
+ }
+ }
+ }
+ }
}
diff --git a/src/assets/styles/core/theme-animation.scss b/src/assets/styles/core/theme-animation.scss
index 377b945..60167cd 100644
--- a/src/assets/styles/core/theme-animation.scss
+++ b/src/assets/styles/core/theme-animation.scss
@@ -4,60 +4,60 @@ $bg-animation-color-dark: #fff;
$bg-animation-duration: 0.5s;
html {
- --bg-animation-color: $bg-animation-color-light;
+ --bg-animation-color: $bg-animation-color-light;
- &.dark {
- --bg-animation-color: $bg-animation-color-dark;
- }
+ &.dark {
+ --bg-animation-color: $bg-animation-color-dark;
+ }
- // View transition styles
- &::view-transition-old(*) {
- animation: none;
- }
+ // View transition styles
+ &::view-transition-old(*) {
+ animation: none;
+ }
- &::view-transition-new(*) {
- animation: clip $bg-animation-duration ease-in both;
- }
+ &::view-transition-new(*) {
+ animation: clip $bg-animation-duration ease-in both;
+ }
- &::view-transition-old(root) {
- z-index: 1;
- }
+ &::view-transition-old(root) {
+ z-index: 1;
+ }
- &::view-transition-new(root) {
- z-index: 9999;
- }
+ &::view-transition-new(root) {
+ z-index: 9999;
+ }
- &.dark {
- &::view-transition-old(*) {
- animation: clip $bg-animation-duration ease-in reverse both;
- }
+ &.dark {
+ &::view-transition-old(*) {
+ animation: clip $bg-animation-duration ease-in reverse both;
+ }
- &::view-transition-new(*) {
- animation: none;
- }
+ &::view-transition-new(*) {
+ animation: none;
+ }
- &::view-transition-old(root) {
- z-index: 9999;
- }
+ &::view-transition-old(root) {
+ z-index: 9999;
+ }
- &::view-transition-new(root) {
- z-index: 1;
- }
- }
+ &::view-transition-new(root) {
+ z-index: 1;
+ }
+ }
}
// 定义动画
@keyframes clip {
- from {
- clip-path: circle(0% at var(--x) var(--y));
- }
+ from {
+ clip-path: circle(0% at var(--x) var(--y));
+ }
- to {
- clip-path: circle(var(--r) at var(--x) var(--y));
- }
+ to {
+ clip-path: circle(var(--r) at var(--x) var(--y));
+ }
}
// body 相关样式
body {
- background-color: var(--bg-animation-color);
+ background-color: var(--bg-animation-color);
}
diff --git a/src/assets/styles/core/theme-change.scss b/src/assets/styles/core/theme-change.scss
index 5b640d2..7be858f 100644
--- a/src/assets/styles/core/theme-change.scss
+++ b/src/assets/styles/core/theme-change.scss
@@ -1,11 +1,11 @@
// 主题切换过渡优化,优化除视觉上的不适感
.theme-change {
- * {
- transition: 0s !important;
- }
+ * {
+ transition: 0s !important;
+ }
- .el-switch__core,
- .el-switch__action {
- transition: all 0.3s !important;
- }
+ .el-switch__core,
+ .el-switch__action {
+ transition: all 0.3s !important;
+ }
}
diff --git a/src/assets/styles/custom/one-dark-pro.scss b/src/assets/styles/custom/one-dark-pro.scss
index 36bdf63..161ef38 100644
--- a/src/assets/styles/custom/one-dark-pro.scss
+++ b/src/assets/styles/custom/one-dark-pro.scss
@@ -1,9 +1,9 @@
.hljs {
- display: block;
- overflow-x: auto;
- padding: 0.5em;
+ display: block;
+ overflow-x: auto;
+ padding: 0.5em;
- color: #a6accd;
+ color: #a6accd;
}
.hljs-string,
@@ -11,18 +11,18 @@
.hljs-selector-class,
.hljs-template-variable,
.hljs-deletion {
- color: #aed07e !important;
+ color: #aed07e !important;
}
.hljs-comment,
.hljs-quote {
- color: #6f747d;
+ color: #6f747d;
}
.hljs-doctag,
.hljs-keyword,
.hljs-formula {
- color: #c792ea;
+ color: #c792ea;
}
.hljs-section,
@@ -30,11 +30,11 @@
.hljs-selector-tag,
.hljs-deletion,
.hljs-subst {
- color: #c86068;
+ color: #c86068;
}
.hljs-literal {
- color: #56b6c2;
+ color: #56b6c2;
}
.hljs-string,
@@ -42,33 +42,33 @@
.hljs-addition,
.hljs-attribute,
.hljs-meta-string {
- color: #abb2bf;
+ color: #abb2bf;
}
.hljs-attribute {
- color: #c792ea;
+ color: #c792ea;
}
.hljs-function {
- color: #c792ea;
+ color: #c792ea;
}
.hljs-type {
- color: #f07178;
+ color: #f07178;
}
.hljs-title {
- color: #82aaff !important;
+ color: #82aaff !important;
}
.hljs-built_in,
.hljs-class {
- color: #82aaff;
+ color: #82aaff;
}
// 括号
.hljs-params {
- color: #a6accd;
+ color: #a6accd;
}
.hljs-attr,
@@ -78,7 +78,7 @@
.hljs-selector-attr,
.hljs-selector-pseudo,
.hljs-number {
- color: #de7e61;
+ color: #de7e61;
}
.hljs-symbol,
@@ -86,13 +86,13 @@
.hljs-link,
.hljs-meta,
.hljs-selector-id {
- color: #61aeee;
+ color: #61aeee;
}
.hljs-strong {
- font-weight: bold;
+ font-weight: bold;
}
.hljs-link {
- text-decoration: underline;
+ text-decoration: underline;
}
diff --git a/src/components/core/banners/art-basic-banner/index.vue b/src/components/core/banners/art-basic-banner/index.vue
index 65b47e4..0dd4303 100644
--- a/src/components/core/banners/art-basic-banner/index.vue
+++ b/src/components/core/banners/art-basic-banner/index.vue
@@ -1,343 +1,352 @@
-
-
-
-
-
+
+
+
+
+
-
-
-
- {{ title }}
-
+
+
+
+ {{
+ title
+ }}
+
-
-
- {{
- subtitle
- }}
-
+
+
+ {{ subtitle }}
+
-
-
-
- {{ buttonConfig?.text }}
-
-
+
+
+
+ {{ buttonConfig?.text }}
+
+
-
-
+
+
-
-
![背景图片]()
-
-
+
+
![背景图片]()
+
+
diff --git a/src/components/core/banners/art-card-banner/index.vue b/src/components/core/banners/art-card-banner/index.vue
index 8a5f9d4..0267547 100644
--- a/src/components/core/banners/art-card-banner/index.vue
+++ b/src/components/core/banners/art-card-banner/index.vue
@@ -1,114 +1,114 @@
-
-
-
-
![]()
-
-
-
{{ title }}
-
{{ description }}
-
-
-
- {{ cancelButton?.text }}
-
-
- {{ button?.text }}
-
-
-
-
+
+
+
+
![]()
+
+
+
{{ title }}
+
{{ description }}
+
+
+
+ {{ cancelButton?.text }}
+
+
+ {{ button?.text }}
+
+
+
+
diff --git a/src/components/core/base/art-back-to-top/index.vue b/src/components/core/base/art-back-to-top/index.vue
index 6f8da61..3cf0f18 100644
--- a/src/components/core/base/art-back-to-top/index.vue
+++ b/src/components/core/base/art-back-to-top/index.vue
@@ -1,40 +1,40 @@
-
-
-
+
+
+
diff --git a/src/components/core/base/art-logo/index.vue b/src/components/core/base/art-logo/index.vue
index 8bc8309..085e931 100644
--- a/src/components/core/base/art-logo/index.vue
+++ b/src/components/core/base/art-logo/index.vue
@@ -1,21 +1,21 @@
-
-

-
+
+

+
diff --git a/src/components/core/base/art-svg-icon/index.vue b/src/components/core/base/art-svg-icon/index.vue
index 0bfcd0c..c16f783 100644
--- a/src/components/core/base/art-svg-icon/index.vue
+++ b/src/components/core/base/art-svg-icon/index.vue
@@ -1,24 +1,24 @@
-
+
diff --git a/src/components/core/cards/art-bar-chart-card/index.vue b/src/components/core/cards/art-bar-chart-card/index.vue
index 6815c2b..82c6e5f 100644
--- a/src/components/core/cards/art-bar-chart-card/index.vue
+++ b/src/components/core/cards/art-bar-chart-card/index.vue
@@ -1,103 +1,108 @@
-
-
-
-
- {{ value }}
-
-
{{ label }}
-
-
- {{ percentage > 0 ? '+' : '' }}{{ percentage }}%
-
-
- {{ date }}
-
-
-
-
+
+
+
+
+ {{ value }}
+
+
{{ label }}
+
+
+ {{ percentage > 0 ? '+' : '' }}{{ percentage }}%
+
+
+ {{ date }}
+
+
+
+
diff --git a/src/components/core/cards/art-data-list-card/index.vue b/src/components/core/cards/art-data-list-card/index.vue
index fc43323..1f093a0 100644
--- a/src/components/core/cards/art-data-list-card/index.vue
+++ b/src/components/core/cards/art-data-list-card/index.vue
@@ -1,74 +1,74 @@
-
-
-
{{ title }}
-
{{ subtitle }}
-
-
-
-
-
-
{{ item.title }}
-
{{ item.status }}
-
-
{{ item.time }}
-
-
-
查看更多
-
+
+
+
{{ title }}
+
{{ subtitle }}
+
+
+
+
+
+
{{ item.title }}
+
{{ item.status }}
+
+
{{ item.time }}
+
+
+
查看更多
+
diff --git a/src/components/core/cards/art-donut-chart-card/index.vue b/src/components/core/cards/art-donut-chart-card/index.vue
index df2dcbb..1d6ff38 100644
--- a/src/components/core/cards/art-donut-chart-card/index.vue
+++ b/src/components/core/cards/art-donut-chart-card/index.vue
@@ -1,124 +1,124 @@
-
-
-
-
-
- {{ title }}
-
-
-
- {{ formatNumber(value) }}
-
-
- {{ percentage > 0 ? '+' : '' }}{{ percentage }}%
- {{ percentageLabel }}
-
-
-
-
-
-
- {{ previousValue }}
-
-
-
-
-
-
-
+
+
+
+
+
+ {{ title }}
+
+
+
+ {{ formatNumber(value) }}
+
+
+ {{ percentage > 0 ? '+' : '' }}{{ percentage }}%
+ {{ percentageLabel }}
+
+
+
+
+
+
+ {{ previousValue }}
+
+
+
+
+
+
+
diff --git a/src/components/core/cards/art-image-card/index.vue b/src/components/core/cards/art-image-card/index.vue
index d27fe00..30c5560 100644
--- a/src/components/core/cards/art-image-card/index.vue
+++ b/src/components/core/cards/art-image-card/index.vue
@@ -1,89 +1,89 @@
-
-
-
-
-
-
-
-
-
- {{ props.readTime }} 阅读
-
-
+
+
+
+
+
+
+
+
+
+ {{ props.readTime }} 阅读
+
+
-
-
- {{ props.category }}
-
-
{{ props.title }}
-
-
-
- {{ props.views }}
-
-
-
- {{ props.comments }}
-
- {{ props.date }}
-
-
-
-
+
+
+ {{ props.category }}
+
+
{{ props.title }}
+
+
+
+ {{ props.views }}
+
+
+
+ {{ props.comments }}
+
+ {{ props.date }}
+
+
+
+
diff --git a/src/components/core/cards/art-line-chart-card/index.vue b/src/components/core/cards/art-line-chart-card/index.vue
index e58c9b2..57dd214 100644
--- a/src/components/core/cards/art-line-chart-card/index.vue
+++ b/src/components/core/cards/art-line-chart-card/index.vue
@@ -1,126 +1,130 @@
-
-
-
-
- {{ value }}
-
-
{{ label }}
-
-
- {{ percentage > 0 ? '+' : '' }}{{ percentage }}%
-
-
- {{ date }}
-
-
-
-
+
+
+
+
+ {{ value }}
+
+
{{ label }}
+
+
+ {{ percentage > 0 ? '+' : '' }}{{ percentage }}%
+
+
+ {{ date }}
+
+
+
+
diff --git a/src/components/core/cards/art-progress-card/index.vue b/src/components/core/cards/art-progress-card/index.vue
index 048a836..b3e72ed 100644
--- a/src/components/core/cards/art-progress-card/index.vue
+++ b/src/components/core/cards/art-progress-card/index.vue
@@ -1,86 +1,89 @@
-
+
diff --git a/src/components/core/cards/art-stats-card/index.vue b/src/components/core/cards/art-stats-card/index.vue
index 8e0341b..42ea827 100644
--- a/src/components/core/cards/art-stats-card/index.vue
+++ b/src/components/core/cards/art-stats-card/index.vue
@@ -1,67 +1,71 @@
-
+
diff --git a/src/components/core/cards/art-timeline-list-card/index.vue b/src/components/core/cards/art-timeline-list-card/index.vue
index fbb2c78..d0e516e 100644
--- a/src/components/core/cards/art-timeline-list-card/index.vue
+++ b/src/components/core/cards/art-timeline-list-card/index.vue
@@ -1,69 +1,71 @@
-
-
-
{{ title }}
-
{{ subtitle }}
-
-
-
-
-
-
- {{ item.content }}
- #{{ item.code }}
-
-
-
-
-
-
+
+
+
{{ title }}
+
{{ subtitle }}
+
+
+
+
+
+
+ {{ item.content }}
+
+ #{{ item.code }}
+
+
+
+
+
+
+
diff --git a/src/components/core/charts/art-bar-chart/index.vue b/src/components/core/charts/art-bar-chart/index.vue
index d677196..b49f8be 100644
--- a/src/components/core/charts/art-bar-chart/index.vue
+++ b/src/components/core/charts/art-bar-chart/index.vue
@@ -1,203 +1,209 @@
-
+
diff --git a/src/components/core/charts/art-dual-bar-compare-chart/index.vue b/src/components/core/charts/art-dual-bar-compare-chart/index.vue
index 32aa60f..230c2c5 100644
--- a/src/components/core/charts/art-dual-bar-compare-chart/index.vue
+++ b/src/components/core/charts/art-dual-bar-compare-chart/index.vue
@@ -1,195 +1,195 @@
-
+
diff --git a/src/components/core/charts/art-h-bar-chart/index.vue b/src/components/core/charts/art-h-bar-chart/index.vue
index 2e34759..d1f1787 100644
--- a/src/components/core/charts/art-h-bar-chart/index.vue
+++ b/src/components/core/charts/art-h-bar-chart/index.vue
@@ -1,208 +1,214 @@
-
+
diff --git a/src/components/core/charts/art-k-line-chart/index.vue b/src/components/core/charts/art-k-line-chart/index.vue
index 0061b51..4d01016 100644
--- a/src/components/core/charts/art-k-line-chart/index.vue
+++ b/src/components/core/charts/art-k-line-chart/index.vue
@@ -1,90 +1,91 @@
-
+
diff --git a/src/components/core/charts/art-line-chart/index.vue b/src/components/core/charts/art-line-chart/index.vue
index b70c2c3..673038f 100644
--- a/src/components/core/charts/art-line-chart/index.vue
+++ b/src/components/core/charts/art-line-chart/index.vue
@@ -1,371 +1,377 @@
-
-
+
+
diff --git a/src/components/core/charts/art-radar-chart/index.vue b/src/components/core/charts/art-radar-chart/index.vue
index e99fff6..920eca7 100644
--- a/src/components/core/charts/art-radar-chart/index.vue
+++ b/src/components/core/charts/art-radar-chart/index.vue
@@ -1,105 +1,108 @@
-
+
diff --git a/src/components/core/charts/art-ring-chart/index.vue b/src/components/core/charts/art-ring-chart/index.vue
index 79115f7..de5ca4f 100644
--- a/src/components/core/charts/art-ring-chart/index.vue
+++ b/src/components/core/charts/art-ring-chart/index.vue
@@ -1,133 +1,133 @@
-
-
+
+
diff --git a/src/components/core/charts/art-scatter-chart/index.vue b/src/components/core/charts/art-scatter-chart/index.vue
index 995b56a..00400bd 100644
--- a/src/components/core/charts/art-scatter-chart/index.vue
+++ b/src/components/core/charts/art-scatter-chart/index.vue
@@ -1,115 +1,122 @@
-
-
+
+
diff --git a/src/components/core/forms/art-button-more/index.vue b/src/components/core/forms/art-button-more/index.vue
index 858d305..ce2c6cf 100644
--- a/src/components/core/forms/art-button-more/index.vue
+++ b/src/components/core/forms/art-button-more/index.vue
@@ -1,71 +1,74 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/core/forms/art-button-table/index.vue b/src/components/core/forms/art-button-table/index.vue
index c849901..867aa24 100644
--- a/src/components/core/forms/art-button-table/index.vue
+++ b/src/components/core/forms/art-button-table/index.vue
@@ -1,59 +1,59 @@
-
+
diff --git a/src/components/core/forms/art-drag-verify/index.vue b/src/components/core/forms/art-drag-verify/index.vue
index 5306e04..51d099c 100644
--- a/src/components/core/forms/art-drag-verify/index.vue
+++ b/src/components/core/forms/art-drag-verify/index.vue
@@ -1,430 +1,431 @@
-
-
-
-
+
+
+
+
-
-
-
- {{ message }}
-
-
+
+
+
+ {{ message }}
+
+
-
-
-
+
+
+
diff --git a/src/components/core/forms/art-excel-export/index.vue b/src/components/core/forms/art-excel-export/index.vue
index 08207c2..ed4d207 100644
--- a/src/components/core/forms/art-excel-export/index.vue
+++ b/src/components/core/forms/art-excel-export/index.vue
@@ -1,389 +1,399 @@
-
-
-
-
-
- {{ loadingText }}
-
- {{ buttonText }}
-
+
+
+
+
+
+ {{ loadingText }}
+
+ {{ buttonText }}
+
diff --git a/src/components/core/forms/art-excel-import/index.vue b/src/components/core/forms/art-excel-import/index.vue
index 8aa82fe..7104b99 100644
--- a/src/components/core/forms/art-excel-import/index.vue
+++ b/src/components/core/forms/art-excel-import/index.vue
@@ -1,62 +1,62 @@
-
-
-
- 导入 Excel
-
-
-
+
+
+
+ 导入 Excel
+
+
+
diff --git a/src/components/core/forms/art-form/index.vue b/src/components/core/forms/art-form/index.vue
index 1e76f14..40468ac 100644
--- a/src/components/core/forms/art-form/index.vue
+++ b/src/components/core/forms/art-form/index.vue
@@ -2,310 +2,323 @@
-
-
-
-
-
-
-
- {{ item.label }}
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+ {{ item.label }}
+
+
+
+
+
+
+
-
-
-
-
+
+
+
+
-
-
-
-
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
- {{ t('table.form.reset') }}
-
-
- {{ t('table.form.submit') }}
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ t('table.form.reset') }}
+
+
+ {{ t('table.form.submit') }}
+
+
+
+
+
+
+
diff --git a/src/components/core/forms/art-search-bar/index.vue b/src/components/core/forms/art-search-bar/index.vue
index b25b5bb..5d57aec 100644
--- a/src/components/core/forms/art-search-bar/index.vue
+++ b/src/components/core/forms/art-search-bar/index.vue
@@ -2,436 +2,455 @@
-
-
-
-
-
-
-
- {{ item.label }}
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+ {{ item.label }}
+
+
+
+
+
+
+
-
-
-
-
+
+
+
+
-
-
-
-
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/core/forms/art-wang-editor/index.vue b/src/components/core/forms/art-wang-editor/index.vue
index cfc457e..123c715 100644
--- a/src/components/core/forms/art-wang-editor/index.vue
+++ b/src/components/core/forms/art-wang-editor/index.vue
@@ -1,219 +1,222 @@
-
-
-
-
+
+
+
+
diff --git a/src/components/core/forms/art-wang-editor/style.scss b/src/components/core/forms/art-wang-editor/style.scss
index fd5dbca..64f09f3 100644
--- a/src/components/core/forms/art-wang-editor/style.scss
+++ b/src/components/core/forms/art-wang-editor/style.scss
@@ -2,209 +2,209 @@ $box-radius: calc(var(--custom-radius) / 3 + 2px);
// 全屏容器 z-index 调整
.w-e-full-screen-container {
- z-index: 100 !important;
+ z-index: 100 !important;
}
/* 编辑器容器 */
.editor-wrapper {
- width: 100%;
- height: 100%;
- border: 1px solid var(--art-gray-300);
- border-radius: $box-radius !important;
+ width: 100%;
+ height: 100%;
+ border: 1px solid var(--art-gray-300);
+ border-radius: $box-radius !important;
- .w-e-bar {
- border-radius: $box-radius $box-radius 0 0 !important;
- }
+ .w-e-bar {
+ border-radius: $box-radius $box-radius 0 0 !important;
+ }
- .menu-item {
- display: flex;
- flex-direction: row;
- align-items: center;
+ .menu-item {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
- i {
- margin-right: 5px;
- }
- }
+ i {
+ margin-right: 5px;
+ }
+ }
- /* 工具栏 */
- .editor-toolbar {
- border-bottom: 1px solid var(--default-border);
- }
+ /* 工具栏 */
+ .editor-toolbar {
+ border-bottom: 1px solid var(--default-border);
+ }
- /* 下拉选择框配置 */
- .w-e-select-list {
- min-width: 140px;
- padding: 5px 10px 10px;
- border: none;
- border-radius: $box-radius;
- }
+ /* 下拉选择框配置 */
+ .w-e-select-list {
+ min-width: 140px;
+ padding: 5px 10px 10px;
+ border: none;
+ border-radius: $box-radius;
+ }
- /* 下拉选择框元素配置 */
- .w-e-select-list ul li {
- margin-top: 5px;
- font-size: 15px !important;
- border-radius: $box-radius;
- }
+ /* 下拉选择框元素配置 */
+ .w-e-select-list ul li {
+ margin-top: 5px;
+ font-size: 15px !important;
+ border-radius: $box-radius;
+ }
- /* 下拉选择框 正文文字大小调整 */
- .w-e-select-list ul li:last-of-type {
- font-size: 16px !important;
- }
+ /* 下拉选择框 正文文字大小调整 */
+ .w-e-select-list ul li:last-of-type {
+ font-size: 16px !important;
+ }
- /* 下拉选择框 hover 样式调整 */
- .w-e-select-list ul li:hover {
- background-color: var(--art-gray-200);
- }
+ /* 下拉选择框 hover 样式调整 */
+ .w-e-select-list ul li:hover {
+ background-color: var(--art-gray-200);
+ }
- :root {
- /* 激活颜色 */
- --w-e-toolbar-active-bg-color: var(--art-gray-200);
+ :root {
+ /* 激活颜色 */
+ --w-e-toolbar-active-bg-color: var(--art-gray-200);
- /* toolbar 图标和文字颜色 */
- --w-e-toolbar-color: #000;
+ /* toolbar 图标和文字颜色 */
+ --w-e-toolbar-color: #000;
- /* 表格选中时候的边框颜色 */
- --w-e-textarea-selected-border-color: #ddd;
+ /* 表格选中时候的边框颜色 */
+ --w-e-textarea-selected-border-color: #ddd;
- /* 表格头背景颜色 */
- --w-e-textarea-slight-bg-color: var(--art-gray-200);
- }
+ /* 表格头背景颜色 */
+ --w-e-textarea-slight-bg-color: var(--art-gray-200);
+ }
- /* 工具栏按钮样式 */
- .w-e-bar-item svg {
- fill: var(--art-gray-800);
- }
+ /* 工具栏按钮样式 */
+ .w-e-bar-item svg {
+ fill: var(--art-gray-800);
+ }
- .w-e-bar-item button {
- color: var(--art-gray-800);
- border-radius: $box-radius;
- }
+ .w-e-bar-item button {
+ color: var(--art-gray-800);
+ border-radius: $box-radius;
+ }
- /* 工具栏 hover 按钮背景颜色 */
- .w-e-bar-item button:hover {
- background-color: var(--art-gray-200);
- }
+ /* 工具栏 hover 按钮背景颜色 */
+ .w-e-bar-item button:hover {
+ background-color: var(--art-gray-200);
+ }
- /* 工具栏分割线 */
- .w-e-bar-divider {
- height: 20px;
- margin-top: 10px;
- background-color: #ccc;
- }
+ /* 工具栏分割线 */
+ .w-e-bar-divider {
+ height: 20px;
+ margin-top: 10px;
+ background-color: #ccc;
+ }
- /* 工具栏菜单 */
- .w-e-bar-item-group .w-e-bar-item-menus-container {
- min-width: 120px;
- padding: 10px 0;
- border: none;
- border-radius: $box-radius;
+ /* 工具栏菜单 */
+ .w-e-bar-item-group .w-e-bar-item-menus-container {
+ min-width: 120px;
+ padding: 10px 0;
+ border: none;
+ border-radius: $box-radius;
- .w-e-bar-item {
- button {
- width: 100%;
- margin: 0 5px;
- }
- }
- }
+ .w-e-bar-item {
+ button {
+ width: 100%;
+ margin: 0 5px;
+ }
+ }
+ }
- /* 代码块 */
- .w-e-text-container [data-slate-editor] pre > code {
- padding: 0.6rem 1rem;
- background-color: var(--art-gray-50);
- border-radius: $box-radius;
- }
+ /* 代码块 */
+ .w-e-text-container [data-slate-editor] pre > code {
+ padding: 0.6rem 1rem;
+ background-color: var(--art-gray-50);
+ border-radius: $box-radius;
+ }
- /* 弹出框 */
- .w-e-drop-panel {
- border: 0;
- border-radius: $box-radius;
- }
+ /* 弹出框 */
+ .w-e-drop-panel {
+ border: 0;
+ border-radius: $box-radius;
+ }
- a {
- color: #318ef4;
- }
+ a {
+ color: #318ef4;
+ }
- .w-e-text-container {
- strong,
- b {
- font-weight: 500;
- }
+ .w-e-text-container {
+ strong,
+ b {
+ font-weight: 500;
+ }
- i,
- em {
- font-style: italic;
- }
- }
+ i,
+ em {
+ font-style: italic;
+ }
+ }
- /* 表格样式优化 */
- .w-e-text-container [data-slate-editor] .table-container th {
- border-right: none;
- }
+ /* 表格样式优化 */
+ .w-e-text-container [data-slate-editor] .table-container th {
+ border-right: none;
+ }
- .w-e-text-container [data-slate-editor] .table-container th:last-of-type {
- border-right: 1px solid #ccc !important;
- }
+ .w-e-text-container [data-slate-editor] .table-container th:last-of-type {
+ border-right: 1px solid #ccc !important;
+ }
- /* 引用 */
- .w-e-text-container [data-slate-editor] blockquote {
- background-color: var(--art-gray-200);
- border-left: 4px solid var(--art-gray-300);
- }
+ /* 引用 */
+ .w-e-text-container [data-slate-editor] blockquote {
+ background-color: var(--art-gray-200);
+ border-left: 4px solid var(--art-gray-300);
+ }
- /* 输入区域弹出 bar */
- .w-e-hover-bar {
- border-radius: $box-radius;
- }
+ /* 输入区域弹出 bar */
+ .w-e-hover-bar {
+ border-radius: $box-radius;
+ }
- /* 超链接弹窗 */
- .w-e-modal {
- border: none;
- border-radius: $box-radius;
- }
+ /* 超链接弹窗 */
+ .w-e-modal {
+ border: none;
+ border-radius: $box-radius;
+ }
- /* 图片样式调整 */
- .w-e-text-container [data-slate-editor] .w-e-selected-image-container {
- overflow: inherit;
+ /* 图片样式调整 */
+ .w-e-text-container [data-slate-editor] .w-e-selected-image-container {
+ overflow: inherit;
- &:hover {
- border: 0;
- }
+ &:hover {
+ border: 0;
+ }
- img {
- border: 1px solid transparent;
- transition: border 0.3s;
+ img {
+ border: 1px solid transparent;
+ transition: border 0.3s;
- &:hover {
- border: 1px solid #318ef4 !important;
- }
- }
+ &:hover {
+ border: 1px solid #318ef4 !important;
+ }
+ }
- .w-e-image-dragger {
- width: 12px;
- height: 12px;
- background-color: #318ef4;
- border: 2px solid #fff;
- border-radius: $box-radius;
- }
+ .w-e-image-dragger {
+ width: 12px;
+ height: 12px;
+ background-color: #318ef4;
+ border: 2px solid #fff;
+ border-radius: $box-radius;
+ }
- .left-top {
- top: -6px;
- left: -6px;
- }
+ .left-top {
+ top: -6px;
+ left: -6px;
+ }
- .right-top {
- top: -6px;
- right: -6px;
- }
+ .right-top {
+ top: -6px;
+ right: -6px;
+ }
- .left-bottom {
- bottom: -6px;
- left: -6px;
- }
+ .left-bottom {
+ bottom: -6px;
+ left: -6px;
+ }
- .right-bottom {
- right: -6px;
- bottom: -6px;
- }
- }
+ .right-bottom {
+ right: -6px;
+ bottom: -6px;
+ }
+ }
}
diff --git a/src/components/core/layouts/art-breadcrumb/index.vue b/src/components/core/layouts/art-breadcrumb/index.vue
index 4b54859..0c6b040 100644
--- a/src/components/core/layouts/art-breadcrumb/index.vue
+++ b/src/components/core/layouts/art-breadcrumb/index.vue
@@ -1,142 +1,142 @@
-
+
diff --git a/src/components/core/layouts/art-chat-window/index.vue b/src/components/core/layouts/art-chat-window/index.vue
index f3d9471..f5876b5 100644
--- a/src/components/core/layouts/art-chat-window/index.vue
+++ b/src/components/core/layouts/art-chat-window/index.vue
@@ -1,262 +1,279 @@
-
-
-
-
-
Art Bot
-
-
-
{{ isOnline ? '在线' : '离线' }}
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
Art Bot
+
+
+
{{ isOnline ? '在线' : '离线' }}
+
+
+
+
+
+
+
+
+
-
-
+
+
+
+
+
diff --git a/src/components/core/layouts/art-fast-enter/index.vue b/src/components/core/layouts/art-fast-enter/index.vue
index fdde222..f2a7c14 100644
--- a/src/components/core/layouts/art-fast-enter/index.vue
+++ b/src/components/core/layouts/art-fast-enter/index.vue
@@ -1,113 +1,117 @@
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-
-
-
-
{{ application.name }}
-
{{ application.description }}
-
-
-
-
+
+
+
+
+
+
+
+
{{
+ application.name
+ }}
+
{{ application.description }}
+
+
+
+
-
-
快速链接
-
- -
- {{ quickLink.name }}
-
-
-
-
-
+
+
快速链接
+
+ -
+ {{ quickLink.name }}
+
+
+
+
+
diff --git a/src/components/core/layouts/art-fireworks-effect/index.vue b/src/components/core/layouts/art-fireworks-effect/index.vue
index be85274..06425d8 100644
--- a/src/components/core/layouts/art-fireworks-effect/index.vue
+++ b/src/components/core/layouts/art-fireworks-effect/index.vue
@@ -1,633 +1,643 @@
-
+
diff --git a/src/components/core/layouts/art-global-component/index.vue b/src/components/core/layouts/art-global-component/index.vue
index 6908f94..97e2e95 100644
--- a/src/components/core/layouts/art-global-component/index.vue
+++ b/src/components/core/layouts/art-global-component/index.vue
@@ -1,14 +1,14 @@
-
+
diff --git a/src/components/core/layouts/art-global-search/index.vue b/src/components/core/layouts/art-global-search/index.vue
index a7d88df..3914981 100644
--- a/src/components/core/layouts/art-global-search/index.vue
+++ b/src/components/core/layouts/art-global-search/index.vue
@@ -1,417 +1,430 @@
-
-
-
-
-
-
-
-
-
-
-
- {{ formatMenuTitle(item.meta.title) }}
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+ {{ formatMenuTitle(item.meta.title) }}
+
+
+
+
-
-
{{ $t('search.historyTitle') }}
-
-
- {{ formatMenuTitle(item.meta.title) }}
-
-
-
-
-
+
+
{{ $t('search.historyTitle') }}
+
+
+ {{ formatMenuTitle(item.meta.title) }}
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
diff --git a/src/components/core/layouts/art-header-bar/index.vue b/src/components/core/layouts/art-header-bar/index.vue
index 4e3c8f9..0bf51fb 100644
--- a/src/components/core/layouts/art-header-bar/index.vue
+++ b/src/components/core/layouts/art-header-bar/index.vue
@@ -1,485 +1,509 @@
-
-
-
-
-
-
-
{{ AppConfig.systemInfo.name }}
-
+
+
+
+
+
+
+
{{
+ AppConfig.systemInfo.name
+ }}
+
-
+
-
-
+
+
-
-
+
+
-
-
-
-
+
+
+
+
-
-
+
+
-
-
+
+
-
-
-
+
+
+
-
-
-
-
-
-
{{ $t('topBar.search.title') }}
-
-
-
+
+
+
+
+
+
{{
+ $t('topBar.search.title')
+ }}
+
+
+
-
-
+
+
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
-
-
-
+
+
+
+
-
-
-
-
+
+
+
+
-
-
-
-
-
-
-
- {{ $t('topBar.guide.title')
- }} {{ $t('topBar.guide.theme') }} 、 {{ $t('topBar.guide.menu') }} {{ $t('topBar.guide.description') }}
-
-
-
-
+
+
+
+
+
+
+
+ {{ $t('topBar.guide.title')
+ }}
+ {{ $t('topBar.guide.theme') }} 、
+
+ {{ $t('topBar.guide.menu') }} {{ $t('topBar.guide.description') }}
+
+
+
+
-
-
+
+
-
-
-
-
+
+
+
+
-
-
+
+
-
-
-
+
+
+
diff --git a/src/components/core/layouts/art-header-bar/widget/ArtUserMenu.vue b/src/components/core/layouts/art-header-bar/widget/ArtUserMenu.vue
index c8c5832..44618d5 100644
--- a/src/components/core/layouts/art-header-bar/widget/ArtUserMenu.vue
+++ b/src/components/core/layouts/art-header-bar/widget/ArtUserMenu.vue
@@ -1,159 +1,161 @@
-
-
-
-
-
-
-
-

-
- {{
- userInfo.userName
- }}
- {{ userInfo.email }}
-
-
-
-
-
-
+
+
+
+
+
+
+
+

+
+ {{
+ userInfo.userName
+ }}
+ {{
+ userInfo.email
+ }}
+
+
+
+
+
+
diff --git a/src/components/core/layouts/art-menus/art-horizontal-menu/index.vue b/src/components/core/layouts/art-menus/art-horizontal-menu/index.vue
index edd1473..a1add75 100644
--- a/src/components/core/layouts/art-menus/art-horizontal-menu/index.vue
+++ b/src/components/core/layouts/art-menus/art-horizontal-menu/index.vue
@@ -1,110 +1,110 @@
-
-
-
-
-
+
+
+
+
+
diff --git a/src/components/core/layouts/art-menus/art-horizontal-menu/widget/HorizontalSubmenu.vue b/src/components/core/layouts/art-menus/art-horizontal-menu/widget/HorizontalSubmenu.vue
index ff32c1e..0fb7048 100644
--- a/src/components/core/layouts/art-menus/art-horizontal-menu/widget/HorizontalSubmenu.vue
+++ b/src/components/core/layouts/art-menus/art-horizontal-menu/widget/HorizontalSubmenu.vue
@@ -1,95 +1,95 @@
-
-
-
- {{ formatMenuTitle(item.meta.title) }}
-
-
- {{ item.meta.showTextBadge }}
-
-
+
+
+
+ {{ formatMenuTitle(item.meta.title) }}
+
+
+ {{ item.meta.showTextBadge }}
+
+
-
-
-
+
+
+
-
-
- {{ formatMenuTitle(item.meta.title) }}
-
-
- {{ item.meta.showTextBadge }}
-
-
+
+
+ {{ formatMenuTitle(item.meta.title) }}
+
+
+ {{ item.meta.showTextBadge }}
+
+
diff --git a/src/components/core/layouts/art-menus/art-mixed-menu/index.vue b/src/components/core/layouts/art-menus/art-mixed-menu/index.vue
index 4e98246..cbeea0b 100644
--- a/src/components/core/layouts/art-menus/art-mixed-menu/index.vue
+++ b/src/components/core/layouts/art-menus/art-mixed-menu/index.vue
@@ -1,234 +1,237 @@
-
-
-
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
-
+
+
+
diff --git a/src/components/core/layouts/art-menus/art-sidebar-menu/index.vue b/src/components/core/layouts/art-menus/art-sidebar-menu/index.vue
index 39387dc..0b3d5bd 100644
--- a/src/components/core/layouts/art-menus/art-sidebar-menu/index.vue
+++ b/src/components/core/layouts/art-menus/art-sidebar-menu/index.vue
@@ -1,355 +1,362 @@
-
diff --git a/src/components/core/layouts/art-menus/art-sidebar-menu/style.scss b/src/components/core/layouts/art-menus/art-sidebar-menu/style.scss
index b98011c..67aeeb9 100644
--- a/src/components/core/layouts/art-menus/art-sidebar-menu/style.scss
+++ b/src/components/core/layouts/art-menus/art-sidebar-menu/style.scss
@@ -1,253 +1,253 @@
.layout-sidebar {
- display: flex;
- height: 100vh;
- user-select: none;
- scrollbar-width: none;
- border-right: 1px solid var(--art-card-border);
+ display: flex;
+ height: 100vh;
+ user-select: none;
+ scrollbar-width: none;
+ border-right: 1px solid var(--art-card-border);
- &.no-border {
- border-right: none !important;
- }
+ &.no-border {
+ border-right: none !important;
+ }
- // 自定义滚动条宽度
- :deep(.el-scrollbar__bar.is-vertical) {
- width: 4px;
- }
+ // 自定义滚动条宽度
+ :deep(.el-scrollbar__bar.is-vertical) {
+ width: 4px;
+ }
- :deep(.el-scrollbar__thumb) {
- right: -2px;
- background-color: #ccc;
- border-radius: 2px;
- }
+ :deep(.el-scrollbar__thumb) {
+ right: -2px;
+ background-color: #ccc;
+ border-radius: 2px;
+ }
- .dual-menu-left {
- position: relative;
- width: 80px;
- height: 100%;
- border-right: 1px solid var(--art-card-border) !important;
- transition: width 0.25s;
+ .dual-menu-left {
+ position: relative;
+ width: 80px;
+ height: 100%;
+ border-right: 1px solid var(--art-card-border) !important;
+ transition: width 0.25s;
- .logo {
- margin: auto;
- margin-top: 12px;
- margin-bottom: 3px;
- cursor: pointer;
- }
+ .logo {
+ margin: auto;
+ margin-top: 12px;
+ margin-bottom: 3px;
+ cursor: pointer;
+ }
- ul {
- li {
- > div {
- position: relative;
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- margin: 8px;
- overflow: hidden;
- text-align: center;
- cursor: pointer;
- border-radius: 5px;
+ ul {
+ li {
+ > div {
+ position: relative;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ margin: 8px;
+ overflow: hidden;
+ text-align: center;
+ cursor: pointer;
+ border-radius: 5px;
- .art-svg-icon {
- display: block;
- margin: 0 auto;
- font-size: 20px;
- }
+ .art-svg-icon {
+ display: block;
+ margin: 0 auto;
+ font-size: 20px;
+ }
- span {
- display: -webkit-box;
- width: 100%;
- overflow: hidden;
- font-size: 12px;
- text-overflow: ellipsis;
- -webkit-line-clamp: 1;
- line-clamp: 1;
- -webkit-box-orient: vertical;
- }
+ span {
+ display: -webkit-box;
+ width: 100%;
+ overflow: hidden;
+ font-size: 12px;
+ text-overflow: ellipsis;
+ -webkit-line-clamp: 1;
+ line-clamp: 1;
+ -webkit-box-orient: vertical;
+ }
- &.is-active {
- background: var(--el-color-primary-light-9);
+ &.is-active {
+ background: var(--el-color-primary-light-9);
- .art-svg-icon,
- span {
- color: var(--theme-color) !important;
- }
- }
- }
- }
- }
+ .art-svg-icon,
+ span {
+ color: var(--theme-color) !important;
+ }
+ }
+ }
+ }
+ }
- .switch-btn {
- position: absolute;
- right: 0;
- bottom: 15px;
- left: 0;
- margin: auto;
- }
- }
+ .switch-btn {
+ position: absolute;
+ right: 0;
+ bottom: 15px;
+ left: 0;
+ margin: auto;
+ }
+ }
- .menu-left {
- position: relative;
- box-sizing: border-box;
- height: 100vh;
+ .menu-left {
+ position: relative;
+ box-sizing: border-box;
+ height: 100vh;
- @media only screen and (width <= 640px) {
- height: 100dvh;
- }
+ @media only screen and (width <= 640px) {
+ height: 100dvh;
+ }
- .el-menu {
- height: 100%;
- }
+ .el-menu {
+ height: 100%;
+ }
- &:hover {
- .dual-menu-collapse-btn {
- opacity: 1 !important;
- }
- }
+ &:hover {
+ .dual-menu-collapse-btn {
+ opacity: 1 !important;
+ }
+ }
- .dual-menu-collapse-btn {
- position: absolute;
- top: 50%;
- right: -11px;
- z-index: 10;
- width: 11px;
- height: 50px;
- cursor: pointer;
- background-color: var(--default-box-color);
- border: 1px solid var(--art-card-border);
- border-radius: 0 15px 15px 0;
- opacity: 0;
- transition: opacity 0.2s;
- transform: translateY(-50%);
+ .dual-menu-collapse-btn {
+ position: absolute;
+ top: 50%;
+ right: -11px;
+ z-index: 10;
+ width: 11px;
+ height: 50px;
+ cursor: pointer;
+ background-color: var(--default-box-color);
+ border: 1px solid var(--art-card-border);
+ border-radius: 0 15px 15px 0;
+ opacity: 0;
+ transition: opacity 0.2s;
+ transform: translateY(-50%);
- &:hover {
- .art-svg-icon {
- color: var(--art-gray-800) !important;
- }
- }
+ &:hover {
+ .art-svg-icon {
+ color: var(--art-gray-800) !important;
+ }
+ }
- .art-svg-icon {
- position: absolute;
- top: 0;
- bottom: 0;
- left: -4px;
- margin: auto;
- transition: all 0.3s;
- }
- }
- }
+ .art-svg-icon {
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ left: -4px;
+ margin: auto;
+ transition: all 0.3s;
+ }
+ }
+ }
- .header {
- position: relative;
- box-sizing: border-box;
- display: flex;
- align-items: center;
- width: 100%;
- height: 60px;
- overflow: hidden;
- line-height: 60px;
- cursor: pointer;
+ .header {
+ position: relative;
+ box-sizing: border-box;
+ display: flex;
+ align-items: center;
+ width: 100%;
+ height: 60px;
+ overflow: hidden;
+ line-height: 60px;
+ cursor: pointer;
- .logo {
- margin-left: 22px;
- }
+ .logo {
+ margin-left: 22px;
+ }
- p {
- position: absolute;
- top: 0;
- bottom: 0;
- left: 58px;
- box-sizing: border-box;
- margin-left: 10px;
- font-size: 18px;
+ p {
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ left: 58px;
+ box-sizing: border-box;
+ margin-left: 10px;
+ font-size: 18px;
- &.is-dual-menu-name {
- left: 25px;
- margin: auto;
- }
- }
- }
+ &.is-dual-menu-name {
+ left: 25px;
+ margin: auto;
+ }
+ }
+ }
- .el-menu {
- box-sizing: border-box;
- height: calc(100vh - 60px);
- overflow-y: auto;
- // 防止菜单内的滚动影响整个页面滚动
- overscroll-behavior: contain;
- border-right: 0;
- scrollbar-width: none;
- -ms-scroll-chaining: contain;
+ .el-menu {
+ box-sizing: border-box;
+ height: calc(100vh - 60px);
+ overflow-y: auto;
+ // 防止菜单内的滚动影响整个页面滚动
+ overscroll-behavior: contain;
+ border-right: 0;
+ scrollbar-width: none;
+ -ms-scroll-chaining: contain;
- &::-webkit-scrollbar {
- width: 0 !important;
- }
- }
+ &::-webkit-scrollbar {
+ width: 0 !important;
+ }
+ }
- .menu-model {
- display: none;
- }
+ .menu-model {
+ display: none;
+ }
}
@media only screen and (width <= 800px) {
- .layout-sidebar {
- width: 0;
+ .layout-sidebar {
+ width: 0;
- .header {
- height: 50px;
- line-height: 50px;
- }
+ .header {
+ height: 50px;
+ line-height: 50px;
+ }
- .el-menu {
- height: calc(100vh - 60px);
- }
+ .el-menu {
+ height: calc(100vh - 60px);
+ }
- .el-menu--collapse {
- width: 0;
- }
+ .el-menu--collapse {
+ width: 0;
+ }
- // 折叠状态下的header样式
- .menu-left-close .header {
- .logo {
- display: none;
- }
+ // 折叠状态下的header样式
+ .menu-left-close .header {
+ .logo {
+ display: none;
+ }
- p {
- left: 16px;
- font-size: 0;
- opacity: 0 !important;
- }
- }
+ p {
+ left: 16px;
+ font-size: 0;
+ opacity: 0 !important;
+ }
+ }
- .menu-model {
- position: fixed;
- top: 0;
- left: 0;
- z-index: -1;
- display: block;
- width: 100%;
- height: 100vh;
- background: rgba($color: #000, $alpha: 50%);
- transition: opacity 0.2s ease-in-out;
- }
- }
+ .menu-model {
+ position: fixed;
+ top: 0;
+ left: 0;
+ z-index: -1;
+ display: block;
+ width: 100%;
+ height: 100vh;
+ background: rgba($color: #000, $alpha: 50%);
+ transition: opacity 0.2s ease-in-out;
+ }
+ }
}
@media only screen and (width <= 640px) {
- .layout-sidebar {
- border-right: 0 !important;
- }
+ .layout-sidebar {
+ border-right: 0 !important;
+ }
}
.dark {
- .layout-sidebar {
- border-right: 1px solid rgb(255 255 255 / 13%);
+ .layout-sidebar {
+ border-right: 1px solid rgb(255 255 255 / 13%);
- :deep(.el-scrollbar__thumb) {
- background-color: #777;
- }
+ :deep(.el-scrollbar__thumb) {
+ background-color: #777;
+ }
- .dual-menu-left {
- border-right: 1px solid rgb(255 255 255 / 9%) !important;
- }
- }
+ .dual-menu-left {
+ border-right: 1px solid rgb(255 255 255 / 9%) !important;
+ }
+ }
}
diff --git a/src/components/core/layouts/art-menus/art-sidebar-menu/theme.scss b/src/components/core/layouts/art-menus/art-sidebar-menu/theme.scss
index 7626c42..64933fb 100644
--- a/src/components/core/layouts/art-menus/art-sidebar-menu/theme.scss
+++ b/src/components/core/layouts/art-menus/art-sidebar-menu/theme.scss
@@ -12,247 +12,247 @@ $popup-menu-radius: 6px;
// 通用菜单项样式
@mixin menu-item-base {
- width: calc(100% - 16px);
- margin-left: 8px;
- border-radius: 6px;
+ width: calc(100% - 16px);
+ margin-left: 8px;
+ border-radius: 6px;
- .menu-icon {
- margin-left: -7px;
- }
+ .menu-icon {
+ margin-left: -7px;
+ }
}
// 通用 hover 样式
@mixin menu-hover($bg-color) {
- .el-sub-menu__title:hover,
- .el-menu-item:not(.is-active):hover {
- background: $bg-color !important;
- }
+ .el-sub-menu__title:hover,
+ .el-menu-item:not(.is-active):hover {
+ background: $bg-color !important;
+ }
}
// 通用选中样式
@mixin menu-active($color, $bg-color, $icon-color: var(--theme-color)) {
- .el-menu-item.is-active {
- color: $color !important;
- background-color: $bg-color;
+ .el-menu-item.is-active {
+ color: $color !important;
+ background-color: $bg-color;
- .menu-icon {
- .art-svg-icon {
- color: $icon-color !important;
- }
- }
- }
+ .menu-icon {
+ .art-svg-icon {
+ color: $icon-color !important;
+ }
+ }
+ }
}
// 弹窗菜单项样式
@mixin popup-menu-item {
- height: $popup-menu-height;
- margin-bottom: $popup-menu-margin;
- border-radius: $popup-menu-radius;
+ height: $popup-menu-height;
+ margin-bottom: $popup-menu-margin;
+ border-radius: $popup-menu-radius;
- .menu-icon {
- margin-right: 5px;
- }
+ .menu-icon {
+ margin-right: 5px;
+ }
- &:last-of-type {
- margin-bottom: 0;
- }
+ &:last-of-type {
+ margin-bottom: 0;
+ }
}
// 主题菜单通用样式(合并 design 和 dark 主题的共同逻辑)
@mixin theme-menu-base {
- .el-sub-menu__title,
- .el-menu-item {
- @include menu-item-base;
- }
+ .el-sub-menu__title,
+ .el-menu-item {
+ @include menu-item-base;
+ }
}
// 弹窗菜单通用样式
@mixin popup-menu-base($hover-bg, $active-color, $active-bg) {
- .el-menu--popup {
- padding: $popup-menu-padding;
+ .el-menu--popup {
+ padding: $popup-menu-padding;
- .el-sub-menu__title:hover,
- .el-menu-item:hover {
- background-color: $hover-bg !important;
- border-radius: $popup-menu-radius;
- }
+ .el-sub-menu__title:hover,
+ .el-menu-item:hover {
+ background-color: $hover-bg !important;
+ border-radius: $popup-menu-radius;
+ }
- .el-menu-item {
- @include popup-menu-item;
+ .el-menu-item {
+ @include popup-menu-item;
- &.is-active {
- color: $active-color !important;
- background-color: $active-bg !important;
- }
- }
+ &.is-active {
+ color: $active-color !important;
+ background-color: $active-bg !important;
+ }
+ }
- .el-sub-menu {
- @include popup-menu-item;
+ .el-sub-menu {
+ @include popup-menu-item;
- height: $popup-menu-height !important;
+ height: $popup-menu-height !important;
- .el-sub-menu__title {
- height: $popup-menu-height !important;
- border-radius: $popup-menu-radius;
- }
- }
- }
+ .el-sub-menu__title {
+ height: $popup-menu-height !important;
+ border-radius: $popup-menu-radius;
+ }
+ }
+ }
}
.layout-sidebar {
- // ---------------------- Modify default style ----------------------
+ // ---------------------- Modify default style ----------------------
- // 菜单折叠样式
- .menu-left-close {
- .header {
- .logo {
- margin: 0 auto;
- }
- }
- }
+ // 菜单折叠样式
+ .menu-left-close {
+ .header {
+ .logo {
+ margin: 0 auto;
+ }
+ }
+ }
- // 菜单图标
- .menu-icon {
- margin-right: 8px;
- font-size: $menu-icon-size;
- }
+ // 菜单图标
+ .menu-icon {
+ margin-right: 8px;
+ font-size: $menu-icon-size;
+ }
- // 菜单高度
- .el-sub-menu__title,
- .el-menu-item {
- height: $menu-height !important;
- margin-bottom: 4px;
- line-height: $menu-height !important;
+ // 菜单高度
+ .el-sub-menu__title,
+ .el-menu-item {
+ height: $menu-height !important;
+ margin-bottom: 4px;
+ line-height: $menu-height !important;
- span {
- font-size: $menu-font-size !important;
+ span {
+ font-size: $menu-font-size !important;
- @include ellipsis();
- }
- }
+ @include ellipsis();
+ }
+ }
- // 右侧箭头
- .el-sub-menu__icon-arrow {
- width: 13px !important;
- font-size: 13px !important;
- }
+ // 右侧箭头
+ .el-sub-menu__icon-arrow {
+ width: 13px !important;
+ font-size: 13px !important;
+ }
- // 菜单折叠
- .el-menu--collapse {
- .el-sub-menu.is-active {
- .el-sub-menu__title {
- .menu-icon {
- .art-svg-icon {
- // 选中菜单图标颜色
- color: var(--theme-color) !important;
- }
- }
- }
- }
- }
+ // 菜单折叠
+ .el-menu--collapse {
+ .el-sub-menu.is-active {
+ .el-sub-menu__title {
+ .menu-icon {
+ .art-svg-icon {
+ // 选中菜单图标颜色
+ color: var(--theme-color) !important;
+ }
+ }
+ }
+ }
+ }
- // ---------------------- Design theme menu ----------------------
- .el-menu-design {
- @include theme-menu-base;
- @include menu-active(var(--theme-color), var(--el-color-primary-light-9));
- @include menu-hover($hover-bg-color);
+ // ---------------------- Design theme menu ----------------------
+ .el-menu-design {
+ @include theme-menu-base;
+ @include menu-active(var(--theme-color), var(--el-color-primary-light-9));
+ @include menu-hover($hover-bg-color);
- .el-sub-menu__icon-arrow {
- color: var(--art-gray-600);
- }
- }
+ .el-sub-menu__icon-arrow {
+ color: var(--art-gray-600);
+ }
+ }
- // ---------------------- Dark theme menu ----------------------
- .el-menu-dark {
- @include theme-menu-base;
- @include menu-active(#fff, #27282d, #fff);
- @include menu-hover(#0f1015);
+ // ---------------------- Dark theme menu ----------------------
+ .el-menu-dark {
+ @include theme-menu-base;
+ @include menu-active(#fff, #27282d, #fff);
+ @include menu-hover(#0f1015);
- .el-sub-menu__icon-arrow {
- color: var(--art-gray-400);
- }
- }
+ .el-sub-menu__icon-arrow {
+ color: var(--art-gray-400);
+ }
+ }
- // ---------------------- Light theme menu ----------------------
- .el-menu-light {
- .el-sub-menu__title,
- .el-menu-item {
- .menu-icon {
- margin-left: 1px;
- }
- }
+ // ---------------------- Light theme menu ----------------------
+ .el-menu-light {
+ .el-sub-menu__title,
+ .el-menu-item {
+ .menu-icon {
+ margin-left: 1px;
+ }
+ }
- .el-menu-item.is-active {
- background-color: var(--el-color-primary-light-9);
+ .el-menu-item.is-active {
+ background-color: var(--el-color-primary-light-9);
- .art-svg-icon {
- color: var(--theme-color) !important;
- }
+ .art-svg-icon {
+ color: var(--theme-color) !important;
+ }
- &::before {
- position: absolute;
- top: 0;
- left: 0;
- width: 4px;
- height: 100%;
- content: '';
- background: var(--theme-color);
- }
- }
+ &::before {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 4px;
+ height: 100%;
+ content: '';
+ background: var(--theme-color);
+ }
+ }
- @include menu-hover($hover-bg-color);
+ @include menu-hover($hover-bg-color);
- .el-sub-menu__icon-arrow {
- color: var(--art-gray-600);
- }
- }
+ .el-sub-menu__icon-arrow {
+ color: var(--art-gray-600);
+ }
+ }
}
@media only screen and (width <= 640px) {
- .layout-sidebar {
- .el-menu-design {
- > .el-sub-menu {
- margin-left: 0;
- }
+ .layout-sidebar {
+ .el-menu-design {
+ > .el-sub-menu {
+ margin-left: 0;
+ }
- .el-sub-menu {
- width: 100% !important;
- }
- }
- }
+ .el-sub-menu {
+ width: 100% !important;
+ }
+ }
+ }
}
// 菜单折叠 hover 弹窗样式(浅色主题)
.el-menu--vertical,
.el-menu--popup-container {
- @include popup-menu-base(var(--art-gray-200), var(--art-gray-900), var(--art-gray-200));
+ @include popup-menu-base(var(--art-gray-200), var(--art-gray-900), var(--art-gray-200));
}
// 暗黑模式菜单样式
.dark {
- .el-menu--vertical,
- .el-menu--popup-container {
- @include popup-menu-base(var(--art-gray-200), var(--art-gray-900), #292a2e);
- }
+ .el-menu--vertical,
+ .el-menu--popup-container {
+ @include popup-menu-base(var(--art-gray-200), var(--art-gray-900), #292a2e);
+ }
- .layout-sidebar {
- // 图标颜色、文字颜色
- .menu-icon .art-svg-icon,
- .menu-name {
- color: var(--art-gray-800) !important;
- }
+ .layout-sidebar {
+ // 图标颜色、文字颜色
+ .menu-icon .art-svg-icon,
+ .menu-name {
+ color: var(--art-gray-800) !important;
+ }
- // 选中的文字颜色跟图标颜色
- .el-menu-item.is-active {
- span,
- .menu-icon .art-svg-icon {
- color: var(--theme-color) !important;
- }
- }
+ // 选中的文字颜色跟图标颜色
+ .el-menu-item.is-active {
+ span,
+ .menu-icon .art-svg-icon {
+ color: var(--theme-color) !important;
+ }
+ }
- // 右侧箭头颜色
- .el-sub-menu__icon-arrow {
- color: #fff;
- }
- }
+ // 右侧箭头颜色
+ .el-sub-menu__icon-arrow {
+ color: #fff;
+ }
+ }
}
diff --git a/src/components/core/layouts/art-menus/art-sidebar-menu/widget/SidebarSubmenu.vue b/src/components/core/layouts/art-menus/art-sidebar-menu/widget/SidebarSubmenu.vue
index a7ac6a9..4721773 100644
--- a/src/components/core/layouts/art-menus/art-sidebar-menu/widget/SidebarSubmenu.vue
+++ b/src/components/core/layouts/art-menus/art-sidebar-menu/widget/SidebarSubmenu.vue
@@ -1,188 +1,191 @@
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
+
+
-
-
-
+
+
+
-
-
-
-
- {{ item.meta.showTextBadge }}
-
-
-
-
+
+
+
+
+ {{ item.meta.showTextBadge }}
+
+
+
+
diff --git a/src/components/core/layouts/art-notification/index.vue b/src/components/core/layouts/art-notification/index.vue
index a58853c..d0448c5 100644
--- a/src/components/core/layouts/art-notification/index.vue
+++ b/src/components/core/layouts/art-notification/index.vue
@@ -1,427 +1,432 @@
-
-
- {{ $t('notice.title') }}
-
- {{ $t('notice.btnRead') }}
-
-
+
+
+ {{ $t('notice.title') }}
+
+ {{ $t('notice.btnRead') }}
+
+
-
- -
- {{ item.name }} ({{ item.num }})
-
-
+
+ -
+ {{ item.name }} ({{ item.num }})
+
+
-
-
+
+
+ {{ $t('notice.viewAll') }}
+
+
+
-
-
+
+
diff --git a/src/components/core/layouts/art-page-content/index.vue b/src/components/core/layouts/art-page-content/index.vue
index a862df1..b19fb86 100644
--- a/src/components/core/layouts/art-page-content/index.vue
+++ b/src/components/core/layouts/art-page-content/index.vue
@@ -1,136 +1,136 @@
-
diff --git a/src/components/core/layouts/art-screen-lock/index.vue b/src/components/core/layouts/art-screen-lock/index.vue
index 5bf5248..2825220 100644
--- a/src/components/core/layouts/art-screen-lock/index.vue
+++ b/src/components/core/layouts/art-screen-lock/index.vue
@@ -1,519 +1,530 @@
-
-
-
-
-
🔒
-
系统已锁定
-
- 检测到开发者工具已打开
- 为了系统安全,请关闭开发者工具后继续使用
-
-
Security Lock Activated
-
-
+
+
+
+
+
🔒
+
系统已锁定
+
+ 检测到开发者工具已打开
+ 为了系统安全,请关闭开发者工具后继续使用
+
+
Security Lock Activated
+
+
-
-
-
-
-

-
{{ userInfo.userName }}
-
-
-
-
-
-
-
-
-
-
-
- {{ $t('lockScreen.lock.btnText') }}
-
-
-
-
-
+
+
+
+
+

+
{{ userInfo.userName }}
+
+
+
+
+
+
+
+
+
+
+
+ {{ $t('lockScreen.lock.btnText') }}
+
+
+
+
+
-
-
-
-

-
- {{ userInfo.userName }}
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+

+
+ {{ userInfo.userName }}
+
+
+
+
+
+
+
+
+
+
+
-
- {{ $t('lockScreen.unlock.btnText') }}
-
-
-
- {{ $t('lockScreen.unlock.backBtnText') }}
-
-
-
-
-
-
+
+ {{ $t('lockScreen.unlock.btnText') }}
+
+
+
+ {{ $t('lockScreen.unlock.backBtnText') }}
+
+
+
+
+
+
diff --git a/src/components/core/layouts/art-settings-panel/composables/useSettingsConfig.ts b/src/components/core/layouts/art-settings-panel/composables/useSettingsConfig.ts
index 35e8066..76438c1 100644
--- a/src/components/core/layouts/art-settings-panel/composables/useSettingsConfig.ts
+++ b/src/components/core/layouts/art-settings-panel/composables/useSettingsConfig.ts
@@ -8,241 +8,241 @@ import { headerBarConfig } from '@/config/modules/headerBar'
* 设置项配置选项管理
*/
export function useSettingsConfig() {
- const { t } = useI18n()
+ const { t } = useI18n()
- // 标签页风格选项
- const tabStyleOptions = computed(() => [
- {
- value: 'tab-default',
- label: t('setting.tabStyle.default')
- },
- {
- value: 'tab-card',
- label: t('setting.tabStyle.card')
- },
- {
- value: 'tab-google',
- label: t('setting.tabStyle.google')
- }
- ])
+ // 标签页风格选项
+ const tabStyleOptions = computed(() => [
+ {
+ value: 'tab-default',
+ label: t('setting.tabStyle.default')
+ },
+ {
+ value: 'tab-card',
+ label: t('setting.tabStyle.card')
+ },
+ {
+ value: 'tab-google',
+ label: t('setting.tabStyle.google')
+ }
+ ])
- // 页面切换动画选项
- const pageTransitionOptions = computed(() => [
- {
- value: '',
- label: t('setting.transition.list.none')
- },
- {
- value: 'fade',
- label: t('setting.transition.list.fade')
- },
- {
- value: 'slide-left',
- label: t('setting.transition.list.slideLeft')
- },
- {
- value: 'slide-bottom',
- label: t('setting.transition.list.slideBottom')
- },
- {
- value: 'slide-top',
- label: t('setting.transition.list.slideTop')
- }
- ])
+ // 页面切换动画选项
+ const pageTransitionOptions = computed(() => [
+ {
+ value: '',
+ label: t('setting.transition.list.none')
+ },
+ {
+ value: 'fade',
+ label: t('setting.transition.list.fade')
+ },
+ {
+ value: 'slide-left',
+ label: t('setting.transition.list.slideLeft')
+ },
+ {
+ value: 'slide-bottom',
+ label: t('setting.transition.list.slideBottom')
+ },
+ {
+ value: 'slide-top',
+ label: t('setting.transition.list.slideTop')
+ }
+ ])
- // 圆角大小选项
- const customRadiusOptions = [
- { value: '0', label: '0' },
- { value: '0.25', label: '0.25' },
- { value: '0.5', label: '0.5' },
- { value: '0.75', label: '0.75' },
- { value: '1', label: '1' }
- ]
+ // 圆角大小选项
+ const customRadiusOptions = [
+ { value: '0', label: '0' },
+ { value: '0.25', label: '0.25' },
+ { value: '0.5', label: '0.5' },
+ { value: '0.75', label: '0.75' },
+ { value: '1', label: '1' }
+ ]
- // 容器宽度选项
- const containerWidthOptions = computed(() => [
- {
- value: ContainerWidthEnum.FULL,
- label: t('setting.container.list[0]'),
- icon: 'icon-park-outline:auto-width'
- },
- {
- value: ContainerWidthEnum.BOXED,
- label: t('setting.container.list[1]'),
- icon: 'ix:width'
- }
- ])
+ // 容器宽度选项
+ const containerWidthOptions = computed(() => [
+ {
+ value: ContainerWidthEnum.FULL,
+ label: t('setting.container.list[0]'),
+ icon: 'icon-park-outline:auto-width'
+ },
+ {
+ value: ContainerWidthEnum.BOXED,
+ label: t('setting.container.list[1]'),
+ icon: 'ix:width'
+ }
+ ])
- // 盒子样式选项
- const boxStyleOptions = computed(() => [
- {
- value: 'border-mode',
- label: t('setting.box.list[0]'),
- type: 'border-mode' as const
- },
- {
- value: 'shadow-mode',
- label: t('setting.box.list[1]'),
- type: 'shadow-mode' as const
- }
- ])
+ // 盒子样式选项
+ const boxStyleOptions = computed(() => [
+ {
+ value: 'border-mode',
+ label: t('setting.box.list[0]'),
+ type: 'border-mode' as const
+ },
+ {
+ value: 'shadow-mode',
+ label: t('setting.box.list[1]'),
+ type: 'shadow-mode' as const
+ }
+ ])
- // 从配置文件获取的选项
- const configOptions = {
- // 主题色彩选项
- mainColors: AppConfig.systemMainColor,
+ // 从配置文件获取的选项
+ const configOptions = {
+ // 主题色彩选项
+ mainColors: AppConfig.systemMainColor,
- // 主题风格选项
- themeList: AppConfig.settingThemeList,
+ // 主题风格选项
+ themeList: AppConfig.settingThemeList,
- // 菜单布局选项
- menuLayoutList: AppConfig.menuLayoutList
- }
+ // 菜单布局选项
+ menuLayoutList: AppConfig.menuLayoutList
+ }
- // 基础设置项配置
- const basicSettingsConfig = computed(() => {
- // 定义所有基础设置项
- const allSettings = [
- {
- key: 'showWorkTab',
- label: t('setting.basics.list.multiTab'),
- type: 'switch' as const,
- handler: 'workTab',
- headerBarKey: null // 不依赖headerBar配置
- },
- {
- key: 'uniqueOpened',
- label: t('setting.basics.list.accordion'),
- type: 'switch' as const,
- handler: 'uniqueOpened',
- headerBarKey: null // 不依赖headerBar配置
- },
- {
- key: 'showMenuButton',
- label: t('setting.basics.list.collapseSidebar'),
- type: 'switch' as const,
- handler: 'menuButton',
- headerBarKey: 'menuButton' as const
- },
- {
- key: 'showFastEnter',
- label: t('setting.basics.list.fastEnter'),
- type: 'switch' as const,
- handler: 'fastEnter',
- headerBarKey: 'fastEnter' as const
- },
- {
- key: 'showRefreshButton',
- label: t('setting.basics.list.reloadPage'),
- type: 'switch' as const,
- handler: 'refreshButton',
- headerBarKey: 'refreshButton' as const
- },
- {
- key: 'showCrumbs',
- label: t('setting.basics.list.breadcrumb'),
- type: 'switch' as const,
- handler: 'crumbs',
- mobileHide: true,
- headerBarKey: 'breadcrumb' as const
- },
- {
- key: 'showLanguage',
- label: t('setting.basics.list.language'),
- type: 'switch' as const,
- handler: 'language',
- headerBarKey: 'language' as const
- },
- {
- key: 'showNprogress',
- label: t('setting.basics.list.progressBar'),
- type: 'switch' as const,
- handler: 'nprogress',
- headerBarKey: null // 不依赖headerBar配置
- },
- {
- key: 'colorWeak',
- label: t('setting.basics.list.weakMode'),
- type: 'switch' as const,
- handler: 'colorWeak',
- headerBarKey: null // 不依赖headerBar配置
- },
- {
- key: 'watermarkVisible',
- label: t('setting.basics.list.watermark'),
- type: 'switch' as const,
- handler: 'watermark',
- headerBarKey: null // 不依赖headerBar配置
- },
- {
- key: 'menuOpenWidth',
- label: t('setting.basics.list.menuWidth'),
- type: 'input-number' as const,
- handler: 'menuOpenWidth',
- min: 180,
- max: 320,
- step: 10,
- style: { width: '120px' },
- controlsPosition: 'right' as const,
- headerBarKey: null // 不依赖headerBar配置
- },
- {
- key: 'tabStyle',
- label: t('setting.basics.list.tabStyle'),
- type: 'select' as const,
- handler: 'tabStyle',
- options: tabStyleOptions.value,
- style: { width: '120px' },
- headerBarKey: null // 不依赖headerBar配置
- },
- {
- key: 'pageTransition',
- label: t('setting.basics.list.pageTransition'),
- type: 'select' as const,
- handler: 'pageTransition',
- options: pageTransitionOptions.value,
- style: { width: '120px' },
- headerBarKey: null // 不依赖headerBar配置
- },
- {
- key: 'customRadius',
- label: t('setting.basics.list.borderRadius'),
- type: 'select' as const,
- handler: 'customRadius',
- options: customRadiusOptions,
- style: { width: '120px' },
- headerBarKey: null // 不依赖headerBar配置
- }
- ]
+ // 基础设置项配置
+ const basicSettingsConfig = computed(() => {
+ // 定义所有基础设置项
+ const allSettings = [
+ {
+ key: 'showWorkTab',
+ label: t('setting.basics.list.multiTab'),
+ type: 'switch' as const,
+ handler: 'workTab',
+ headerBarKey: null // 不依赖headerBar配置
+ },
+ {
+ key: 'uniqueOpened',
+ label: t('setting.basics.list.accordion'),
+ type: 'switch' as const,
+ handler: 'uniqueOpened',
+ headerBarKey: null // 不依赖headerBar配置
+ },
+ {
+ key: 'showMenuButton',
+ label: t('setting.basics.list.collapseSidebar'),
+ type: 'switch' as const,
+ handler: 'menuButton',
+ headerBarKey: 'menuButton' as const
+ },
+ {
+ key: 'showFastEnter',
+ label: t('setting.basics.list.fastEnter'),
+ type: 'switch' as const,
+ handler: 'fastEnter',
+ headerBarKey: 'fastEnter' as const
+ },
+ {
+ key: 'showRefreshButton',
+ label: t('setting.basics.list.reloadPage'),
+ type: 'switch' as const,
+ handler: 'refreshButton',
+ headerBarKey: 'refreshButton' as const
+ },
+ {
+ key: 'showCrumbs',
+ label: t('setting.basics.list.breadcrumb'),
+ type: 'switch' as const,
+ handler: 'crumbs',
+ mobileHide: true,
+ headerBarKey: 'breadcrumb' as const
+ },
+ {
+ key: 'showLanguage',
+ label: t('setting.basics.list.language'),
+ type: 'switch' as const,
+ handler: 'language',
+ headerBarKey: 'language' as const
+ },
+ {
+ key: 'showNprogress',
+ label: t('setting.basics.list.progressBar'),
+ type: 'switch' as const,
+ handler: 'nprogress',
+ headerBarKey: null // 不依赖headerBar配置
+ },
+ {
+ key: 'colorWeak',
+ label: t('setting.basics.list.weakMode'),
+ type: 'switch' as const,
+ handler: 'colorWeak',
+ headerBarKey: null // 不依赖headerBar配置
+ },
+ {
+ key: 'watermarkVisible',
+ label: t('setting.basics.list.watermark'),
+ type: 'switch' as const,
+ handler: 'watermark',
+ headerBarKey: null // 不依赖headerBar配置
+ },
+ {
+ key: 'menuOpenWidth',
+ label: t('setting.basics.list.menuWidth'),
+ type: 'input-number' as const,
+ handler: 'menuOpenWidth',
+ min: 180,
+ max: 320,
+ step: 10,
+ style: { width: '120px' },
+ controlsPosition: 'right' as const,
+ headerBarKey: null // 不依赖headerBar配置
+ },
+ {
+ key: 'tabStyle',
+ label: t('setting.basics.list.tabStyle'),
+ type: 'select' as const,
+ handler: 'tabStyle',
+ options: tabStyleOptions.value,
+ style: { width: '120px' },
+ headerBarKey: null // 不依赖headerBar配置
+ },
+ {
+ key: 'pageTransition',
+ label: t('setting.basics.list.pageTransition'),
+ type: 'select' as const,
+ handler: 'pageTransition',
+ options: pageTransitionOptions.value,
+ style: { width: '120px' },
+ headerBarKey: null // 不依赖headerBar配置
+ },
+ {
+ key: 'customRadius',
+ label: t('setting.basics.list.borderRadius'),
+ type: 'select' as const,
+ handler: 'customRadius',
+ options: customRadiusOptions,
+ style: { width: '120px' },
+ headerBarKey: null // 不依赖headerBar配置
+ }
+ ]
- // 根据 headerBarConfig 过滤设置项
- return (
- allSettings
- .filter((setting) => {
- // 如果设置项不依赖headerBar配置,则始终显示
- if (setting.headerBarKey === null) {
- return true
- }
+ // 根据 headerBarConfig 过滤设置项
+ return (
+ allSettings
+ .filter((setting) => {
+ // 如果设置项不依赖headerBar配置,则始终显示
+ if (setting.headerBarKey === null) {
+ return true
+ }
- // 如果依赖headerBar配置,检查对应的功能是否启用
- const headerBarFeature = headerBarConfig[setting.headerBarKey]
- return headerBarFeature?.enabled !== false
- })
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
- .map(({ headerBarKey: _headerBarKey, ...setting }) => setting)
- )
- })
+ // 如果依赖headerBar配置,检查对应的功能是否启用
+ const headerBarFeature = headerBarConfig[setting.headerBarKey]
+ return headerBarFeature?.enabled !== false
+ })
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ .map(({ headerBarKey: _headerBarKey, ...setting }) => setting)
+ )
+ })
- return {
- // 选项配置
- tabStyleOptions,
- pageTransitionOptions,
- customRadiusOptions,
- containerWidthOptions,
- boxStyleOptions,
- configOptions,
+ return {
+ // 选项配置
+ tabStyleOptions,
+ pageTransitionOptions,
+ customRadiusOptions,
+ containerWidthOptions,
+ boxStyleOptions,
+ configOptions,
- // 设置项配置
- basicSettingsConfig
- }
+ // 设置项配置
+ basicSettingsConfig
+ }
}
diff --git a/src/components/core/layouts/art-settings-panel/composables/useSettingsHandlers.ts b/src/components/core/layouts/art-settings-panel/composables/useSettingsHandlers.ts
index 392c690..be07073 100644
--- a/src/components/core/layouts/art-settings-panel/composables/useSettingsHandlers.ts
+++ b/src/components/core/layouts/art-settings-panel/composables/useSettingsHandlers.ts
@@ -6,162 +6,162 @@ import type { ContainerWidthEnum } from '@/enums/appEnum'
* 设置项通用处理逻辑
*/
export function useSettingsHandlers() {
- const settingStore = useSettingStore()
+ const settingStore = useSettingStore()
- // DOM 操作相关
- const domOperations = {
- // 设置HTML类名
- setHtmlClass: (className: string, add: boolean) => {
- const el = document.getElementsByTagName('html')[0]
- if (add) {
- el.classList.add(className)
- } else {
- el.classList.remove(className)
- }
- },
+ // DOM 操作相关
+ const domOperations = {
+ // 设置HTML类名
+ setHtmlClass: (className: string, add: boolean) => {
+ const el = document.getElementsByTagName('html')[0]
+ if (add) {
+ el.classList.add(className)
+ } else {
+ el.classList.remove(className)
+ }
+ },
- // 设置根元素属性
- setRootAttribute: (attribute: string, value: string) => {
- const el = document.documentElement
- el.setAttribute(attribute, value)
- },
+ // 设置根元素属性
+ setRootAttribute: (attribute: string, value: string) => {
+ const el = document.documentElement
+ el.setAttribute(attribute, value)
+ },
- // 设置body类名
- setBodyClass: (className: string, add: boolean) => {
- const el = document.getElementsByTagName('body')[0]
- if (add) {
- el.classList.add(className)
- } else {
- el.classList.remove(className)
- }
- }
- }
+ // 设置body类名
+ setBodyClass: (className: string, add: boolean) => {
+ const el = document.getElementsByTagName('body')[0]
+ if (add) {
+ el.classList.add(className)
+ } else {
+ el.classList.remove(className)
+ }
+ }
+ }
- // 通用切换处理器
- const createToggleHandler = (storeMethod: () => void, callback?: () => void) => {
- return () => {
- storeMethod()
- callback?.()
- }
- }
+ // 通用切换处理器
+ const createToggleHandler = (storeMethod: () => void, callback?: () => void) => {
+ return () => {
+ storeMethod()
+ callback?.()
+ }
+ }
- // 通用值变更处理器
- const createValueHandler = (
- storeMethod: (value: T) => void,
- callback?: (value: T) => void
- ) => {
- return (value: T) => {
- if (value !== undefined && value !== null) {
- storeMethod(value)
- callback?.(value)
- }
- }
- }
+ // 通用值变更处理器
+ const createValueHandler = (
+ storeMethod: (value: T) => void,
+ callback?: (value: T) => void
+ ) => {
+ return (value: T) => {
+ if (value !== undefined && value !== null) {
+ storeMethod(value)
+ callback?.(value)
+ }
+ }
+ }
- // 基础设置处理器
- const basicHandlers = {
- // 工作台标签页
- workTab: createToggleHandler(() => settingStore.setWorkTab(!settingStore.showWorkTab)),
+ // 基础设置处理器
+ const basicHandlers = {
+ // 工作台标签页
+ workTab: createToggleHandler(() => settingStore.setWorkTab(!settingStore.showWorkTab)),
- // 菜单手风琴
- uniqueOpened: createToggleHandler(() => settingStore.setUniqueOpened()),
+ // 菜单手风琴
+ uniqueOpened: createToggleHandler(() => settingStore.setUniqueOpened()),
- // 显示菜单按钮
- menuButton: createToggleHandler(() => settingStore.setButton()),
+ // 显示菜单按钮
+ menuButton: createToggleHandler(() => settingStore.setButton()),
- // 显示快速入口
- fastEnter: createToggleHandler(() => settingStore.setFastEnter()),
+ // 显示快速入口
+ fastEnter: createToggleHandler(() => settingStore.setFastEnter()),
- // 显示刷新按钮
- refreshButton: createToggleHandler(() => settingStore.setShowRefreshButton()),
+ // 显示刷新按钮
+ refreshButton: createToggleHandler(() => settingStore.setShowRefreshButton()),
- // 显示面包屑
- crumbs: createToggleHandler(() => settingStore.setCrumbs()),
+ // 显示面包屑
+ crumbs: createToggleHandler(() => settingStore.setCrumbs()),
- // 显示语言切换
- language: createToggleHandler(() => settingStore.setLanguage()),
+ // 显示语言切换
+ language: createToggleHandler(() => settingStore.setLanguage()),
- // 显示进度条
- nprogress: createToggleHandler(() => settingStore.setNprogress()),
+ // 显示进度条
+ nprogress: createToggleHandler(() => settingStore.setNprogress()),
- // 色弱模式
- colorWeak: createToggleHandler(
- () => settingStore.setColorWeak(),
- () => {
- domOperations.setHtmlClass('color-weak', settingStore.colorWeak)
- }
- ),
+ // 色弱模式
+ colorWeak: createToggleHandler(
+ () => settingStore.setColorWeak(),
+ () => {
+ domOperations.setHtmlClass('color-weak', settingStore.colorWeak)
+ }
+ ),
- // 水印显示
- watermark: createToggleHandler(() =>
- settingStore.setWatermarkVisible(!settingStore.watermarkVisible)
- ),
+ // 水印显示
+ watermark: createToggleHandler(() =>
+ settingStore.setWatermarkVisible(!settingStore.watermarkVisible)
+ ),
- // 菜单展开宽度
- menuOpenWidth: createValueHandler((width: number) =>
- settingStore.setMenuOpenWidth(width)
- ),
+ // 菜单展开宽度
+ menuOpenWidth: createValueHandler((width: number) =>
+ settingStore.setMenuOpenWidth(width)
+ ),
- // 标签页风格
- tabStyle: createValueHandler((style: string) => settingStore.setTabStyle(style)),
+ // 标签页风格
+ tabStyle: createValueHandler((style: string) => settingStore.setTabStyle(style)),
- // 页面切换动画
- pageTransition: createValueHandler((transition: string) =>
- settingStore.setPageTransition(transition)
- ),
+ // 页面切换动画
+ pageTransition: createValueHandler((transition: string) =>
+ settingStore.setPageTransition(transition)
+ ),
- // 圆角大小
- customRadius: createValueHandler((radius: string) =>
- settingStore.setCustomRadius(radius)
- )
- }
+ // 圆角大小
+ customRadius: createValueHandler((radius: string) =>
+ settingStore.setCustomRadius(radius)
+ )
+ }
- // 盒子样式处理器
- const boxStyleHandlers = {
- // 设置盒子模式
- setBoxMode: (type: 'border-mode' | 'shadow-mode') => {
- const { boxBorderMode } = storeToRefs(settingStore)
+ // 盒子样式处理器
+ const boxStyleHandlers = {
+ // 设置盒子模式
+ setBoxMode: (type: 'border-mode' | 'shadow-mode') => {
+ const { boxBorderMode } = storeToRefs(settingStore)
- // 防止重复设置
- if (
- (type === 'shadow-mode' && boxBorderMode.value === false) ||
- (type === 'border-mode' && boxBorderMode.value === true)
- ) {
- return
- }
+ // 防止重复设置
+ if (
+ (type === 'shadow-mode' && boxBorderMode.value === false) ||
+ (type === 'border-mode' && boxBorderMode.value === true)
+ ) {
+ return
+ }
- setTimeout(() => {
- domOperations.setRootAttribute('data-box-mode', type)
- settingStore.setBorderMode()
- }, 50)
- }
- }
+ setTimeout(() => {
+ domOperations.setRootAttribute('data-box-mode', type)
+ settingStore.setBorderMode()
+ }, 50)
+ }
+ }
- // 颜色设置处理器
- const colorHandlers = {
- // 选择主题色
- selectColor: (theme: string) => {
- settingStore.setElementTheme(theme)
- settingStore.reload()
- }
- }
+ // 颜色设置处理器
+ const colorHandlers = {
+ // 选择主题色
+ selectColor: (theme: string) => {
+ settingStore.setElementTheme(theme)
+ settingStore.reload()
+ }
+ }
- // 容器设置处理器
- const containerHandlers = {
- // 设置容器宽度
- setWidth: (type: ContainerWidthEnum) => {
- settingStore.setContainerWidth(type)
- settingStore.reload()
- }
- }
+ // 容器设置处理器
+ const containerHandlers = {
+ // 设置容器宽度
+ setWidth: (type: ContainerWidthEnum) => {
+ settingStore.setContainerWidth(type)
+ settingStore.reload()
+ }
+ }
- return {
- domOperations,
- basicHandlers,
- boxStyleHandlers,
- colorHandlers,
- containerHandlers,
- createToggleHandler,
- createValueHandler
- }
+ return {
+ domOperations,
+ basicHandlers,
+ boxStyleHandlers,
+ colorHandlers,
+ containerHandlers,
+ createToggleHandler,
+ createValueHandler
+ }
}
diff --git a/src/components/core/layouts/art-settings-panel/composables/useSettingsPanel.ts b/src/components/core/layouts/art-settings-panel/composables/useSettingsPanel.ts
index 358ef57..ea48aed 100644
--- a/src/components/core/layouts/art-settings-panel/composables/useSettingsPanel.ts
+++ b/src/components/core/layouts/art-settings-panel/composables/useSettingsPanel.ts
@@ -14,194 +14,194 @@ import { useSettingsHandlers } from './useSettingsHandlers'
* 设置面板核心逻辑管理
*/
export function useSettingsPanel() {
- const settingStore = useSettingStore()
- const { systemThemeType, systemThemeMode, menuType } = storeToRefs(settingStore)
+ const settingStore = useSettingStore()
+ const { systemThemeType, systemThemeMode, menuType } = storeToRefs(settingStore)
- // Composables
- const { openFestival, cleanup } = useCeremony()
- const { setSystemTheme, setSystemAutoTheme } = useTheme()
- const { initColorWeak } = useSettingsState()
- const { domOperations } = useSettingsHandlers()
+ // Composables
+ const { openFestival, cleanup } = useCeremony()
+ const { setSystemTheme, setSystemAutoTheme } = useTheme()
+ const { initColorWeak } = useSettingsState()
+ const { domOperations } = useSettingsHandlers()
- // 响应式状态
- const showDrawer = ref(false)
+ // 响应式状态
+ const showDrawer = ref(false)
- // 使用 VueUse breakpoints 优化性能
- const breakpoints = useBreakpoints({ tablet: 1000 })
- const isMobile = breakpoints.smaller('tablet')
+ // 使用 VueUse breakpoints 优化性能
+ const breakpoints = useBreakpoints({ tablet: 1000 })
+ const isMobile = breakpoints.smaller('tablet')
- // 记录窗口宽度变化前的菜单类型
- const beforeMenuType = ref()
- const hasChangedMenu = ref(false)
+ // 记录窗口宽度变化前的菜单类型
+ const beforeMenuType = ref()
+ const hasChangedMenu = ref(false)
- // 计算属性
- const systemThemeColor = computed(() => settingStore.systemThemeColor as string)
+ // 计算属性
+ const systemThemeColor = computed(() => settingStore.systemThemeColor as string)
- // 主题相关处理
- const useThemeHandlers = () => {
- // 初始化系统颜色
- const initSystemColor = () => {
- if (!AppConfig.systemMainColor.includes(systemThemeColor.value)) {
- settingStore.setElementTheme(AppConfig.systemMainColor[0])
- settingStore.reload()
- }
- }
+ // 主题相关处理
+ const useThemeHandlers = () => {
+ // 初始化系统颜色
+ const initSystemColor = () => {
+ if (!AppConfig.systemMainColor.includes(systemThemeColor.value)) {
+ settingStore.setElementTheme(AppConfig.systemMainColor[0])
+ settingStore.reload()
+ }
+ }
- // 初始化系统主题
- const initSystemTheme = () => {
- if (systemThemeMode.value === SystemThemeEnum.AUTO) {
- setSystemAutoTheme()
- } else {
- setSystemTheme(systemThemeType.value)
- }
- }
+ // 初始化系统主题
+ const initSystemTheme = () => {
+ if (systemThemeMode.value === SystemThemeEnum.AUTO) {
+ setSystemAutoTheme()
+ } else {
+ setSystemTheme(systemThemeType.value)
+ }
+ }
- // 监听系统主题变化
- const listenerSystemTheme = () => {
- const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)')
- mediaQuery.addEventListener('change', initSystemTheme)
- return () => {
- mediaQuery.removeEventListener('change', initSystemTheme)
- }
- }
+ // 监听系统主题变化
+ const listenerSystemTheme = () => {
+ const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)')
+ mediaQuery.addEventListener('change', initSystemTheme)
+ return () => {
+ mediaQuery.removeEventListener('change', initSystemTheme)
+ }
+ }
- return {
- initSystemColor,
- initSystemTheme,
- listenerSystemTheme
- }
- }
+ return {
+ initSystemColor,
+ initSystemTheme,
+ listenerSystemTheme
+ }
+ }
- // 响应式布局处理
- const useResponsiveLayout = () => {
- // 使用 watch 监听断点变化,性能更优
- const stopWatch = watch(
- isMobile,
- (mobile: boolean) => {
- if (mobile) {
- // 切换到移动端布局
- if (!hasChangedMenu.value) {
- beforeMenuType.value = menuType.value
- useSettingsState().switchMenuLayouts(MenuTypeEnum.LEFT)
- settingStore.setMenuOpen(false)
- hasChangedMenu.value = true
- }
- } else {
- // 恢复桌面端布局
- if (hasChangedMenu.value && beforeMenuType.value) {
- useSettingsState().switchMenuLayouts(beforeMenuType.value)
- settingStore.setMenuOpen(true)
- hasChangedMenu.value = false
- }
- }
- },
- { immediate: true }
- )
+ // 响应式布局处理
+ const useResponsiveLayout = () => {
+ // 使用 watch 监听断点变化,性能更优
+ const stopWatch = watch(
+ isMobile,
+ (mobile: boolean) => {
+ if (mobile) {
+ // 切换到移动端布局
+ if (!hasChangedMenu.value) {
+ beforeMenuType.value = menuType.value
+ useSettingsState().switchMenuLayouts(MenuTypeEnum.LEFT)
+ settingStore.setMenuOpen(false)
+ hasChangedMenu.value = true
+ }
+ } else {
+ // 恢复桌面端布局
+ if (hasChangedMenu.value && beforeMenuType.value) {
+ useSettingsState().switchMenuLayouts(beforeMenuType.value)
+ settingStore.setMenuOpen(true)
+ hasChangedMenu.value = false
+ }
+ }
+ },
+ { immediate: true }
+ )
- return { stopWatch }
- }
+ return { stopWatch }
+ }
- // 抽屉控制
- const useDrawerControl = () => {
- // 用于存储 setTimeout 的 ID,以便在需要时清除
- let themeChangeTimer: ReturnType | null = null
+ // 抽屉控制
+ const useDrawerControl = () => {
+ // 用于存储 setTimeout 的 ID,以便在需要时清除
+ let themeChangeTimer: ReturnType | null = null
- // 打开抽屉
- const handleOpen = () => {
- // 清除可能存在的旧定时器
- if (themeChangeTimer) {
- clearTimeout(themeChangeTimer)
- }
- // 延迟添加 theme-change class,避免抽屉打开动画受影响
- themeChangeTimer = setTimeout(() => {
- domOperations.setBodyClass('theme-change', true)
- themeChangeTimer = null
- }, 500)
- }
+ // 打开抽屉
+ const handleOpen = () => {
+ // 清除可能存在的旧定时器
+ if (themeChangeTimer) {
+ clearTimeout(themeChangeTimer)
+ }
+ // 延迟添加 theme-change class,避免抽屉打开动画受影响
+ themeChangeTimer = setTimeout(() => {
+ domOperations.setBodyClass('theme-change', true)
+ themeChangeTimer = null
+ }, 500)
+ }
- // 关闭抽屉
- const handleClose = () => {
- // 清除未执行的定时器,防止关闭后才添加 class
- if (themeChangeTimer) {
- clearTimeout(themeChangeTimer)
- themeChangeTimer = null
- }
- // 立即移除 theme-change class
- domOperations.setBodyClass('theme-change', false)
- }
+ // 关闭抽屉
+ const handleClose = () => {
+ // 清除未执行的定时器,防止关闭后才添加 class
+ if (themeChangeTimer) {
+ clearTimeout(themeChangeTimer)
+ themeChangeTimer = null
+ }
+ // 立即移除 theme-change class
+ domOperations.setBodyClass('theme-change', false)
+ }
- // 打开设置
- const openSetting = () => {
- showDrawer.value = true
- }
+ // 打开设置
+ const openSetting = () => {
+ showDrawer.value = true
+ }
- // 关闭设置
- const closeDrawer = () => {
- showDrawer.value = false
- }
+ // 关闭设置
+ const closeDrawer = () => {
+ showDrawer.value = false
+ }
- return {
- handleOpen,
- handleClose,
- openSetting,
- closeDrawer
- }
- }
+ return {
+ handleOpen,
+ handleClose,
+ openSetting,
+ closeDrawer
+ }
+ }
- // Props 变化监听
- const usePropsWatcher = (props: { open?: boolean }) => {
- watch(
- () => props.open,
- (val: boolean | undefined) => {
- if (val !== undefined) {
- showDrawer.value = val
- }
- }
- )
- }
+ // Props 变化监听
+ const usePropsWatcher = (props: { open?: boolean }) => {
+ watch(
+ () => props.open,
+ (val: boolean | undefined) => {
+ if (val !== undefined) {
+ showDrawer.value = val
+ }
+ }
+ )
+ }
- // 初始化设置
- const useSettingsInitializer = () => {
- const themeHandlers = useThemeHandlers()
- const { openSetting } = useDrawerControl()
- const { stopWatch } = useResponsiveLayout()
- let themeCleanup: (() => void) | null = null
+ // 初始化设置
+ const useSettingsInitializer = () => {
+ const themeHandlers = useThemeHandlers()
+ const { openSetting } = useDrawerControl()
+ const { stopWatch } = useResponsiveLayout()
+ let themeCleanup: (() => void) | null = null
- const initializeSettings = () => {
- mittBus.on('openSetting', openSetting)
- themeHandlers.initSystemColor()
- themeCleanup = themeHandlers.listenerSystemTheme()
- initColorWeak()
+ const initializeSettings = () => {
+ mittBus.on('openSetting', openSetting)
+ themeHandlers.initSystemColor()
+ themeCleanup = themeHandlers.listenerSystemTheme()
+ initColorWeak()
- // 设置盒子模式
- const boxMode = settingStore.boxBorderMode ? 'border-mode' : 'shadow-mode'
- domOperations.setRootAttribute('data-box-mode', boxMode)
+ // 设置盒子模式
+ const boxMode = settingStore.boxBorderMode ? 'border-mode' : 'shadow-mode'
+ domOperations.setRootAttribute('data-box-mode', boxMode)
- themeHandlers.initSystemTheme()
- openFestival()
- }
+ themeHandlers.initSystemTheme()
+ openFestival()
+ }
- const cleanupSettings = () => {
- stopWatch()
- themeCleanup?.()
- cleanup()
- }
+ const cleanupSettings = () => {
+ stopWatch()
+ themeCleanup?.()
+ cleanup()
+ }
- return {
- initializeSettings,
- cleanupSettings
- }
- }
+ return {
+ initializeSettings,
+ cleanupSettings
+ }
+ }
- return {
- // 状态
- showDrawer,
+ return {
+ // 状态
+ showDrawer,
- // 方法组合
- useThemeHandlers,
- useResponsiveLayout,
- useDrawerControl,
- usePropsWatcher,
- useSettingsInitializer
- }
+ // 方法组合
+ useThemeHandlers,
+ useResponsiveLayout,
+ useDrawerControl,
+ usePropsWatcher,
+ useSettingsInitializer
+ }
}
diff --git a/src/components/core/layouts/art-settings-panel/composables/useSettingsState.ts b/src/components/core/layouts/art-settings-panel/composables/useSettingsState.ts
index 65352d2..2fb90cc 100644
--- a/src/components/core/layouts/art-settings-panel/composables/useSettingsState.ts
+++ b/src/components/core/layouts/art-settings-panel/composables/useSettingsState.ts
@@ -5,33 +5,33 @@ import { MenuThemeEnum, MenuTypeEnum } from '@/enums/appEnum'
* 设置状态管理
*/
export function useSettingsState() {
- const settingStore = useSettingStore()
+ const settingStore = useSettingStore()
- // 色弱模式初始化
- const initColorWeak = () => {
- if (settingStore.colorWeak) {
- const el = document.getElementsByTagName('html')[0]
- setTimeout(() => {
- el.classList.add('color-weak')
- }, 100)
- }
- }
+ // 色弱模式初始化
+ const initColorWeak = () => {
+ if (settingStore.colorWeak) {
+ const el = document.getElementsByTagName('html')[0]
+ setTimeout(() => {
+ el.classList.add('color-weak')
+ }, 100)
+ }
+ }
- // 菜单布局切换
- const switchMenuLayouts = (type: MenuTypeEnum) => {
- if (type === MenuTypeEnum.LEFT || type === MenuTypeEnum.TOP_LEFT) {
- settingStore.setMenuOpen(true)
- }
- settingStore.switchMenuLayouts(type)
- if (type === MenuTypeEnum.DUAL_MENU) {
- settingStore.switchMenuStyles(MenuThemeEnum.DESIGN)
- settingStore.setMenuOpen(true)
- }
- }
+ // 菜单布局切换
+ const switchMenuLayouts = (type: MenuTypeEnum) => {
+ if (type === MenuTypeEnum.LEFT || type === MenuTypeEnum.TOP_LEFT) {
+ settingStore.setMenuOpen(true)
+ }
+ settingStore.switchMenuLayouts(type)
+ if (type === MenuTypeEnum.DUAL_MENU) {
+ settingStore.switchMenuStyles(MenuThemeEnum.DESIGN)
+ settingStore.setMenuOpen(true)
+ }
+ }
- return {
- // 方法
- initColorWeak,
- switchMenuLayouts
- }
+ return {
+ // 方法
+ initColorWeak,
+ switchMenuLayouts
+ }
}
diff --git a/src/components/core/layouts/art-settings-panel/index.vue b/src/components/core/layouts/art-settings-panel/index.vue
index 0cbf344..955440b 100644
--- a/src/components/core/layouts/art-settings-panel/index.vue
+++ b/src/components/core/layouts/art-settings-panel/index.vue
@@ -1,72 +1,72 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/core/layouts/art-settings-panel/style.scss b/src/components/core/layouts/art-settings-panel/style.scss
index e863074..42e9b76 100644
--- a/src/components/core/layouts/art-settings-panel/style.scss
+++ b/src/components/core/layouts/art-settings-panel/style.scss
@@ -2,91 +2,91 @@
// 设置抽屉模态框样式
.setting-modal {
- background: transparent !important;
+ background: transparent !important;
- .el-drawer {
- // 背景滤镜效果
- background: rgba($color: #fff, $alpha: 50%) !important;
- box-shadow: 0 0 30px rgb(0 0 0 / 10%) !important;
+ .el-drawer {
+ // 背景滤镜效果
+ background: rgba($color: #fff, $alpha: 50%) !important;
+ box-shadow: 0 0 30px rgb(0 0 0 / 10%) !important;
- @include backdropBlur();
+ @include backdropBlur();
- .setting-box-wrap {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- width: calc(100% + 15px);
- margin-bottom: 10px;
+ .setting-box-wrap {
+ display: flex;
+ flex-wrap: wrap;
+ align-items: center;
+ width: calc(100% + 15px);
+ margin-bottom: 10px;
- .setting-item {
- box-sizing: border-box;
- width: calc(33.333% - 15px);
- margin-right: 15px;
- text-align: center;
+ .setting-item {
+ box-sizing: border-box;
+ width: calc(33.333% - 15px);
+ margin-right: 15px;
+ text-align: center;
- .box {
- position: relative;
- box-sizing: border-box;
- display: flex;
- height: 52px;
- overflow: hidden;
- cursor: pointer;
- border: 2px solid var(--default-border);
- border-radius: 8px;
- box-shadow: 0 0 8px 0 rgb(0 0 0 / 10%);
- transition: box-shadow 0.1s;
+ .box {
+ position: relative;
+ box-sizing: border-box;
+ display: flex;
+ height: 52px;
+ overflow: hidden;
+ cursor: pointer;
+ border: 2px solid var(--default-border);
+ border-radius: 8px;
+ box-shadow: 0 0 8px 0 rgb(0 0 0 / 10%);
+ transition: box-shadow 0.1s;
- &.mt-16 {
- margin-top: 16px;
- }
+ &.mt-16 {
+ margin-top: 16px;
+ }
- &.is-active {
- border: 2px solid var(--theme-color);
- }
+ &.is-active {
+ border: 2px solid var(--theme-color);
+ }
- img {
- width: 100%;
- height: 100%;
- }
- }
+ img {
+ width: 100%;
+ height: 100%;
+ }
+ }
- .name {
- margin-top: 6px;
- font-size: 14px;
- text-align: center;
- }
- }
- }
- }
+ .name {
+ margin-top: 6px;
+ font-size: 14px;
+ text-align: center;
+ }
+ }
+ }
+ }
- // 去除滚动条
- .el-drawer__body::-webkit-scrollbar {
- width: 0 !important;
- }
+ // 去除滚动条
+ .el-drawer__body::-webkit-scrollbar {
+ width: 0 !important;
+ }
}
.dark {
- .setting-modal {
- .el-drawer {
- background: rgba($color: #000, $alpha: 50%) !important;
+ .setting-modal {
+ .el-drawer {
+ background: rgba($color: #000, $alpha: 50%) !important;
- .setting-item {
- .box {
- border: 2px solid transparent;
- }
- }
- }
- }
+ .setting-item {
+ .box {
+ border: 2px solid transparent;
+ }
+ }
+ }
+ }
}
// 去除火狐浏览器滚动条
:deep(.el-drawer__body) {
- scrollbar-width: none;
+ scrollbar-width: none;
}
// 移动端隐藏
@media screen and (width <= 800px) {
- .mobile-hide {
- display: none !important;
- }
+ .mobile-hide {
+ display: none !important;
+ }
}
diff --git a/src/components/core/layouts/art-settings-panel/widget/BasicSettings.vue b/src/components/core/layouts/art-settings-panel/widget/BasicSettings.vue
index b6dc9d3..495930e 100644
--- a/src/components/core/layouts/art-settings-panel/widget/BasicSettings.vue
+++ b/src/components/core/layouts/art-settings-panel/widget/BasicSettings.vue
@@ -1,77 +1,77 @@
-
-
-
-
+
+
+
+
diff --git a/src/components/core/layouts/art-settings-panel/widget/BoxStyleSettings.vue b/src/components/core/layouts/art-settings-panel/widget/BoxStyleSettings.vue
index 86c7a9e..3d01736 100644
--- a/src/components/core/layouts/art-settings-panel/widget/BoxStyleSettings.vue
+++ b/src/components/core/layouts/art-settings-panel/widget/BoxStyleSettings.vue
@@ -1,38 +1,38 @@
-
-
-
-
- {{ option.label }}
-
-
-
+
+
+
+
+ {{ option.label }}
+
+
+
diff --git a/src/components/core/layouts/art-settings-panel/widget/ColorSettings.vue b/src/components/core/layouts/art-settings-panel/widget/ColorSettings.vue
index 05a4b41..dccb7e9 100644
--- a/src/components/core/layouts/art-settings-panel/widget/ColorSettings.vue
+++ b/src/components/core/layouts/art-settings-panel/widget/ColorSettings.vue
@@ -1,35 +1,35 @@
-
+
diff --git a/src/components/core/layouts/art-settings-panel/widget/ContainerSettings.vue b/src/components/core/layouts/art-settings-panel/widget/ContainerSettings.vue
index 1f5be72..bae9bcc 100644
--- a/src/components/core/layouts/art-settings-panel/widget/ContainerSettings.vue
+++ b/src/components/core/layouts/art-settings-panel/widget/ContainerSettings.vue
@@ -1,33 +1,33 @@
-
+
diff --git a/src/components/core/layouts/art-settings-panel/widget/MenuLayoutSettings.vue b/src/components/core/layouts/art-settings-panel/widget/MenuLayoutSettings.vue
index dbcae46..169ca8d 100644
--- a/src/components/core/layouts/art-settings-panel/widget/MenuLayoutSettings.vue
+++ b/src/components/core/layouts/art-settings-panel/widget/MenuLayoutSettings.vue
@@ -1,31 +1,34 @@
-
-
-
-
-
-
![]()
-
-
{{ $t(`setting.menuType.list[${index}]`) }}
-
-
-
+
+
+
+
+
+
![]()
+
+
{{ $t(`setting.menuType.list[${index}]`) }}
+
+
+
diff --git a/src/components/core/layouts/art-settings-panel/widget/MenuStyleSettings.vue b/src/components/core/layouts/art-settings-panel/widget/MenuStyleSettings.vue
index 61237eb..33b18ce 100644
--- a/src/components/core/layouts/art-settings-panel/widget/MenuStyleSettings.vue
+++ b/src/components/core/layouts/art-settings-panel/widget/MenuStyleSettings.vue
@@ -1,44 +1,44 @@
-
-
-
-
-
![]()
-
-
-
+
+
+
+
+
![]()
+
+
+
diff --git a/src/components/core/layouts/art-settings-panel/widget/SectionTitle.vue b/src/components/core/layouts/art-settings-panel/widget/SectionTitle.vue
index 31ef00c..8ece720 100644
--- a/src/components/core/layouts/art-settings-panel/widget/SectionTitle.vue
+++ b/src/components/core/layouts/art-settings-panel/widget/SectionTitle.vue
@@ -1,17 +1,17 @@
-
- {{ title }}
-
+
+ {{ title }}
+
diff --git a/src/components/core/layouts/art-settings-panel/widget/SettingActions.vue b/src/components/core/layouts/art-settings-panel/widget/SettingActions.vue
index 7b47d1a..302d650 100644
--- a/src/components/core/layouts/art-settings-panel/widget/SettingActions.vue
+++ b/src/components/core/layouts/art-settings-panel/widget/SettingActions.vue
@@ -1,235 +1,241 @@
-
-
- {{ $t('setting.actions.copyConfig') }}
-
-
- {{ $t('setting.actions.resetConfig') }}
-
-
+
+
+ {{ $t('setting.actions.copyConfig') }}
+
+
+ {{ $t('setting.actions.resetConfig') }}
+
+
diff --git a/src/components/core/layouts/art-settings-panel/widget/SettingDrawer.vue b/src/components/core/layouts/art-settings-panel/widget/SettingDrawer.vue
index 85372be..3281389 100644
--- a/src/components/core/layouts/art-settings-panel/widget/SettingDrawer.vue
+++ b/src/components/core/layouts/art-settings-panel/widget/SettingDrawer.vue
@@ -1,51 +1,51 @@
-
+
diff --git a/src/components/core/layouts/art-settings-panel/widget/SettingHeader.vue b/src/components/core/layouts/art-settings-panel/widget/SettingHeader.vue
index e3ead9e..49299b9 100644
--- a/src/components/core/layouts/art-settings-panel/widget/SettingHeader.vue
+++ b/src/components/core/layouts/art-settings-panel/widget/SettingHeader.vue
@@ -1,18 +1,18 @@
-
+
diff --git a/src/components/core/layouts/art-settings-panel/widget/SettingItem.vue b/src/components/core/layouts/art-settings-panel/widget/SettingItem.vue
index 5721027..5e87c27 100644
--- a/src/components/core/layouts/art-settings-panel/widget/SettingItem.vue
+++ b/src/components/core/layouts/art-settings-panel/widget/SettingItem.vue
@@ -1,101 +1,105 @@
-
-
{{ config.label }}
+
+ {{ config.label }}
-
-
+
+
-
-
+
+
-
-
-
-
-
+
+
+
+
+
diff --git a/src/components/core/layouts/art-settings-panel/widget/ThemeSettings.vue b/src/components/core/layouts/art-settings-panel/widget/ThemeSettings.vue
index 4b46fcd..94fa30c 100644
--- a/src/components/core/layouts/art-settings-panel/widget/ThemeSettings.vue
+++ b/src/components/core/layouts/art-settings-panel/widget/ThemeSettings.vue
@@ -1,28 +1,28 @@
-
-
-
-
-
![]()
-
-
{{ $t(`setting.theme.list[${index}]`) }}
-
-
+
+
+
+
+
![]()
+
+
{{ $t(`setting.theme.list[${index}]`) }}
+
+
diff --git a/src/components/core/layouts/art-work-tab/index.vue b/src/components/core/layouts/art-work-tab/index.vue
index 152ff63..cd47dfd 100644
--- a/src/components/core/layouts/art-work-tab/index.vue
+++ b/src/components/core/layouts/art-work-tab/index.vue
@@ -1,584 +1,595 @@
-
-
-
- - showMenu(e, item.path)"
- >
-
- {{ item.customTitle || formatMenuTitle(item.title) }}
-
-
-
-
-
-
-
+
+
+
+ - showMenu(e, item.path)"
+ >
+
+ {{ item.customTitle || formatMenuTitle(item.title) }}
+
+
+
+
+
+
+
-
-
showMenu(e, activeTab)"
- >
-
-
-
+
+
showMenu(e, activeTab)"
+ >
+
+
+
-
-
+
+
diff --git a/src/components/core/media/art-cutter-img/index.vue b/src/components/core/media/art-cutter-img/index.vue
index 191ceed..61738f6 100644
--- a/src/components/core/media/art-cutter-img/index.vue
+++ b/src/components/core/media/art-cutter-img/index.vue
@@ -1,350 +1,350 @@
-
-
-
{{ title }}
-
-
- 选择图片
-
-
- 清除
-
-
-
-
-
-
-
+
+
+
{{ title }}
+
+
+ 选择图片
+
+
+ 清除
+
+
+
+
+
+
+
-
-
{{ previewTitle }}
-
-
![预览图]()
-
-
下载图片
-
-
+
+
{{ previewTitle }}
+
+
![预览图]()
+
+
下载图片
+
+
diff --git a/src/components/core/media/art-video-player/index.vue b/src/components/core/media/art-video-player/index.vue
index 4f681ea..d5b2b59 100644
--- a/src/components/core/media/art-video-player/index.vue
+++ b/src/components/core/media/art-video-player/index.vue
@@ -1,111 +1,111 @@
-
+
diff --git a/src/components/core/others/art-menu-right/index.vue b/src/components/core/others/art-menu-right/index.vue
index 1cc92ab..ff674b9 100644
--- a/src/components/core/others/art-menu-right/index.vue
+++ b/src/components/core/others/art-menu-right/index.vue
@@ -1,415 +1,418 @@
-
diff --git a/src/components/core/others/art-watermark/index.vue b/src/components/core/others/art-watermark/index.vue
index 1d7f06b..1f7274e 100644
--- a/src/components/core/others/art-watermark/index.vue
+++ b/src/components/core/others/art-watermark/index.vue
@@ -1,64 +1,64 @@
-
+
diff --git a/src/components/core/tables/art-table-header/index.vue b/src/components/core/tables/art-table-header/index.vue
index 788c2b7..e9b1f46 100644
--- a/src/components/core/tables/art-table-header/index.vue
+++ b/src/components/core/tables/art-table-header/index.vue
@@ -1,328 +1,339 @@
-
diff --git a/src/components/core/tables/art-table/index.vue b/src/components/core/tables/art-table/index.vue
index 2392d96..187d659 100644
--- a/src/components/core/tables/art-table/index.vue
+++ b/src/components/core/tables/art-table/index.vue
@@ -3,340 +3,341 @@
-
-
-
-
-
-
- {{ getGlobalIndex($index) }}
-
-
+
+
+
+
+
+
+ {{ getGlobalIndex($index) }}
+
+
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
- {{ col.label }}
-
-
-
-
-
-
-
+
+
+
+
+ {{ col.label }}
+
+
+
+
+
+
+
-
+
-
-
-
-
-
+
+
+
+
+
-
-
+
+
diff --git a/src/components/core/tables/art-table/style.scss b/src/components/core/tables/art-table/style.scss
index 67459e8..17412a2 100644
--- a/src/components/core/tables/art-table/style.scss
+++ b/src/components/core/tables/art-table/style.scss
@@ -1,99 +1,99 @@
.art-table {
- position: relative;
- height: 100%;
+ position: relative;
+ height: 100%;
- .el-table {
- height: 100%;
- margin-top: 10px;
- }
+ .el-table {
+ height: 100%;
+ margin-top: 10px;
+ }
- :deep(.el-loading-mask) {
- z-index: 100;
- background-color: var(--default-box-color) !important;
- }
+ :deep(.el-loading-mask) {
+ z-index: 100;
+ background-color: var(--default-box-color) !important;
+ }
- // Loading 过渡动画 - 消失时淡出
- .loading-fade-leave-active {
- transition: opacity 0.3s ease-out;
- }
+ // Loading 过渡动画 - 消失时淡出
+ .loading-fade-leave-active {
+ transition: opacity 0.3s ease-out;
+ }
- .loading-fade-leave-to {
- opacity: 0;
- }
+ .loading-fade-leave-to {
+ opacity: 0;
+ }
- // 空状态垂直居中
- &.is-empty {
- :deep(.el-scrollbar__wrap) {
- display: flex;
- }
- }
+ // 空状态垂直居中
+ &.is-empty {
+ :deep(.el-scrollbar__wrap) {
+ display: flex;
+ }
+ }
- .pagination {
- display: flex;
- margin-top: 13px;
+ .pagination {
+ display: flex;
+ margin-top: 13px;
- :deep(.el-select) {
- width: 102px !important;
- }
+ :deep(.el-select) {
+ width: 102px !important;
+ }
- // 分页对齐方式
- &.left {
- justify-content: flex-start;
- }
+ // 分页对齐方式
+ &.left {
+ justify-content: flex-start;
+ }
- &.center {
- justify-content: center;
- }
+ &.center {
+ justify-content: center;
+ }
- &.right {
- justify-content: flex-end;
- }
+ &.right {
+ justify-content: flex-end;
+ }
- // 自定义分页组件样式
- &.custom-pagination {
- :deep(.el-pagination) {
- .btn-prev,
- .btn-next {
- background-color: transparent;
- border: 1px solid var(--art-gray-300);
- transition: border-color 0.15s;
+ // 自定义分页组件样式
+ &.custom-pagination {
+ :deep(.el-pagination) {
+ .btn-prev,
+ .btn-next {
+ background-color: transparent;
+ border: 1px solid var(--art-gray-300);
+ transition: border-color 0.15s;
- &:hover:not(.is-disabled) {
- color: var(--theme-color);
- border-color: var(--theme-color);
- }
- }
+ &:hover:not(.is-disabled) {
+ color: var(--theme-color);
+ border-color: var(--theme-color);
+ }
+ }
- li {
- box-sizing: border-box;
- font-weight: 400 !important;
- background-color: transparent;
- border: 1px solid var(--art-gray-300);
- transition: border-color 0.15s;
+ li {
+ box-sizing: border-box;
+ font-weight: 400 !important;
+ background-color: transparent;
+ border: 1px solid var(--art-gray-300);
+ transition: border-color 0.15s;
- &.is-active {
- font-weight: 400;
- color: #fff;
- background-color: var(--theme-color);
- border: 1px solid var(--theme-color);
- }
+ &.is-active {
+ font-weight: 400;
+ color: #fff;
+ background-color: var(--theme-color);
+ border: 1px solid var(--theme-color);
+ }
- &:hover:not(.is-disabled) {
- border-color: var(--theme-color);
- }
- }
- }
- }
- }
+ &:hover:not(.is-disabled) {
+ border-color: var(--theme-color);
+ }
+ }
+ }
+ }
+ }
}
// 移动端分页
@media (width <= 640px) {
- :deep(.el-pagination) {
- display: flex;
- flex-wrap: wrap;
- gap: 15px 0;
- align-items: center;
- justify-content: center;
- }
+ :deep(.el-pagination) {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 15px 0;
+ align-items: center;
+ justify-content: center;
+ }
}
diff --git a/src/components/core/text-effect/art-count-to/index.vue b/src/components/core/text-effect/art-count-to/index.vue
index 7fb104b..435b21b 100644
--- a/src/components/core/text-effect/art-count-to/index.vue
+++ b/src/components/core/text-effect/art-count-to/index.vue
@@ -1,310 +1,319 @@
-
- {{ formattedValue }}
-
+
+ {{ formattedValue }}
+
diff --git a/src/components/core/text-effect/art-festival-text-scroll/index.vue b/src/components/core/text-effect/art-festival-text-scroll/index.vue
index 770b457..4c56993 100644
--- a/src/components/core/text-effect/art-festival-text-scroll/index.vue
+++ b/src/components/core/text-effect/art-festival-text-scroll/index.vue
@@ -1,32 +1,32 @@
-
+
diff --git a/src/components/core/text-effect/art-text-scroll/index.vue b/src/components/core/text-effect/art-text-scroll/index.vue
index 90be30f..b2e2af4 100644
--- a/src/components/core/text-effect/art-text-scroll/index.vue
+++ b/src/components/core/text-effect/art-text-scroll/index.vue
@@ -1,285 +1,285 @@
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
diff --git a/src/components/core/theme/theme-svg/index.vue b/src/components/core/theme/theme-svg/index.vue
index 0b565a9..f6c59d5 100644
--- a/src/components/core/theme/theme-svg/index.vue
+++ b/src/components/core/theme/theme-svg/index.vue
@@ -1,100 +1,100 @@
-
+
diff --git a/src/components/core/views/exception/ArtException.vue b/src/components/core/views/exception/ArtException.vue
index 699228f..62cc838 100644
--- a/src/components/core/views/exception/ArtException.vue
+++ b/src/components/core/views/exception/ArtException.vue
@@ -1,43 +1,43 @@
-
-
-
-
-
{{ data.desc }}
-
{{
- data.btnText
- }}
-
-
-
+
+
+
+
+
{{ data.desc }}
+
{{
+ data.btnText
+ }}
+
+
+
diff --git a/src/components/core/views/login/AuthTopBar.vue b/src/components/core/views/login/AuthTopBar.vue
index 9455253..0d5fb06 100644
--- a/src/components/core/views/login/AuthTopBar.vue
+++ b/src/components/core/views/login/AuthTopBar.vue
@@ -1,149 +1,161 @@
-
-
-
-
{{ AppConfig.systemInfo.name }}
-
+
+
+
+
{{ AppConfig.systemInfo.name }}
+
-
-
+
+
diff --git a/src/components/core/views/login/LoginLeftView.vue b/src/components/core/views/login/LoginLeftView.vue
index af6a904..a2acad3 100644
--- a/src/components/core/views/login/LoginLeftView.vue
+++ b/src/components/core/views/login/LoginLeftView.vue
@@ -1,602 +1,615 @@
-
-
-
-
{{ AppConfig.systemInfo.name }}
-
+
+
+
+
{{ AppConfig.systemInfo.name }}
+
-
-
-
+
+
+
-
-
{{ $t('login.leftView.title') }}
-
{{ $t('login.leftView.subTitle') }}
-
+
+
{{ $t('login.leftView.title') }}
+
{{ $t('login.leftView.subTitle') }}
+
-
-
-
-
-
-
+
+
+
+
+
+
-
+
-
-
+
+
-
-
+
+
-
-
-
-
+
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
diff --git a/src/components/core/views/result/ArtResultPage.vue b/src/components/core/views/result/ArtResultPage.vue
index b2eca48..092b7fb 100644
--- a/src/components/core/views/result/ArtResultPage.vue
+++ b/src/components/core/views/result/ArtResultPage.vue
@@ -1,43 +1,43 @@
-
-
-
{{
- title
- }}
-
{{ message }}
-
-
-
-
-
-
-
+
+
+
{{
+ title
+ }}
+
{{ message }}
+
+
+
+
+
+
+
diff --git a/src/components/core/widget/art-icon-button/index.vue b/src/components/core/widget/art-icon-button/index.vue
index 760888b..11c7591 100644
--- a/src/components/core/widget/art-icon-button/index.vue
+++ b/src/components/core/widget/art-icon-button/index.vue
@@ -1,23 +1,23 @@
-
+
diff --git a/src/config/assets/images.ts b/src/config/assets/images.ts
index f3e89dd..f451e4e 100644
--- a/src/config/assets/images.ts
+++ b/src/config/assets/images.ts
@@ -29,33 +29,33 @@ import lightStyle from '@imgs/settings/menu_styles/light.png'
* 配置中心图片资源对象
*/
export const configImages = {
- /** 系统主题预览图 */
- themeStyles: {
- /** 亮色主题 */
- light: lightTheme,
- /** 暗色主题 */
- dark: darkTheme,
- /** 自动主题(跟随系统) */
- system: systemTheme
- },
- /** 菜单布局预览图 */
- menuLayouts: {
- /** 左侧菜单 */
- vertical: verticalLayout,
- /** 顶部菜单 */
- horizontal: horizontalLayout,
- /** 混合菜单 */
- mixed: mixedLayout,
- /** 双栏菜单 */
- dualColumn: dualColumnLayout
- },
- /** 菜单风格预览图 */
- menuStyles: {
- /** 设计风格 */
- design: designStyle,
- /** 暗色风格 */
- dark: darkStyle,
- /** 亮色风格 */
- light: lightStyle
- }
+ /** 系统主题预览图 */
+ themeStyles: {
+ /** 亮色主题 */
+ light: lightTheme,
+ /** 暗色主题 */
+ dark: darkTheme,
+ /** 自动主题(跟随系统) */
+ system: systemTheme
+ },
+ /** 菜单布局预览图 */
+ menuLayouts: {
+ /** 左侧菜单 */
+ vertical: verticalLayout,
+ /** 顶部菜单 */
+ horizontal: horizontalLayout,
+ /** 混合菜单 */
+ mixed: mixedLayout,
+ /** 双栏菜单 */
+ dualColumn: dualColumnLayout
+ },
+ /** 菜单风格预览图 */
+ menuStyles: {
+ /** 设计风格 */
+ design: designStyle,
+ /** 暗色风格 */
+ dark: darkStyle,
+ /** 亮色风格 */
+ light: lightStyle
+ }
}
diff --git a/src/config/fastEnter.ts b/src/config/fastEnter.ts
index ccade16..78cccf2 100644
--- a/src/config/fastEnter.ts
+++ b/src/config/fastEnter.ts
@@ -6,74 +6,74 @@ import { WEB_LINKS } from '@/utils/constants'
import type { FastEnterConfig } from '@/types/config'
const fastEnterConfig: FastEnterConfig = {
- // 显示条件(屏幕宽度)
- minWidth: 1200,
- // 应用列表
- applications: [
- {
- name: '工作台',
- description: '系统概览与数据统计',
- icon: 'ri:pie-chart-line',
- iconColor: '#377dff',
- enabled: true,
- order: 1,
- routeName: 'Console'
- },
- {
- name: '官方文档',
- description: '使用指南与开发文档',
- icon: 'ri:bill-line',
- iconColor: '#ffb100',
- enabled: true,
- order: 2,
- link: WEB_LINKS.DOCS
- },
- {
- name: '技术支持',
- description: '技术支持与问题反馈',
- icon: 'ri:user-location-line',
- iconColor: '#ff6b6b',
- enabled: true,
- order: 3,
- link: WEB_LINKS.COMMUNITY
- },
- {
- name: '哔哩哔哩',
- description: '技术分享与交流',
- icon: 'ri:bilibili-line',
- iconColor: '#FB7299',
- enabled: true,
- order: 4,
- link: WEB_LINKS.BILIBILI
- }
- ],
- // 快速链接
- quickLinks: [
- {
- name: '登录',
- enabled: true,
- order: 1,
- routeName: 'Login'
- },
- {
- name: '注册',
- enabled: true,
- order: 2,
- routeName: 'Register'
- },
- {
- name: '忘记密码',
- enabled: true,
- order: 3,
- routeName: 'ForgetPassword'
- },
- {
- name: '个人中心',
- enabled: true,
- order: 4,
- routeName: 'UserCenter'
- }
- ]
+ // 显示条件(屏幕宽度)
+ minWidth: 1200,
+ // 应用列表
+ applications: [
+ {
+ name: '工作台',
+ description: '系统概览与数据统计',
+ icon: 'ri:pie-chart-line',
+ iconColor: '#377dff',
+ enabled: true,
+ order: 1,
+ routeName: 'Console'
+ },
+ {
+ name: '官方文档',
+ description: '使用指南与开发文档',
+ icon: 'ri:bill-line',
+ iconColor: '#ffb100',
+ enabled: true,
+ order: 2,
+ link: WEB_LINKS.DOCS
+ },
+ {
+ name: '技术支持',
+ description: '技术支持与问题反馈',
+ icon: 'ri:user-location-line',
+ iconColor: '#ff6b6b',
+ enabled: true,
+ order: 3,
+ link: WEB_LINKS.COMMUNITY
+ },
+ {
+ name: '哔哩哔哩',
+ description: '技术分享与交流',
+ icon: 'ri:bilibili-line',
+ iconColor: '#FB7299',
+ enabled: true,
+ order: 4,
+ link: WEB_LINKS.BILIBILI
+ }
+ ],
+ // 快速链接
+ quickLinks: [
+ {
+ name: '登录',
+ enabled: true,
+ order: 1,
+ routeName: 'Login'
+ },
+ {
+ name: '注册',
+ enabled: true,
+ order: 2,
+ routeName: 'Register'
+ },
+ {
+ name: '忘记密码',
+ enabled: true,
+ order: 3,
+ routeName: 'ForgetPassword'
+ },
+ {
+ name: '个人中心',
+ enabled: true,
+ order: 4,
+ routeName: 'UserCenter'
+ }
+ ]
}
export default Object.freeze(fastEnterConfig)
diff --git a/src/config/index.ts b/src/config/index.ts
index daa623a..2e0bcbe 100644
--- a/src/config/index.ts
+++ b/src/config/index.ts
@@ -36,100 +36,104 @@ import fastEnterConfig from './modules/fastEnter'
import { headerBarConfig } from './modules/headerBar'
const appConfig: SystemConfig = {
- // 系统信息
- systemInfo: {
- name: 'Art Design Pro' // 系统名称
- },
- // 系统主题
- systemThemeStyles: {
- [SystemThemeEnum.LIGHT]: { className: '' },
- [SystemThemeEnum.DARK]: { className: SystemThemeEnum.DARK }
- },
- // 系统主题列表
- settingThemeList: [
- {
- name: 'Light',
- theme: SystemThemeEnum.LIGHT,
- color: ['#fff', '#fff'],
- leftLineColor: '#EDEEF0',
- rightLineColor: '#EDEEF0',
- img: configImages.themeStyles.light
- },
- {
- name: 'Dark',
- theme: SystemThemeEnum.DARK,
- color: ['#22252A'],
- leftLineColor: '#3F4257',
- rightLineColor: '#3F4257',
- img: configImages.themeStyles.dark
- },
- {
- name: 'System',
- theme: SystemThemeEnum.AUTO,
- color: ['#fff', '#22252A'],
- leftLineColor: '#EDEEF0',
- rightLineColor: '#3F4257',
- img: configImages.themeStyles.system
- }
- ],
- // 菜单布局列表
- menuLayoutList: [
- { name: 'Left', value: MenuTypeEnum.LEFT, img: configImages.menuLayouts.vertical },
- { name: 'Top', value: MenuTypeEnum.TOP, img: configImages.menuLayouts.horizontal },
- { name: 'Mixed', value: MenuTypeEnum.TOP_LEFT, img: configImages.menuLayouts.mixed },
- { name: 'Dual Column', value: MenuTypeEnum.DUAL_MENU, img: configImages.menuLayouts.dualColumn }
- ],
- // 菜单主题列表
- themeList: [
- {
- theme: MenuThemeEnum.DESIGN,
- background: '#FFFFFF',
- systemNameColor: 'var(--art-gray-800)',
- iconColor: '#6B6B6B',
- textColor: '#29343D',
- img: configImages.menuStyles.design
- },
- {
- theme: MenuThemeEnum.DARK,
- background: '#191A23',
- systemNameColor: '#D9DADB',
- iconColor: '#BABBBD',
- textColor: '#BABBBD',
- img: configImages.menuStyles.dark
- },
- {
- theme: MenuThemeEnum.LIGHT,
- background: '#ffffff',
- systemNameColor: 'var(--art-gray-800)',
- iconColor: '#6B6B6B',
- textColor: '#29343D',
- img: configImages.menuStyles.light
- }
- ],
- // 暗黑模式菜单样式
- darkMenuStyles: [
- {
- theme: MenuThemeEnum.DARK,
- background: 'var(--default-box-color)',
- systemNameColor: '#DDDDDD',
- iconColor: '#BABBBD',
- textColor: 'rgba(#FFFFFF, 0.7)'
- }
- ],
- // 系统主色
- systemMainColor: [
- '#5D87FF',
- '#B48DF3',
- '#1D84FF',
- '#60C041',
- '#38C0FC',
- '#F9901F',
- '#FF80C8'
- ] as const,
- // 快速入口配置
- fastEnter: fastEnterConfig,
- // 顶部栏功能配置
- headerBar: headerBarConfig
+ // 系统信息
+ systemInfo: {
+ name: 'Art Design Pro' // 系统名称
+ },
+ // 系统主题
+ systemThemeStyles: {
+ [SystemThemeEnum.LIGHT]: { className: '' },
+ [SystemThemeEnum.DARK]: { className: SystemThemeEnum.DARK }
+ },
+ // 系统主题列表
+ settingThemeList: [
+ {
+ name: 'Light',
+ theme: SystemThemeEnum.LIGHT,
+ color: ['#fff', '#fff'],
+ leftLineColor: '#EDEEF0',
+ rightLineColor: '#EDEEF0',
+ img: configImages.themeStyles.light
+ },
+ {
+ name: 'Dark',
+ theme: SystemThemeEnum.DARK,
+ color: ['#22252A'],
+ leftLineColor: '#3F4257',
+ rightLineColor: '#3F4257',
+ img: configImages.themeStyles.dark
+ },
+ {
+ name: 'System',
+ theme: SystemThemeEnum.AUTO,
+ color: ['#fff', '#22252A'],
+ leftLineColor: '#EDEEF0',
+ rightLineColor: '#3F4257',
+ img: configImages.themeStyles.system
+ }
+ ],
+ // 菜单布局列表
+ menuLayoutList: [
+ { name: 'Left', value: MenuTypeEnum.LEFT, img: configImages.menuLayouts.vertical },
+ { name: 'Top', value: MenuTypeEnum.TOP, img: configImages.menuLayouts.horizontal },
+ { name: 'Mixed', value: MenuTypeEnum.TOP_LEFT, img: configImages.menuLayouts.mixed },
+ {
+ name: 'Dual Column',
+ value: MenuTypeEnum.DUAL_MENU,
+ img: configImages.menuLayouts.dualColumn
+ }
+ ],
+ // 菜单主题列表
+ themeList: [
+ {
+ theme: MenuThemeEnum.DESIGN,
+ background: '#FFFFFF',
+ systemNameColor: 'var(--art-gray-800)',
+ iconColor: '#6B6B6B',
+ textColor: '#29343D',
+ img: configImages.menuStyles.design
+ },
+ {
+ theme: MenuThemeEnum.DARK,
+ background: '#191A23',
+ systemNameColor: '#D9DADB',
+ iconColor: '#BABBBD',
+ textColor: '#BABBBD',
+ img: configImages.menuStyles.dark
+ },
+ {
+ theme: MenuThemeEnum.LIGHT,
+ background: '#ffffff',
+ systemNameColor: 'var(--art-gray-800)',
+ iconColor: '#6B6B6B',
+ textColor: '#29343D',
+ img: configImages.menuStyles.light
+ }
+ ],
+ // 暗黑模式菜单样式
+ darkMenuStyles: [
+ {
+ theme: MenuThemeEnum.DARK,
+ background: 'var(--default-box-color)',
+ systemNameColor: '#DDDDDD',
+ iconColor: '#BABBBD',
+ textColor: 'rgba(#FFFFFF, 0.7)'
+ }
+ ],
+ // 系统主色
+ systemMainColor: [
+ '#5D87FF',
+ '#B48DF3',
+ '#1D84FF',
+ '#60C041',
+ '#38C0FC',
+ '#F9901F',
+ '#FF80C8'
+ ] as const,
+ // 快速入口配置
+ fastEnter: fastEnterConfig,
+ // 顶部栏功能配置
+ headerBar: headerBarConfig
}
export default Object.freeze(appConfig)
diff --git a/src/config/modules/component.ts b/src/config/modules/component.ts
index bc709e0..b5cfd0a 100644
--- a/src/config/modules/component.ts
+++ b/src/config/modules/component.ts
@@ -21,70 +21,70 @@ import { defineAsyncComponent } from 'vue'
* 全局组件配置列表
*/
export const globalComponentsConfig: GlobalComponentConfig[] = [
- {
- name: '设置面板',
- key: 'settings-panel',
- component: defineAsyncComponent(
- () => import('@/components/core/layouts/art-settings-panel/index.vue')
- ),
- enabled: true
- },
- {
- name: '全局搜索',
- key: 'global-search',
- component: defineAsyncComponent(
- () => import('@/components/core/layouts/art-global-search/index.vue')
- ),
- enabled: true
- },
- {
- name: '锁屏',
- key: 'screen-lock',
- component: defineAsyncComponent(
- () => import('@/components/core/layouts/art-screen-lock/index.vue')
- ),
- enabled: true
- },
- {
- name: '聊天窗口',
- key: 'chat-window',
- component: defineAsyncComponent(
- () => import('@/components/core/layouts/art-chat-window/index.vue')
- ),
- enabled: true
- },
- {
- name: '礼花效果',
- key: 'fireworks-effect',
- component: defineAsyncComponent(
- () => import('@/components/core/layouts/art-fireworks-effect/index.vue')
- ),
- enabled: true
- },
- {
- name: '水印效果',
- key: 'watermark',
- component: defineAsyncComponent(
- () => import('@/components/core/others/art-watermark/index.vue')
- ),
- enabled: true
- }
+ {
+ name: '设置面板',
+ key: 'settings-panel',
+ component: defineAsyncComponent(
+ () => import('@/components/core/layouts/art-settings-panel/index.vue')
+ ),
+ enabled: true
+ },
+ {
+ name: '全局搜索',
+ key: 'global-search',
+ component: defineAsyncComponent(
+ () => import('@/components/core/layouts/art-global-search/index.vue')
+ ),
+ enabled: true
+ },
+ {
+ name: '锁屏',
+ key: 'screen-lock',
+ component: defineAsyncComponent(
+ () => import('@/components/core/layouts/art-screen-lock/index.vue')
+ ),
+ enabled: true
+ },
+ {
+ name: '聊天窗口',
+ key: 'chat-window',
+ component: defineAsyncComponent(
+ () => import('@/components/core/layouts/art-chat-window/index.vue')
+ ),
+ enabled: true
+ },
+ {
+ name: '礼花效果',
+ key: 'fireworks-effect',
+ component: defineAsyncComponent(
+ () => import('@/components/core/layouts/art-fireworks-effect/index.vue')
+ ),
+ enabled: true
+ },
+ {
+ name: '水印效果',
+ key: 'watermark',
+ component: defineAsyncComponent(
+ () => import('@/components/core/others/art-watermark/index.vue')
+ ),
+ enabled: true
+ }
]
/**
* 全局组件配置接口
*/
export interface GlobalComponentConfig {
- /** 组件名称 */
- name: string
- /** 组件标识 */
- key: string
- /** 组件 */
- component: any
- /** 是否启用 */
- enabled?: boolean
- /** 组件描述 */
- description?: string
+ /** 组件名称 */
+ name: string
+ /** 组件标识 */
+ key: string
+ /** 组件 */
+ component: any
+ /** 是否启用 */
+ enabled?: boolean
+ /** 组件描述 */
+ description?: string
}
/**
@@ -92,7 +92,7 @@ export interface GlobalComponentConfig {
* @returns 已启用的组件配置列表
*/
export const getEnabledGlobalComponents = () => {
- return globalComponentsConfig.filter((config) => config.enabled !== false)
+ return globalComponentsConfig.filter((config) => config.enabled !== false)
}
/**
@@ -101,5 +101,5 @@ export const getEnabledGlobalComponents = () => {
* @returns 组件配置对象
*/
export const getGlobalComponentByKey = (key: string) => {
- return globalComponentsConfig.find((config) => config.key === key)
+ return globalComponentsConfig.find((config) => config.key === key)
}
diff --git a/src/config/modules/fastEnter.ts b/src/config/modules/fastEnter.ts
index 6b9740c..1ed13ac 100644
--- a/src/config/modules/fastEnter.ts
+++ b/src/config/modules/fastEnter.ts
@@ -6,122 +6,122 @@ import { WEB_LINKS } from '@/utils/constants'
import type { FastEnterConfig } from '@/types/config'
const fastEnterConfig: FastEnterConfig = {
- // 显示条件(屏幕宽度)
- minWidth: 1200,
- // 应用列表
- applications: [
- {
- name: '工作台',
- description: '系统概览与数据统计',
- icon: 'ri:pie-chart-line',
- iconColor: '#377dff',
- enabled: true,
- order: 1,
- routeName: 'Console'
- },
- {
- name: '分析页',
- description: '数据分析与可视化',
- icon: 'ri:game-line',
- iconColor: '#ff3b30',
- enabled: true,
- order: 2,
- routeName: 'Analysis'
- },
- {
- name: '礼花效果',
- description: '动画特效展示',
- icon: 'ri:loader-line',
- iconColor: '#7A7FFF',
- enabled: true,
- order: 3,
- routeName: 'Fireworks'
- },
- {
- name: '聊天',
- description: '即时通讯功能',
- icon: 'ri:user-line',
- iconColor: '#13DEB9',
- enabled: true,
- order: 4,
- routeName: 'Chat'
- },
- {
- name: '官方文档',
- description: '使用指南与开发文档',
- icon: 'ri:bill-line',
- iconColor: '#ffb100',
- enabled: true,
- order: 5,
- link: WEB_LINKS.DOCS
- },
- {
- name: '技术支持',
- description: '技术支持与问题反馈',
- icon: 'ri:user-location-line',
- iconColor: '#ff6b6b',
- enabled: true,
- order: 6,
- link: WEB_LINKS.COMMUNITY
- },
- {
- name: '更新日志',
- description: '版本更新与变更记录',
- icon: 'ri:gamepad-line',
- iconColor: '#38C0FC',
- enabled: true,
- order: 7,
- routeName: 'ChangeLog'
- },
- {
- name: '哔哩哔哩',
- description: '技术分享与交流',
- icon: 'ri:bilibili-line',
- iconColor: '#FB7299',
- enabled: true,
- order: 8,
- link: WEB_LINKS.BILIBILI
- }
- ],
- // 快速链接
- quickLinks: [
- {
- name: '登录',
- enabled: true,
- order: 1,
- routeName: 'Login'
- },
- {
- name: '注册',
- enabled: true,
- order: 2,
- routeName: 'Register'
- },
- {
- name: '忘记密码',
- enabled: true,
- order: 3,
- routeName: 'ForgetPassword'
- },
- {
- name: '定价',
- enabled: true,
- order: 4,
- routeName: 'Pricing'
- },
- {
- name: '个人中心',
- enabled: true,
- order: 5,
- routeName: 'UserCenter'
- },
- {
- name: '留言管理',
- enabled: true,
- order: 6,
- routeName: 'ArticleComment'
- }
- ]
+ // 显示条件(屏幕宽度)
+ minWidth: 1200,
+ // 应用列表
+ applications: [
+ {
+ name: '工作台',
+ description: '系统概览与数据统计',
+ icon: 'ri:pie-chart-line',
+ iconColor: '#377dff',
+ enabled: true,
+ order: 1,
+ routeName: 'Console'
+ },
+ {
+ name: '分析页',
+ description: '数据分析与可视化',
+ icon: 'ri:game-line',
+ iconColor: '#ff3b30',
+ enabled: true,
+ order: 2,
+ routeName: 'Analysis'
+ },
+ {
+ name: '礼花效果',
+ description: '动画特效展示',
+ icon: 'ri:loader-line',
+ iconColor: '#7A7FFF',
+ enabled: true,
+ order: 3,
+ routeName: 'Fireworks'
+ },
+ {
+ name: '聊天',
+ description: '即时通讯功能',
+ icon: 'ri:user-line',
+ iconColor: '#13DEB9',
+ enabled: true,
+ order: 4,
+ routeName: 'Chat'
+ },
+ {
+ name: '官方文档',
+ description: '使用指南与开发文档',
+ icon: 'ri:bill-line',
+ iconColor: '#ffb100',
+ enabled: true,
+ order: 5,
+ link: WEB_LINKS.DOCS
+ },
+ {
+ name: '技术支持',
+ description: '技术支持与问题反馈',
+ icon: 'ri:user-location-line',
+ iconColor: '#ff6b6b',
+ enabled: true,
+ order: 6,
+ link: WEB_LINKS.COMMUNITY
+ },
+ {
+ name: '更新日志',
+ description: '版本更新与变更记录',
+ icon: 'ri:gamepad-line',
+ iconColor: '#38C0FC',
+ enabled: true,
+ order: 7,
+ routeName: 'ChangeLog'
+ },
+ {
+ name: '哔哩哔哩',
+ description: '技术分享与交流',
+ icon: 'ri:bilibili-line',
+ iconColor: '#FB7299',
+ enabled: true,
+ order: 8,
+ link: WEB_LINKS.BILIBILI
+ }
+ ],
+ // 快速链接
+ quickLinks: [
+ {
+ name: '登录',
+ enabled: true,
+ order: 1,
+ routeName: 'Login'
+ },
+ {
+ name: '注册',
+ enabled: true,
+ order: 2,
+ routeName: 'Register'
+ },
+ {
+ name: '忘记密码',
+ enabled: true,
+ order: 3,
+ routeName: 'ForgetPassword'
+ },
+ {
+ name: '定价',
+ enabled: true,
+ order: 4,
+ routeName: 'Pricing'
+ },
+ {
+ name: '个人中心',
+ enabled: true,
+ order: 5,
+ routeName: 'UserCenter'
+ },
+ {
+ name: '留言管理',
+ enabled: true,
+ order: 6,
+ routeName: 'ArticleComment'
+ }
+ ]
}
export default Object.freeze(fastEnterConfig)
diff --git a/src/config/modules/festival.ts b/src/config/modules/festival.ts
index 39cd790..e1b773f 100644
--- a/src/config/modules/festival.ts
+++ b/src/config/modules/festival.ts
@@ -30,22 +30,22 @@ import { FestivalConfig } from '@/types/config'
// import yd from '@imgs/ceremony/yd.png'
export const festivalConfigList: FestivalConfig[] = [
- // 跨日期示例
- // {
- // name: 'v3.0 Sass 升级至 TailwindCSS',
- // date: '2025-11-03',
- // endDate: '2025-11-09',
- // image: '',
- // count: 3,
- // scrollText:
- // '🚀 系统 v3.0 测试阶段正式开启!测试周期为 11 月 3 日 - 11 月 16 日,通过 TailwindCSS 重构样式体系、统一 Iconify 图标方案,带来更高效现代的开发体验,正式发布敬请期待~'
- // }
- // 单日示例:圣诞节
- // {
- // name: '圣诞节',
- // date: '2024-12-25',
- // image: sd,
- // count: 3 // 可选,不设置则使用默认值 3 次
- // scrollText: 'Merry Christmas!Art Design Pro 祝您圣诞快乐,愿节日的欢乐与祝福如雪花般纷至沓来!',
- // }
+ // 跨日期示例
+ // {
+ // name: 'v3.0 Sass 升级至 TailwindCSS',
+ // date: '2025-11-03',
+ // endDate: '2025-11-09',
+ // image: '',
+ // count: 3,
+ // scrollText:
+ // '🚀 系统 v3.0 测试阶段正式开启!测试周期为 11 月 3 日 - 11 月 16 日,通过 TailwindCSS 重构样式体系、统一 Iconify 图标方案,带来更高效现代的开发体验,正式发布敬请期待~'
+ // }
+ // 单日示例:圣诞节
+ // {
+ // name: '圣诞节',
+ // date: '2024-12-25',
+ // image: sd,
+ // count: 3 // 可选,不设置则使用默认值 3 次
+ // scrollText: 'Merry Christmas!Art Design Pro 祝您圣诞快乐,愿节日的欢乐与祝福如雪花般纷至沓来!',
+ // }
]
diff --git a/src/config/modules/headerBar.ts b/src/config/modules/headerBar.ts
index a420e82..279868e 100644
--- a/src/config/modules/headerBar.ts
+++ b/src/config/modules/headerBar.ts
@@ -14,50 +14,50 @@ import { HeaderBarFeatureConfig } from '@/types'
* 顶部栏功能配置对象
*/
export const headerBarConfig: HeaderBarFeatureConfig = {
- menuButton: {
- enabled: true,
- description: '控制左侧菜单的展开/收起按钮'
- },
- refreshButton: {
- enabled: true,
- description: '页面刷新按钮'
- },
- fastEnter: {
- enabled: true,
- description: '快速入口功能,提供常用应用和链接的快速访问'
- },
- breadcrumb: {
- enabled: true,
- description: '面包屑导航,显示当前页面路径'
- },
- globalSearch: {
- enabled: true,
- description: '全局搜索功能,支持快捷键 Ctrl+K 或 Cmd+K'
- },
- fullscreen: {
- enabled: true,
- description: '全屏切换功能'
- },
- notification: {
- enabled: true,
- description: '通知中心,显示系统通知和消息'
- },
- chat: {
- enabled: true,
- description: '聊天功能,提供实时沟通'
- },
- language: {
- enabled: true,
- description: '多语言切换功能'
- },
- settings: {
- enabled: true,
- description: '系统设置面板'
- },
- themeToggle: {
- enabled: true,
- description: '主题切换功能(明暗主题)'
- }
+ menuButton: {
+ enabled: true,
+ description: '控制左侧菜单的展开/收起按钮'
+ },
+ refreshButton: {
+ enabled: true,
+ description: '页面刷新按钮'
+ },
+ fastEnter: {
+ enabled: true,
+ description: '快速入口功能,提供常用应用和链接的快速访问'
+ },
+ breadcrumb: {
+ enabled: true,
+ description: '面包屑导航,显示当前页面路径'
+ },
+ globalSearch: {
+ enabled: true,
+ description: '全局搜索功能,支持快捷键 Ctrl+K 或 Cmd+K'
+ },
+ fullscreen: {
+ enabled: true,
+ description: '全屏切换功能'
+ },
+ notification: {
+ enabled: true,
+ description: '通知中心,显示系统通知和消息'
+ },
+ chat: {
+ enabled: true,
+ description: '聊天功能,提供实时沟通'
+ },
+ language: {
+ enabled: true,
+ description: '多语言切换功能'
+ },
+ settings: {
+ enabled: true,
+ description: '系统设置面板'
+ },
+ themeToggle: {
+ enabled: true,
+ description: '主题切换功能(明暗主题)'
+ }
}
export default headerBarConfig
diff --git a/src/config/setting.ts b/src/config/setting.ts
index 94f2d2c..71ad251 100644
--- a/src/config/setting.ts
+++ b/src/config/setting.ts
@@ -27,64 +27,64 @@ import { SystemThemeEnum, MenuThemeEnum, MenuTypeEnum, ContainerWidthEnum } from
* 系统设置默认值配置
*/
export const SETTING_DEFAULT_CONFIG = {
- /** 菜单类型 */
- menuType: MenuTypeEnum.LEFT,
- /** 菜单展开宽度 */
- menuOpenWidth: 230,
- /** 菜单是否展开 */
- menuOpen: true,
- /** 双菜单是否显示文本 */
- dualMenuShowText: false,
- /** 系统主题类型 */
- systemThemeType: SystemThemeEnum.AUTO,
- /** 系统主题模式 */
- systemThemeMode: SystemThemeEnum.AUTO,
- /** 菜单风格 */
- menuThemeType: MenuThemeEnum.DESIGN,
- /** 系统主题颜色 */
- systemThemeColor: AppConfig.systemMainColor[0],
- /** 是否显示菜单按钮 */
- showMenuButton: true,
- /** 是否显示快速入口 */
- showFastEnter: true,
- /** 是否显示刷新按钮 */
- showRefreshButton: true,
- /** 是否显示面包屑 */
- showCrumbs: true,
- /** 是否显示工作台标签 */
- showWorkTab: true,
- /** 是否显示语言切换 */
- showLanguage: true,
- /** 是否显示进度条 */
- showNprogress: false,
- /** 是否显示设置引导 */
- showSettingGuide: true,
- /** 是否显示节日文本 */
- showFestivalText: false,
- /** 是否显示水印 */
- watermarkVisible: false,
- /** 是否自动关闭 */
- autoClose: false,
- /** 是否唯一展开 */
- uniqueOpened: true,
- /** 是否色弱模式 */
- colorWeak: false,
- /** 是否刷新 */
- refresh: false,
- /** 是否加载节日烟花 */
- holidayFireworksLoaded: false,
- /** 边框模式 */
- boxBorderMode: true,
- /** 页面过渡效果 */
- pageTransition: 'slide-left',
- /** 标签页样式 */
- tabStyle: 'tab-default',
- /** 自定义圆角 */
- customRadius: '0.75',
- /** 容器宽度 */
- containerWidth: ContainerWidthEnum.FULL,
- /** 节日日期 */
- festivalDate: ''
+ /** 菜单类型 */
+ menuType: MenuTypeEnum.LEFT,
+ /** 菜单展开宽度 */
+ menuOpenWidth: 230,
+ /** 菜单是否展开 */
+ menuOpen: true,
+ /** 双菜单是否显示文本 */
+ dualMenuShowText: false,
+ /** 系统主题类型 */
+ systemThemeType: SystemThemeEnum.AUTO,
+ /** 系统主题模式 */
+ systemThemeMode: SystemThemeEnum.AUTO,
+ /** 菜单风格 */
+ menuThemeType: MenuThemeEnum.DESIGN,
+ /** 系统主题颜色 */
+ systemThemeColor: AppConfig.systemMainColor[0],
+ /** 是否显示菜单按钮 */
+ showMenuButton: true,
+ /** 是否显示快速入口 */
+ showFastEnter: true,
+ /** 是否显示刷新按钮 */
+ showRefreshButton: true,
+ /** 是否显示面包屑 */
+ showCrumbs: true,
+ /** 是否显示工作台标签 */
+ showWorkTab: true,
+ /** 是否显示语言切换 */
+ showLanguage: true,
+ /** 是否显示进度条 */
+ showNprogress: false,
+ /** 是否显示设置引导 */
+ showSettingGuide: true,
+ /** 是否显示节日文本 */
+ showFestivalText: false,
+ /** 是否显示水印 */
+ watermarkVisible: false,
+ /** 是否自动关闭 */
+ autoClose: false,
+ /** 是否唯一展开 */
+ uniqueOpened: true,
+ /** 是否色弱模式 */
+ colorWeak: false,
+ /** 是否刷新 */
+ refresh: false,
+ /** 是否加载节日烟花 */
+ holidayFireworksLoaded: false,
+ /** 边框模式 */
+ boxBorderMode: true,
+ /** 页面过渡效果 */
+ pageTransition: 'slide-left',
+ /** 标签页样式 */
+ tabStyle: 'tab-default',
+ /** 自定义圆角 */
+ customRadius: '0.75',
+ /** 容器宽度 */
+ containerWidth: ContainerWidthEnum.FULL,
+ /** 节日日期 */
+ festivalDate: ''
}
/**
@@ -92,7 +92,7 @@ export const SETTING_DEFAULT_CONFIG = {
* @returns 设置默认值对象
*/
export function getSettingDefaults() {
- return { ...SETTING_DEFAULT_CONFIG }
+ return { ...SETTING_DEFAULT_CONFIG }
}
/**
@@ -100,10 +100,10 @@ export function getSettingDefaults() {
* @param currentSettings 当前设置对象
*/
export function resetToDefaults(currentSettings: Record) {
- const defaults = getSettingDefaults()
- Object.keys(defaults).forEach((key) => {
- if (key in currentSettings) {
- currentSettings[key] = defaults[key as keyof typeof defaults]
- }
- })
+ const defaults = getSettingDefaults()
+ Object.keys(defaults).forEach((key) => {
+ if (key in currentSettings) {
+ currentSettings[key] = defaults[key as keyof typeof defaults]
+ }
+ })
}
diff --git a/src/directives/business/highlight.ts b/src/directives/business/highlight.ts
index 13af225..e2a4528 100644
--- a/src/directives/business/highlight.ts
+++ b/src/directives/business/highlight.ts
@@ -46,203 +46,203 @@ import hljs from 'highlight.js'
// 高亮代码
function highlightCode(block: HTMLElement) {
- hljs.highlightElement(block)
+ hljs.highlightElement(block)
}
// 插入行号
function insertLineNumbers(block: HTMLElement) {
- const lines = block.innerHTML.split('\n')
- const numberedLines = lines
- .map((line, index) => {
- return `${index + 1} ${line}`
- })
- .join('\n')
- block.innerHTML = numberedLines
+ const lines = block.innerHTML.split('\n')
+ const numberedLines = lines
+ .map((line, index) => {
+ return `${index + 1} ${line}`
+ })
+ .join('\n')
+ block.innerHTML = numberedLines
}
// 添加复制按钮:调整 DOM 结构,将代码部分包裹在 .code-wrapper 内
function addCopyButton(block: HTMLElement) {
- const copyButton = document.createElement('i')
- copyButton.className = 'copy-button'
- copyButton.innerHTML =
- ''
- copyButton.onclick = () => {
- // 过滤掉行号,只复制代码内容
- const codeContent = block.innerText.replace(/^\d+\s+/gm, '')
- navigator.clipboard.writeText(codeContent).then(() => {
- ElMessage.success('复制成功')
- })
- }
+ const copyButton = document.createElement('i')
+ copyButton.className = 'copy-button'
+ copyButton.innerHTML =
+ ''
+ copyButton.onclick = () => {
+ // 过滤掉行号,只复制代码内容
+ const codeContent = block.innerText.replace(/^\d+\s+/gm, '')
+ navigator.clipboard.writeText(codeContent).then(() => {
+ ElMessage.success('复制成功')
+ })
+ }
- const preElement = block.parentElement
- if (preElement) {
- let codeWrapper: HTMLElement
- // 如果代码块还没有被包裹,则创建包裹容器
- if (!block.parentElement.classList.contains('code-wrapper')) {
- codeWrapper = document.createElement('div')
- codeWrapper.className = 'code-wrapper'
- preElement.replaceChild(codeWrapper, block)
- codeWrapper.appendChild(block)
- } else {
- codeWrapper = block.parentElement
- }
- // 将复制按钮添加到 pre 元素(而非 codeWrapper 内),这样它不会随滚动条滚动
- preElement.appendChild(copyButton)
- }
+ const preElement = block.parentElement
+ if (preElement) {
+ let codeWrapper: HTMLElement
+ // 如果代码块还没有被包裹,则创建包裹容器
+ if (!block.parentElement.classList.contains('code-wrapper')) {
+ codeWrapper = document.createElement('div')
+ codeWrapper.className = 'code-wrapper'
+ preElement.replaceChild(codeWrapper, block)
+ codeWrapper.appendChild(block)
+ } else {
+ codeWrapper = block.parentElement
+ }
+ // 将复制按钮添加到 pre 元素(而非 codeWrapper 内),这样它不会随滚动条滚动
+ preElement.appendChild(copyButton)
+ }
}
// 检查代码块是否已经被处理过
function isBlockProcessed(block: HTMLElement): boolean {
- return (
- block.hasAttribute('data-highlighted') ||
- !!block.querySelector('.line-number') ||
- !!block.parentElement?.querySelector('.copy-button')
- )
+ return (
+ block.hasAttribute('data-highlighted') ||
+ !!block.querySelector('.line-number') ||
+ !!block.parentElement?.querySelector('.copy-button')
+ )
}
// 标记代码块为已处理
function markBlockAsProcessed(block: HTMLElement) {
- block.setAttribute('data-highlighted', 'true')
+ block.setAttribute('data-highlighted', 'true')
}
// 处理单个代码块
function processBlock(block: HTMLElement) {
- if (isBlockProcessed(block)) {
- return
- }
+ if (isBlockProcessed(block)) {
+ return
+ }
- try {
- highlightCode(block)
- insertLineNumbers(block)
- addCopyButton(block)
- markBlockAsProcessed(block)
- } catch (error) {
- console.warn('处理代码块时出错:', error)
- }
+ try {
+ highlightCode(block)
+ insertLineNumbers(block)
+ addCopyButton(block)
+ markBlockAsProcessed(block)
+ } catch (error) {
+ console.warn('处理代码块时出错:', error)
+ }
}
// 查找并处理所有代码块
function processAllCodeBlocks(el: HTMLElement) {
- const blocks = Array.from(el.querySelectorAll('pre code'))
- const unprocessedBlocks = blocks.filter((block) => !isBlockProcessed(block))
+ const blocks = Array.from(el.querySelectorAll('pre code'))
+ const unprocessedBlocks = blocks.filter((block) => !isBlockProcessed(block))
- if (unprocessedBlocks.length === 0) {
- return
- }
+ if (unprocessedBlocks.length === 0) {
+ return
+ }
- if (unprocessedBlocks.length <= 10) {
- // 如果代码块数量少于等于10,直接处理所有代码块
- unprocessedBlocks.forEach((block) => processBlock(block))
- } else {
- // 定义每次处理的代码块数
- const batchSize = 10
- let currentIndex = 0
+ if (unprocessedBlocks.length <= 10) {
+ // 如果代码块数量少于等于10,直接处理所有代码块
+ unprocessedBlocks.forEach((block) => processBlock(block))
+ } else {
+ // 定义每次处理的代码块数
+ const batchSize = 10
+ let currentIndex = 0
- const processBatch = () => {
- const batch = unprocessedBlocks.slice(currentIndex, currentIndex + batchSize)
+ const processBatch = () => {
+ const batch = unprocessedBlocks.slice(currentIndex, currentIndex + batchSize)
- batch.forEach((block) => {
- processBlock(block)
- })
+ batch.forEach((block) => {
+ processBlock(block)
+ })
- // 更新索引并继续处理下一批
- currentIndex += batchSize
- if (currentIndex < unprocessedBlocks.length) {
- // 使用 requestAnimationFrame 确保下一帧再处理
- requestAnimationFrame(processBatch)
- }
- }
+ // 更新索引并继续处理下一批
+ currentIndex += batchSize
+ if (currentIndex < unprocessedBlocks.length) {
+ // 使用 requestAnimationFrame 确保下一帧再处理
+ requestAnimationFrame(processBatch)
+ }
+ }
- // 开始处理第一批代码块
- processBatch()
- }
+ // 开始处理第一批代码块
+ processBatch()
+ }
}
// 重试处理函数
function retryProcessing(el: HTMLElement, maxRetries: number = 3, delay: number = 200) {
- let retryCount = 0
+ let retryCount = 0
- const tryProcess = () => {
- processAllCodeBlocks(el)
+ const tryProcess = () => {
+ processAllCodeBlocks(el)
- // 检查是否还有未处理的代码块
- const remainingBlocks = Array.from(el.querySelectorAll('pre code')).filter(
- (block) => !isBlockProcessed(block)
- )
+ // 检查是否还有未处理的代码块
+ const remainingBlocks = Array.from(el.querySelectorAll('pre code')).filter(
+ (block) => !isBlockProcessed(block)
+ )
- if (remainingBlocks.length > 0 && retryCount < maxRetries) {
- retryCount++
- setTimeout(tryProcess, delay * retryCount) // 递增延迟
- }
- }
+ if (remainingBlocks.length > 0 && retryCount < maxRetries) {
+ retryCount++
+ setTimeout(tryProcess, delay * retryCount) // 递增延迟
+ }
+ }
- tryProcess()
+ tryProcess()
}
// 代码高亮、插入行号、复制按钮
const highlightDirective: Directive = {
- mounted(el: HTMLElement) {
- // 立即尝试处理一次
- processAllCodeBlocks(el)
+ mounted(el: HTMLElement) {
+ // 立即尝试处理一次
+ processAllCodeBlocks(el)
- // 延迟处理,确保 v-html 内容已经渲染
- setTimeout(() => {
- retryProcessing(el)
- }, 100)
+ // 延迟处理,确保 v-html 内容已经渲染
+ setTimeout(() => {
+ retryProcessing(el)
+ }, 100)
- // 使用 MutationObserver 监听 DOM 变化
- const observer = new MutationObserver((mutations) => {
- let hasNewCodeBlocks = false
+ // 使用 MutationObserver 监听 DOM 变化
+ const observer = new MutationObserver((mutations) => {
+ let hasNewCodeBlocks = false
- mutations.forEach((mutation) => {
- if (mutation.type === 'childList') {
- mutation.addedNodes.forEach((node) => {
- if (node.nodeType === Node.ELEMENT_NODE) {
- const element = node as HTMLElement
- // 检查新添加的节点是否包含代码块
- if (element.tagName === 'PRE' || element.querySelector('pre code')) {
- hasNewCodeBlocks = true
- }
- }
- })
- }
- })
+ mutations.forEach((mutation) => {
+ if (mutation.type === 'childList') {
+ mutation.addedNodes.forEach((node) => {
+ if (node.nodeType === Node.ELEMENT_NODE) {
+ const element = node as HTMLElement
+ // 检查新添加的节点是否包含代码块
+ if (element.tagName === 'PRE' || element.querySelector('pre code')) {
+ hasNewCodeBlocks = true
+ }
+ }
+ })
+ }
+ })
- if (hasNewCodeBlocks) {
- // 延迟处理新添加的代码块
- setTimeout(() => {
- processAllCodeBlocks(el)
- }, 50)
- }
- })
+ if (hasNewCodeBlocks) {
+ // 延迟处理新添加的代码块
+ setTimeout(() => {
+ processAllCodeBlocks(el)
+ }, 50)
+ }
+ })
- // 开始观察
- observer.observe(el, {
- childList: true,
- subtree: true
- })
+ // 开始观察
+ observer.observe(el, {
+ childList: true,
+ subtree: true
+ })
- // 将 observer 存储到元素上,以便在 unmounted 时清理
- ;(el as any)._highlightObserver = observer
- },
+ // 将 observer 存储到元素上,以便在 unmounted 时清理
+ ;(el as any)._highlightObserver = observer
+ },
- updated(el: HTMLElement) {
- // 当组件更新时,重新处理代码块
- setTimeout(() => {
- processAllCodeBlocks(el)
- }, 50)
- },
+ updated(el: HTMLElement) {
+ // 当组件更新时,重新处理代码块
+ setTimeout(() => {
+ processAllCodeBlocks(el)
+ }, 50)
+ },
- unmounted(el: HTMLElement) {
- // 清理 MutationObserver
- const observer = (el as any)._highlightObserver
- if (observer) {
- observer.disconnect()
- delete (el as any)._highlightObserver
- }
- }
+ unmounted(el: HTMLElement) {
+ // 清理 MutationObserver
+ const observer = (el as any)._highlightObserver
+ if (observer) {
+ observer.disconnect()
+ delete (el as any)._highlightObserver
+ }
+ }
}
export function setupHighlightDirective(app: App) {
- app.directive('highlight', highlightDirective)
+ app.directive('highlight', highlightDirective)
}
diff --git a/src/directives/business/ripple.ts b/src/directives/business/ripple.ts
index 8d7d8f9..07ae435 100644
--- a/src/directives/business/ripple.ts
+++ b/src/directives/business/ripple.ts
@@ -40,75 +40,75 @@
import type { App, Directive, DirectiveBinding } from 'vue'
export interface RippleOptions {
- /** 水波纹颜色 */
- color?: string
+ /** 水波纹颜色 */
+ color?: string
}
export const vRipple: Directive = {
- mounted(el: HTMLElement, binding: DirectiveBinding) {
- // 获取指令的配置参数
- const options: RippleOptions = binding.value || {}
+ mounted(el: HTMLElement, binding: DirectiveBinding) {
+ // 获取指令的配置参数
+ const options: RippleOptions = binding.value || {}
- // 设置元素为相对定位,并隐藏溢出部分
- el.style.position = 'relative'
- el.style.overflow = 'hidden'
+ // 设置元素为相对定位,并隐藏溢出部分
+ el.style.position = 'relative'
+ el.style.overflow = 'hidden'
- // 点击事件处理
- el.addEventListener('mousedown', (e: MouseEvent) => {
- const rect = el.getBoundingClientRect()
- const left = e.clientX - rect.left
- const top = e.clientY - rect.top
+ // 点击事件处理
+ el.addEventListener('mousedown', (e: MouseEvent) => {
+ const rect = el.getBoundingClientRect()
+ const left = e.clientX - rect.left
+ const top = e.clientY - rect.top
- // 创建水波纹元素
- const ripple = document.createElement('div')
- const diameter = Math.max(el.clientWidth, el.clientHeight)
- const radius = diameter / 2
+ // 创建水波纹元素
+ const ripple = document.createElement('div')
+ const diameter = Math.max(el.clientWidth, el.clientHeight)
+ const radius = diameter / 2
- // 根据直径计算动画时间(直径越大,动画时间越长)
- const baseTime = 600 // 基础动画时间(毫秒)
- const scaleFactor = 0.5 // 缩放因子
- const animationDuration = baseTime + diameter * scaleFactor
+ // 根据直径计算动画时间(直径越大,动画时间越长)
+ const baseTime = 600 // 基础动画时间(毫秒)
+ const scaleFactor = 0.5 // 缩放因子
+ const animationDuration = baseTime + diameter * scaleFactor
- // 设置水波纹的尺寸和位置
- ripple.style.width = ripple.style.height = `${diameter}px`
- ripple.style.left = `${left - radius}px`
- ripple.style.top = `${top - radius}px`
- ripple.style.position = 'absolute'
- ripple.style.borderRadius = '50%'
- ripple.style.pointerEvents = 'none'
+ // 设置水波纹的尺寸和位置
+ ripple.style.width = ripple.style.height = `${diameter}px`
+ ripple.style.left = `${left - radius}px`
+ ripple.style.top = `${top - radius}px`
+ ripple.style.position = 'absolute'
+ ripple.style.borderRadius = '50%'
+ ripple.style.pointerEvents = 'none'
- // 判断是否为有色按钮(Element Plus 按钮类型)
- const buttonTypes = ['primary', 'info', 'warning', 'danger', 'success'].map(
- (type) => `el-button--${type}`
- )
- const isColoredButton = buttonTypes.some((type) => el.classList.contains(type))
- const defaultColor = isColoredButton
- ? 'rgba(255, 255, 255, 0.25)' // 有色按钮使用白色水波纹
- : 'var(--el-color-primary-light-7)' // 默认按钮使用主题色水波纹
+ // 判断是否为有色按钮(Element Plus 按钮类型)
+ const buttonTypes = ['primary', 'info', 'warning', 'danger', 'success'].map(
+ (type) => `el-button--${type}`
+ )
+ const isColoredButton = buttonTypes.some((type) => el.classList.contains(type))
+ const defaultColor = isColoredButton
+ ? 'rgba(255, 255, 255, 0.25)' // 有色按钮使用白色水波纹
+ : 'var(--el-color-primary-light-7)' // 默认按钮使用主题色水波纹
- // 设置水波纹颜色、初始状态和过渡效果
- ripple.style.backgroundColor = options.color || defaultColor
- ripple.style.transform = 'scale(0)'
- ripple.style.transition = `transform ${animationDuration}ms cubic-bezier(0.3, 0, 0.2, 1), opacity ${animationDuration}ms cubic-bezier(0.3, 0, 0.5, 1)`
- ripple.style.zIndex = '1'
+ // 设置水波纹颜色、初始状态和过渡效果
+ ripple.style.backgroundColor = options.color || defaultColor
+ ripple.style.transform = 'scale(0)'
+ ripple.style.transition = `transform ${animationDuration}ms cubic-bezier(0.3, 0, 0.2, 1), opacity ${animationDuration}ms cubic-bezier(0.3, 0, 0.5, 1)`
+ ripple.style.zIndex = '1'
- // 添加水波纹元素到DOM中
- el.appendChild(ripple)
+ // 添加水波纹元素到DOM中
+ el.appendChild(ripple)
- // 触发动画
- requestAnimationFrame(() => {
- ripple.style.transform = 'scale(2)'
- ripple.style.opacity = '0'
- })
+ // 触发动画
+ requestAnimationFrame(() => {
+ ripple.style.transform = 'scale(2)'
+ ripple.style.opacity = '0'
+ })
- // 动画结束后移除水波纹元素
- setTimeout(() => {
- ripple.remove()
- }, animationDuration + 500) // 增加500ms缓冲时间
- })
- }
+ // 动画结束后移除水波纹元素
+ setTimeout(() => {
+ ripple.remove()
+ }, animationDuration + 500) // 增加500ms缓冲时间
+ })
+ }
}
export function setupRippleDirective(app: App) {
- app.directive('ripple', vRipple)
+ app.directive('ripple', vRipple)
}
diff --git a/src/directives/core/auth.ts b/src/directives/core/auth.ts
index b9e85d8..0fac2b8 100644
--- a/src/directives/core/auth.ts
+++ b/src/directives/core/auth.ts
@@ -36,33 +36,33 @@ import { router } from '@/router'
import { App, Directive, DirectiveBinding } from 'vue'
interface AuthBinding extends DirectiveBinding {
- value: string
+ value: string
}
function checkAuthPermission(el: HTMLElement, binding: AuthBinding): void {
- // 获取当前路由的权限列表
- const authList = (router.currentRoute.value.meta.authList as Array<{ authMark: string }>) || []
+ // 获取当前路由的权限列表
+ const authList = (router.currentRoute.value.meta.authList as Array<{ authMark: string }>) || []
- // 检查是否有对应的权限标识
- const hasPermission = authList.some((item) => item.authMark === binding.value)
+ // 检查是否有对应的权限标识
+ const hasPermission = authList.some((item) => item.authMark === binding.value)
- // 如果没有权限,移除元素
- if (!hasPermission) {
- removeElement(el)
- }
+ // 如果没有权限,移除元素
+ if (!hasPermission) {
+ removeElement(el)
+ }
}
function removeElement(el: HTMLElement): void {
- if (el.parentNode) {
- el.parentNode.removeChild(el)
- }
+ if (el.parentNode) {
+ el.parentNode.removeChild(el)
+ }
}
const authDirective: Directive = {
- mounted: checkAuthPermission,
- updated: checkAuthPermission
+ mounted: checkAuthPermission,
+ updated: checkAuthPermission
}
export function setupAuthDirective(app: App): void {
- app.directive('auth', authDirective)
+ app.directive('auth', authDirective)
}
diff --git a/src/directives/core/roles.ts b/src/directives/core/roles.ts
index 2ab1029..b0a076e 100644
--- a/src/directives/core/roles.ts
+++ b/src/directives/core/roles.ts
@@ -48,42 +48,42 @@ import { useUserStore } from '@/store/modules/user'
import { App, Directive, DirectiveBinding } from 'vue'
interface RolesBinding extends DirectiveBinding {
- value: string | string[]
+ value: string | string[]
}
function checkRolePermission(el: HTMLElement, binding: RolesBinding): void {
- const userStore = useUserStore()
- const userRoles = userStore.getUserInfo.roles
+ const userStore = useUserStore()
+ const userRoles = userStore.getUserInfo.roles
- // 如果用户角色为空或未定义,移除元素
- if (!userRoles?.length) {
- removeElement(el)
- return
- }
+ // 如果用户角色为空或未定义,移除元素
+ if (!userRoles?.length) {
+ removeElement(el)
+ return
+ }
- // 确保指令值为数组格式
- const requiredRoles = Array.isArray(binding.value) ? binding.value : [binding.value]
+ // 确保指令值为数组格式
+ const requiredRoles = Array.isArray(binding.value) ? binding.value : [binding.value]
- // 检查用户是否具有所需角色之一
- const hasPermission = requiredRoles.some((role: string) => userRoles.includes(role))
+ // 检查用户是否具有所需角色之一
+ const hasPermission = requiredRoles.some((role: string) => userRoles.includes(role))
- // 如果没有权限,安全地移除元素
- if (!hasPermission) {
- removeElement(el)
- }
+ // 如果没有权限,安全地移除元素
+ if (!hasPermission) {
+ removeElement(el)
+ }
}
function removeElement(el: HTMLElement): void {
- if (el.parentNode) {
- el.parentNode.removeChild(el)
- }
+ if (el.parentNode) {
+ el.parentNode.removeChild(el)
+ }
}
const rolesDirective: Directive = {
- mounted: checkRolePermission,
- updated: checkRolePermission
+ mounted: checkRolePermission,
+ updated: checkRolePermission
}
export function setupRolesDirective(app: App): void {
- app.directive('roles', rolesDirective)
+ app.directive('roles', rolesDirective)
}
diff --git a/src/directives/index.ts b/src/directives/index.ts
index 780464b..4540fcb 100644
--- a/src/directives/index.ts
+++ b/src/directives/index.ts
@@ -5,8 +5,8 @@ import { setupRippleDirective } from './business/ripple'
import { setupRolesDirective } from './core/roles'
export function setupGlobDirectives(app: App) {
- setupAuthDirective(app) // 权限指令
- setupRolesDirective(app) // 角色权限指令
- setupHighlightDirective(app) // 高亮指令
- setupRippleDirective(app) // 水波纹指令
+ setupAuthDirective(app) // 权限指令
+ setupRolesDirective(app) // 角色权限指令
+ setupHighlightDirective(app) // 高亮指令
+ setupRippleDirective(app) // 水波纹指令
}
diff --git a/src/enums/appEnum.ts b/src/enums/appEnum.ts
index a39c278..4444d28 100644
--- a/src/enums/appEnum.ts
+++ b/src/enums/appEnum.ts
@@ -18,64 +18,64 @@
* 菜单类型
*/
export enum MenuTypeEnum {
- /** 左侧菜单 */
- LEFT = 'left',
- /** 顶部菜单 */
- TOP = 'top',
- /** 顶部+左侧菜单 */
- TOP_LEFT = 'top-left',
- /** 双栏菜单 */
- DUAL_MENU = 'dual-menu'
+ /** 左侧菜单 */
+ LEFT = 'left',
+ /** 顶部菜单 */
+ TOP = 'top',
+ /** 顶部+左侧菜单 */
+ TOP_LEFT = 'top-left',
+ /** 双栏菜单 */
+ DUAL_MENU = 'dual-menu'
}
/**
* 系统主题
*/
export enum SystemThemeEnum {
- /** 暗色主题 */
- DARK = 'dark',
- /** 亮色主题 */
- LIGHT = 'light',
- /** 自动主题(跟随系统) */
- AUTO = 'auto'
+ /** 暗色主题 */
+ DARK = 'dark',
+ /** 亮色主题 */
+ LIGHT = 'light',
+ /** 自动主题(跟随系统) */
+ AUTO = 'auto'
}
/**
* 菜单主题
*/
export enum MenuThemeEnum {
- /** 暗色主题 */
- DARK = 'dark',
- /** 亮色主题 */
- LIGHT = 'light',
- /** 设计主题 */
- DESIGN = 'design'
+ /** 暗色主题 */
+ DARK = 'dark',
+ /** 亮色主题 */
+ LIGHT = 'light',
+ /** 设计主题 */
+ DESIGN = 'design'
}
/**
* 菜单宽度
*/
export enum MenuWidth {
- /** 收起宽度 */
- CLOSE = '64px'
+ /** 收起宽度 */
+ CLOSE = '64px'
}
/**
* 语言类型
*/
export enum LanguageEnum {
- /** 中文 */
- ZH = 'zh',
- /** 英文 */
- EN = 'en'
+ /** 中文 */
+ ZH = 'zh',
+ /** 英文 */
+ EN = 'en'
}
/**
* 容器宽度
*/
export enum ContainerWidthEnum {
- /** 全屏宽度 */
- FULL = '100%',
- /** 固定宽度 */
- BOXED = '1200px'
+ /** 全屏宽度 */
+ FULL = '100%',
+ /** 固定宽度 */
+ BOXED = '1200px'
}
diff --git a/src/enums/formEnum.ts b/src/enums/formEnum.ts
index 8e9b3b4..dfabe70 100644
--- a/src/enums/formEnum.ts
+++ b/src/enums/formEnum.ts
@@ -12,13 +12,13 @@
// 页面类型
export enum PageModeEnum {
- Add, // 新增
- Edit // 编辑
+ Add, // 新增
+ Edit // 编辑
}
// 表格大小
export enum TableSizeEnum {
- DEFAULT = 'default',
- SMALL = 'small',
- LARGE = 'large'
+ DEFAULT = 'default',
+ SMALL = 'small',
+ LARGE = 'large'
}
diff --git a/src/env.d.ts b/src/env.d.ts
index 4401f21..80abd08 100644
--- a/src/env.d.ts
+++ b/src/env.d.ts
@@ -9,25 +9,25 @@ declare module 'vue-img-cutter'
declare module 'file-saver'
declare module 'qrcode.vue' {
- export type Level = 'L' | 'M' | 'Q' | 'H'
- export type RenderAs = 'canvas' | 'svg'
- export type GradientType = 'linear' | 'radial'
- export interface ImageSettings {
- src: string
- height: number
- width: number
- excavate: boolean
- }
- export interface QRCodeProps {
- value: string
- size?: number
- level?: Level
- background?: string
- foreground?: string
- renderAs?: RenderAs
- }
- const QrcodeVue: any
- export default QrcodeVue
+ export type Level = 'L' | 'M' | 'Q' | 'H'
+ export type RenderAs = 'canvas' | 'svg'
+ export type GradientType = 'linear' | 'radial'
+ export interface ImageSettings {
+ src: string
+ height: number
+ width: number
+ excavate: boolean
+ }
+ export interface QRCodeProps {
+ value: string
+ size?: number
+ level?: Level
+ background?: string
+ foreground?: string
+ renderAs?: RenderAs
+ }
+ const QrcodeVue: any
+ export default QrcodeVue
}
// 全局变量声明
diff --git a/src/hooks/core/useAppMode.ts b/src/hooks/core/useAppMode.ts
index c39cd9e..334a61e 100644
--- a/src/hooks/core/useAppMode.ts
+++ b/src/hooks/core/useAppMode.ts
@@ -18,28 +18,28 @@
import { computed } from 'vue'
export function useAppMode() {
- // 获取访问模式配置
- const accessMode = import.meta.env.VITE_ACCESS_MODE
+ // 获取访问模式配置
+ const accessMode = import.meta.env.VITE_ACCESS_MODE
- /**
- * 是否为前端控制模式
- * 前端模式:权限由前端路由配置控制
- */
- const isFrontendMode = computed(() => accessMode === 'frontend')
- /**
- * 是否为后端控制模式
- * 后端模式:权限由后端接口返回的菜单数据控制
- */
- const isBackendMode = computed(() => accessMode === 'backend')
+ /**
+ * 是否为前端控制模式
+ * 前端模式:权限由前端路由配置控制
+ */
+ const isFrontendMode = computed(() => accessMode === 'frontend')
+ /**
+ * 是否为后端控制模式
+ * 后端模式:权限由后端接口返回的菜单数据控制
+ */
+ const isBackendMode = computed(() => accessMode === 'backend')
- /**
- * 当前应用模式
- */
- const currentMode = computed(() => accessMode)
+ /**
+ * 当前应用模式
+ */
+ const currentMode = computed(() => accessMode)
- return {
- isFrontendMode,
- isBackendMode,
- currentMode
- }
+ return {
+ isFrontendMode,
+ isBackendMode,
+ currentMode
+ }
}
diff --git a/src/hooks/core/useAuth.ts b/src/hooks/core/useAuth.ts
index 283b859..5b00b24 100644
--- a/src/hooks/core/useAuth.ts
+++ b/src/hooks/core/useAuth.ts
@@ -41,34 +41,34 @@ type AuthItem = NonNullable[number]
const userStore = useUserStore()
export const useAuth = () => {
- const route = useRoute()
- const { isFrontendMode } = useAppMode()
- const { info } = storeToRefs(userStore)
+ const route = useRoute()
+ const { isFrontendMode } = useAppMode()
+ const { info } = storeToRefs(userStore)
- // 前端按钮权限(例如:['add', 'edit'])
- const frontendAuthList = info.value?.buttons ?? []
+ // 前端按钮权限(例如:['add', 'edit'])
+ const frontendAuthList = info.value?.buttons ?? []
- // 后端路由 meta 配置的权限列表(例如:[{ authMark: 'add' }])
- const backendAuthList: AuthItem[] = Array.isArray(route.meta.authList)
- ? (route.meta.authList as AuthItem[])
- : []
+ // 后端路由 meta 配置的权限列表(例如:[{ authMark: 'add' }])
+ const backendAuthList: AuthItem[] = Array.isArray(route.meta.authList)
+ ? (route.meta.authList as AuthItem[])
+ : []
- /**
- * 检查是否拥有某权限标识(前后端模式通用)
- * @param auth 权限标识
- * @returns 是否有权限
- */
- const hasAuth = (auth: string): boolean => {
- // 前端模式
- if (isFrontendMode.value) {
- return frontendAuthList.includes(auth)
- }
+ /**
+ * 检查是否拥有某权限标识(前后端模式通用)
+ * @param auth 权限标识
+ * @returns 是否有权限
+ */
+ const hasAuth = (auth: string): boolean => {
+ // 前端模式
+ if (isFrontendMode.value) {
+ return frontendAuthList.includes(auth)
+ }
- // 后端模式
- return backendAuthList.some((item) => item?.authMark === auth)
- }
+ // 后端模式
+ return backendAuthList.some((item) => item?.authMark === auth)
+ }
- return {
- hasAuth
- }
+ return {
+ hasAuth
+ }
}
diff --git a/src/hooks/core/useCeremony.ts b/src/hooks/core/useCeremony.ts
index ead2630..e9c41dc 100644
--- a/src/hooks/core/useCeremony.ts
+++ b/src/hooks/core/useCeremony.ts
@@ -51,14 +51,14 @@ import { festivalConfigList } from '@/config/modules/festival'
* 节日庆祝配置常量
*/
const FESTIVAL_CONFIG = {
- /** 初始延迟(毫秒) */
- INITIAL_DELAY: 300,
- /** 烟花播放间隔(毫秒) */
- FIREWORK_INTERVAL: 1000,
- /** 文本显示延迟(毫秒) */
- TEXT_DELAY: 2000,
- /** 默认烟花播放次数 */
- DEFAULT_FIREWORKS_COUNT: 3
+ /** 初始延迟(毫秒) */
+ INITIAL_DELAY: 300,
+ /** 烟花播放间隔(毫秒) */
+ FIREWORK_INTERVAL: 1000,
+ /** 文本显示延迟(毫秒) */
+ TEXT_DELAY: 2000,
+ /** 默认烟花播放次数 */
+ DEFAULT_FIREWORKS_COUNT: 3
} as const
/**
@@ -66,119 +66,121 @@ const FESTIVAL_CONFIG = {
* 提供节日烟花效果和祝福文本展示
*/
export function useCeremony() {
- const settingStore = useSettingStore()
- const { holidayFireworksLoaded, isShowFireworks } = storeToRefs(settingStore)
+ const settingStore = useSettingStore()
+ const { holidayFireworksLoaded, isShowFireworks } = storeToRefs(settingStore)
- let fireworksInterval: { pause: () => void } | null = null
+ let fireworksInterval: { pause: () => void } | null = null
- /**
- * 检查日期是否在节日范围内
- * @param currentDate 当前日期
- * @param festivalDate 节日开始日期
- * @param festivalEndDate 节日结束日期(可选)
- */
- const isDateInRange = (
- currentDate: string,
- festivalDate: string,
- festivalEndDate?: string
- ): boolean => {
- if (!festivalEndDate) {
- // 单日节日
- return currentDate === festivalDate
- }
+ /**
+ * 检查日期是否在节日范围内
+ * @param currentDate 当前日期
+ * @param festivalDate 节日开始日期
+ * @param festivalEndDate 节日结束日期(可选)
+ */
+ const isDateInRange = (
+ currentDate: string,
+ festivalDate: string,
+ festivalEndDate?: string
+ ): boolean => {
+ if (!festivalEndDate) {
+ // 单日节日
+ return currentDate === festivalDate
+ }
- // 跨日期节日
- const current = new Date(currentDate)
- const start = new Date(festivalDate)
- const end = new Date(festivalEndDate)
+ // 跨日期节日
+ const current = new Date(currentDate)
+ const start = new Date(festivalDate)
+ const end = new Date(festivalEndDate)
- return current >= start && current <= end
- }
+ return current >= start && current <= end
+ }
- /**
- * 获取当前日期对应的节日数据
- */
- const currentFestivalData = computed(() => {
- const currentDate = useDateFormat(new Date(), 'YYYY-MM-DD').value
- return festivalConfigList.find((item) => isDateInRange(currentDate, item.date, item.endDate))
- })
+ /**
+ * 获取当前日期对应的节日数据
+ */
+ const currentFestivalData = computed(() => {
+ const currentDate = useDateFormat(new Date(), 'YYYY-MM-DD').value
+ return festivalConfigList.find((item) =>
+ isDateInRange(currentDate, item.date, item.endDate)
+ )
+ })
- /**
- * 更新节日日期到 store
- */
- const updateFestivalDate = () => {
- settingStore.setFestivalDate(currentFestivalData.value?.date || '')
- }
+ /**
+ * 更新节日日期到 store
+ */
+ const updateFestivalDate = () => {
+ settingStore.setFestivalDate(currentFestivalData.value?.date || '')
+ }
- /**
- * 触发烟花效果
- */
- const triggerFirework = () => {
- mittBus.emit('triggerFireworks', currentFestivalData.value?.image)
- }
+ /**
+ * 触发烟花效果
+ */
+ const triggerFirework = () => {
+ mittBus.emit('triggerFireworks', currentFestivalData.value?.image)
+ }
- /**
- * 完成烟花效果后显示文本
- */
- const showFestivalText = () => {
- settingStore.setholidayFireworksLoaded(true)
+ /**
+ * 完成烟花效果后显示文本
+ */
+ const showFestivalText = () => {
+ settingStore.setholidayFireworksLoaded(true)
- useTimeoutFn(() => {
- settingStore.setShowFestivalText(true)
- updateFestivalDate()
- }, FESTIVAL_CONFIG.TEXT_DELAY)
- }
+ useTimeoutFn(() => {
+ settingStore.setShowFestivalText(true)
+ updateFestivalDate()
+ }, FESTIVAL_CONFIG.TEXT_DELAY)
+ }
- /**
- * 启动烟花循环
- */
- const startFireworksLoop = () => {
- let playedCount = 0
- // 使用节日配置的播放次数,如果没有则使用默认值
- const count = currentFestivalData.value?.count ?? FESTIVAL_CONFIG.DEFAULT_FIREWORKS_COUNT
+ /**
+ * 启动烟花循环
+ */
+ const startFireworksLoop = () => {
+ let playedCount = 0
+ // 使用节日配置的播放次数,如果没有则使用默认值
+ const count = currentFestivalData.value?.count ?? FESTIVAL_CONFIG.DEFAULT_FIREWORKS_COUNT
- const { pause } = useIntervalFn(() => {
- triggerFirework()
- playedCount++
+ const { pause } = useIntervalFn(() => {
+ triggerFirework()
+ playedCount++
- if (playedCount >= count) {
- pause()
- showFestivalText()
- }
- }, FESTIVAL_CONFIG.FIREWORK_INTERVAL)
+ if (playedCount >= count) {
+ pause()
+ showFestivalText()
+ }
+ }, FESTIVAL_CONFIG.FIREWORK_INTERVAL)
- fireworksInterval = { pause }
- }
+ fireworksInterval = { pause }
+ }
- /**
- * 开启节日庆祝
- */
- const openFestival = () => {
- if (!currentFestivalData.value || !isShowFireworks.value) {
- return
- }
+ /**
+ * 开启节日庆祝
+ */
+ const openFestival = () => {
+ if (!currentFestivalData.value || !isShowFireworks.value) {
+ return
+ }
- const { start } = useTimeoutFn(startFireworksLoop, FESTIVAL_CONFIG.INITIAL_DELAY)
- start()
- }
+ const { start } = useTimeoutFn(startFireworksLoop, FESTIVAL_CONFIG.INITIAL_DELAY)
+ start()
+ }
- /**
- * 清理烟花效果
- */
- const cleanup = () => {
- if (fireworksInterval) {
- fireworksInterval.pause()
- fireworksInterval = null
- }
- settingStore.setShowFestivalText(false)
- updateFestivalDate()
- }
+ /**
+ * 清理烟花效果
+ */
+ const cleanup = () => {
+ if (fireworksInterval) {
+ fireworksInterval.pause()
+ fireworksInterval = null
+ }
+ settingStore.setShowFestivalText(false)
+ updateFestivalDate()
+ }
- return {
- openFestival,
- cleanup,
- holidayFireworksLoaded,
- currentFestivalData,
- isShowFireworks
- }
+ return {
+ openFestival,
+ cleanup,
+ holidayFireworksLoaded,
+ currentFestivalData,
+ isShowFireworks
+ }
}
diff --git a/src/hooks/core/useChart.ts b/src/hooks/core/useChart.ts
index 29ba1d1..dd10813 100644
--- a/src/hooks/core/useChart.ts
+++ b/src/hooks/core/useChart.ts
@@ -57,24 +57,24 @@ import type { BaseChartProps, ChartThemeConfig, UseChartOptions } from '@/types/
// 图表主题配置
export const useChartOps = (): ChartThemeConfig => ({
- /** */
- chartHeight: '16rem',
- /** 字体大小 */
- fontSize: 13,
- /** 字体颜色 */
- fontColor: '#999',
- /** 主题颜色 */
- themeColor: getCssVar('--el-color-primary-light-1'),
- /** 颜色组 */
- colors: [
- getCssVar('--el-color-primary-light-1'),
- '#4ABEFF',
- '#EDF2FF',
- '#14DEBA',
- '#FFAF20',
- '#FA8A6C',
- '#FFAF20'
- ]
+ /** */
+ chartHeight: '16rem',
+ /** 字体大小 */
+ fontSize: 13,
+ /** 字体颜色 */
+ fontColor: '#999',
+ /** 主题颜色 */
+ themeColor: getCssVar('--el-color-primary-light-1'),
+ /** 颜色组 */
+ colors: [
+ getCssVar('--el-color-primary-light-1'),
+ '#4ABEFF',
+ '#EDF2FF',
+ '#14DEBA',
+ '#FFAF20',
+ '#FA8A6C',
+ '#FFAF20'
+ ]
})
// 常量定义
@@ -83,377 +83,377 @@ const MENU_RESIZE_DELAYS = [50, 100, 200] as const
const RESIZE_DEBOUNCE_DELAY = 100
export function useChart(options: UseChartOptions = {}) {
- const { initOptions, initDelay = 0, threshold = 0.1, autoTheme = true } = options
+ const { initOptions, initDelay = 0, threshold = 0.1, autoTheme = true } = options
- const settingStore = useSettingStore()
- const { isDark, menuOpen, menuType } = storeToRefs(settingStore)
+ const settingStore = useSettingStore()
+ const { isDark, menuOpen, menuType } = storeToRefs(settingStore)
- const chartRef = ref()
- let chart: echarts.ECharts | null = null
- let intersectionObserver: IntersectionObserver | null = null
- let pendingOptions: EChartsOption | null = null
- let resizeTimeoutId: number | null = null
- let resizeFrameId: number | null = null
- let isDestroyed = false
- let emptyStateDiv: HTMLElement | null = null
+ const chartRef = ref()
+ let chart: echarts.ECharts | null = null
+ let intersectionObserver: IntersectionObserver | null = null
+ let pendingOptions: EChartsOption | null = null
+ let resizeTimeoutId: number | null = null
+ let resizeFrameId: number | null = null
+ let isDestroyed = false
+ let emptyStateDiv: HTMLElement | null = null
- // 清理定时器的统一方法
- const clearTimers = () => {
- if (resizeTimeoutId) {
- clearTimeout(resizeTimeoutId)
- resizeTimeoutId = null
- }
- if (resizeFrameId) {
- cancelAnimationFrame(resizeFrameId)
- resizeFrameId = null
- }
- }
+ // 清理定时器的统一方法
+ const clearTimers = () => {
+ if (resizeTimeoutId) {
+ clearTimeout(resizeTimeoutId)
+ resizeTimeoutId = null
+ }
+ if (resizeFrameId) {
+ cancelAnimationFrame(resizeFrameId)
+ resizeFrameId = null
+ }
+ }
- // 使用 requestAnimationFrame 优化 resize 处理
- const requestAnimationResize = () => {
- if (resizeFrameId) {
- cancelAnimationFrame(resizeFrameId)
- }
- resizeFrameId = requestAnimationFrame(() => {
- handleResize()
- resizeFrameId = null
- })
- }
+ // 使用 requestAnimationFrame 优化 resize 处理
+ const requestAnimationResize = () => {
+ if (resizeFrameId) {
+ cancelAnimationFrame(resizeFrameId)
+ }
+ resizeFrameId = requestAnimationFrame(() => {
+ handleResize()
+ resizeFrameId = null
+ })
+ }
- // 防抖的resize处理(用于窗口resize事件)
- const debouncedResize = () => {
- if (resizeTimeoutId) {
- clearTimeout(resizeTimeoutId)
- }
- resizeTimeoutId = window.setTimeout(() => {
- requestAnimationResize()
- resizeTimeoutId = null
- }, RESIZE_DEBOUNCE_DELAY)
- }
+ // 防抖的resize处理(用于窗口resize事件)
+ const debouncedResize = () => {
+ if (resizeTimeoutId) {
+ clearTimeout(resizeTimeoutId)
+ }
+ resizeTimeoutId = window.setTimeout(() => {
+ requestAnimationResize()
+ resizeTimeoutId = null
+ }, RESIZE_DEBOUNCE_DELAY)
+ }
- // 多延迟resize处理 - 统一方法
- const multiDelayResize = (delays: readonly number[]) => {
- // 立即调用一次,快速响应
- nextTick(requestAnimationResize)
+ // 多延迟resize处理 - 统一方法
+ const multiDelayResize = (delays: readonly number[]) => {
+ // 立即调用一次,快速响应
+ nextTick(requestAnimationResize)
- // 使用延迟时间,确保图表正确适应变化
- delays.forEach((delay) => {
- setTimeout(requestAnimationResize, delay)
- })
- }
+ // 使用延迟时间,确保图表正确适应变化
+ delays.forEach((delay) => {
+ setTimeout(requestAnimationResize, delay)
+ })
+ }
- // 收缩菜单时,重新计算图表大小(仅在图表存在时监听)
- let menuOpenStopHandle: (() => void) | null = null
- let menuTypeStopHandle: (() => void) | null = null
+ // 收缩菜单时,重新计算图表大小(仅在图表存在时监听)
+ let menuOpenStopHandle: (() => void) | null = null
+ let menuTypeStopHandle: (() => void) | null = null
- const setupMenuWatchers = () => {
- menuOpenStopHandle = watch(menuOpen, () => multiDelayResize(RESIZE_DELAYS))
- menuTypeStopHandle = watch(menuType, () => {
- nextTick(requestAnimationResize)
- setTimeout(() => multiDelayResize(MENU_RESIZE_DELAYS), 0)
- })
- }
+ const setupMenuWatchers = () => {
+ menuOpenStopHandle = watch(menuOpen, () => multiDelayResize(RESIZE_DELAYS))
+ menuTypeStopHandle = watch(menuType, () => {
+ nextTick(requestAnimationResize)
+ setTimeout(() => multiDelayResize(MENU_RESIZE_DELAYS), 0)
+ })
+ }
- const cleanupMenuWatchers = () => {
- menuOpenStopHandle?.()
- menuTypeStopHandle?.()
- menuOpenStopHandle = null
- menuTypeStopHandle = null
- }
+ const cleanupMenuWatchers = () => {
+ menuOpenStopHandle?.()
+ menuTypeStopHandle?.()
+ menuOpenStopHandle = null
+ menuTypeStopHandle = null
+ }
- // 主题变化时重新设置图表选项
- let themeStopHandle: (() => void) | null = null
+ // 主题变化时重新设置图表选项
+ let themeStopHandle: (() => void) | null = null
- const setupThemeWatcher = () => {
- if (autoTheme) {
- themeStopHandle = watch(isDark, () => {
- // 更新空状态样式
- emptyStateManager.updateStyle()
+ const setupThemeWatcher = () => {
+ if (autoTheme) {
+ themeStopHandle = watch(isDark, () => {
+ // 更新空状态样式
+ emptyStateManager.updateStyle()
- if (chart && !isDestroyed) {
- // 使用 requestAnimationFrame 优化主题更新
- requestAnimationFrame(() => {
- if (chart && !isDestroyed) {
- const currentOptions = chart.getOption()
- if (currentOptions) {
- updateChart(currentOptions as EChartsOption)
- }
- }
- })
- }
- })
- }
- }
+ if (chart && !isDestroyed) {
+ // 使用 requestAnimationFrame 优化主题更新
+ requestAnimationFrame(() => {
+ if (chart && !isDestroyed) {
+ const currentOptions = chart.getOption()
+ if (currentOptions) {
+ updateChart(currentOptions as EChartsOption)
+ }
+ }
+ })
+ }
+ })
+ }
+ }
- const cleanupThemeWatcher = () => {
- themeStopHandle?.()
- themeStopHandle = null
- }
+ const cleanupThemeWatcher = () => {
+ themeStopHandle?.()
+ themeStopHandle = null
+ }
- // 样式生成器 - 统一的样式配置
- const createLineStyle = (color: string, width = 1, type?: 'solid' | 'dashed') => ({
- color,
- width,
- ...(type && { type })
- })
+ // 样式生成器 - 统一的样式配置
+ const createLineStyle = (color: string, width = 1, type?: 'solid' | 'dashed') => ({
+ color,
+ width,
+ ...(type && { type })
+ })
- // 缓存样式配置以减少重复计算
- const styleCache = {
- axisLine: null as any,
- splitLine: null as any,
- axisLabel: null as any,
- lastDarkValue: isDark.value
- }
+ // 缓存样式配置以减少重复计算
+ const styleCache = {
+ axisLine: null as any,
+ splitLine: null as any,
+ axisLabel: null as any,
+ lastDarkValue: isDark.value
+ }
- const clearStyleCache = () => {
- styleCache.axisLine = null
- styleCache.splitLine = null
- styleCache.axisLabel = null
- styleCache.lastDarkValue = isDark.value
- }
+ const clearStyleCache = () => {
+ styleCache.axisLine = null
+ styleCache.splitLine = null
+ styleCache.axisLabel = null
+ styleCache.lastDarkValue = isDark.value
+ }
- // 坐标轴线样式
- const getAxisLineStyle = (show: boolean = true) => {
- if (styleCache.lastDarkValue !== isDark.value) {
- clearStyleCache()
- }
- if (!styleCache.axisLine) {
- styleCache.axisLine = {
- show,
- lineStyle: createLineStyle(isDark.value ? '#444' : '#EDEDED')
- }
- }
- return styleCache.axisLine
- }
+ // 坐标轴线样式
+ const getAxisLineStyle = (show: boolean = true) => {
+ if (styleCache.lastDarkValue !== isDark.value) {
+ clearStyleCache()
+ }
+ if (!styleCache.axisLine) {
+ styleCache.axisLine = {
+ show,
+ lineStyle: createLineStyle(isDark.value ? '#444' : '#EDEDED')
+ }
+ }
+ return styleCache.axisLine
+ }
- // 分割线样式
- const getSplitLineStyle = (show: boolean = true) => {
- if (styleCache.lastDarkValue !== isDark.value) {
- clearStyleCache()
- }
- if (!styleCache.splitLine) {
- styleCache.splitLine = {
- show,
- lineStyle: createLineStyle(isDark.value ? '#444' : '#EDEDED', 1, 'dashed')
- }
- }
- return styleCache.splitLine
- }
+ // 分割线样式
+ const getSplitLineStyle = (show: boolean = true) => {
+ if (styleCache.lastDarkValue !== isDark.value) {
+ clearStyleCache()
+ }
+ if (!styleCache.splitLine) {
+ styleCache.splitLine = {
+ show,
+ lineStyle: createLineStyle(isDark.value ? '#444' : '#EDEDED', 1, 'dashed')
+ }
+ }
+ return styleCache.splitLine
+ }
- // 坐标轴标签样式
- const getAxisLabelStyle = (show: boolean = true) => {
- if (styleCache.lastDarkValue !== isDark.value) {
- clearStyleCache()
- }
- if (!styleCache.axisLabel) {
- const { fontColor, fontSize } = useChartOps()
- styleCache.axisLabel = {
- show,
- color: fontColor,
- fontSize
- }
- }
- return styleCache.axisLabel
- }
+ // 坐标轴标签样式
+ const getAxisLabelStyle = (show: boolean = true) => {
+ if (styleCache.lastDarkValue !== isDark.value) {
+ clearStyleCache()
+ }
+ if (!styleCache.axisLabel) {
+ const { fontColor, fontSize } = useChartOps()
+ styleCache.axisLabel = {
+ show,
+ color: fontColor,
+ fontSize
+ }
+ }
+ return styleCache.axisLabel
+ }
- // 坐标轴刻度样式(静态配置,无需缓存)
- const getAxisTickStyle = () => ({
- show: false
- })
+ // 坐标轴刻度样式(静态配置,无需缓存)
+ const getAxisTickStyle = () => ({
+ show: false
+ })
- // 获取动画配置
- const getAnimationConfig = (animationDelay: number = 50, animationDuration: number = 1500) => ({
- animationDelay: (idx: number) => idx * animationDelay + 200,
- animationDuration: (idx: number) => animationDuration - idx * 50,
- animationEasing: 'quarticOut' as const
- })
+ // 获取动画配置
+ const getAnimationConfig = (animationDelay: number = 50, animationDuration: number = 1500) => ({
+ animationDelay: (idx: number) => idx * animationDelay + 200,
+ animationDuration: (idx: number) => animationDuration - idx * 50,
+ animationEasing: 'quarticOut' as const
+ })
- // 获取统一的 tooltip 配置
- const getTooltipStyle = (trigger: 'item' | 'axis' = 'axis', customOptions: any = {}) => ({
- trigger,
- backgroundColor: isDark.value ? 'rgba(0, 0, 0, 0.8)' : 'rgba(255, 255, 255, 0.9)',
- borderColor: isDark.value ? '#333' : '#ddd',
- borderWidth: 1,
- textStyle: {
- color: isDark.value ? '#fff' : '#333'
- },
- ...customOptions
- })
+ // 获取统一的 tooltip 配置
+ const getTooltipStyle = (trigger: 'item' | 'axis' = 'axis', customOptions: any = {}) => ({
+ trigger,
+ backgroundColor: isDark.value ? 'rgba(0, 0, 0, 0.8)' : 'rgba(255, 255, 255, 0.9)',
+ borderColor: isDark.value ? '#333' : '#ddd',
+ borderWidth: 1,
+ textStyle: {
+ color: isDark.value ? '#fff' : '#333'
+ },
+ ...customOptions
+ })
- // 获取统一的图例配置
- const getLegendStyle = (
- position: 'bottom' | 'top' | 'left' | 'right' = 'bottom',
- customOptions: any = {}
- ) => {
- const baseConfig = {
- textStyle: {
- color: isDark.value ? '#fff' : '#333'
- },
- itemWidth: 12,
- itemHeight: 12,
- itemGap: 20,
- ...customOptions
- }
+ // 获取统一的图例配置
+ const getLegendStyle = (
+ position: 'bottom' | 'top' | 'left' | 'right' = 'bottom',
+ customOptions: any = {}
+ ) => {
+ const baseConfig = {
+ textStyle: {
+ color: isDark.value ? '#fff' : '#333'
+ },
+ itemWidth: 12,
+ itemHeight: 12,
+ itemGap: 20,
+ ...customOptions
+ }
- // 根据位置设置不同的配置
- switch (position) {
- case 'bottom':
- return {
- ...baseConfig,
- bottom: 0,
- left: 'center',
- orient: 'horizontal',
- icon: 'roundRect'
- }
- case 'top':
- return {
- ...baseConfig,
- top: 0,
- left: 'center',
- orient: 'horizontal',
- icon: 'roundRect'
- }
- case 'left':
- return {
- ...baseConfig,
- left: 0,
- top: 'center',
- orient: 'vertical',
- icon: 'roundRect'
- }
- case 'right':
- return {
- ...baseConfig,
- right: 0,
- top: 'center',
- orient: 'vertical',
- icon: 'roundRect'
- }
- default:
- return baseConfig
- }
- }
+ // 根据位置设置不同的配置
+ switch (position) {
+ case 'bottom':
+ return {
+ ...baseConfig,
+ bottom: 0,
+ left: 'center',
+ orient: 'horizontal',
+ icon: 'roundRect'
+ }
+ case 'top':
+ return {
+ ...baseConfig,
+ top: 0,
+ left: 'center',
+ orient: 'horizontal',
+ icon: 'roundRect'
+ }
+ case 'left':
+ return {
+ ...baseConfig,
+ left: 0,
+ top: 'center',
+ orient: 'vertical',
+ icon: 'roundRect'
+ }
+ case 'right':
+ return {
+ ...baseConfig,
+ right: 0,
+ top: 'center',
+ orient: 'vertical',
+ icon: 'roundRect'
+ }
+ default:
+ return baseConfig
+ }
+ }
- // 根据图例位置计算 grid 配置
- const getGridWithLegend = (
- showLegend: boolean,
- legendPosition: 'bottom' | 'top' | 'left' | 'right' = 'bottom',
- baseGrid: any = {}
- ) => {
- const defaultGrid = {
- top: 15,
- right: 15,
- bottom: 8,
- left: 0,
- containLabel: true,
- ...baseGrid
- }
+ // 根据图例位置计算 grid 配置
+ const getGridWithLegend = (
+ showLegend: boolean,
+ legendPosition: 'bottom' | 'top' | 'left' | 'right' = 'bottom',
+ baseGrid: any = {}
+ ) => {
+ const defaultGrid = {
+ top: 15,
+ right: 15,
+ bottom: 8,
+ left: 0,
+ containLabel: true,
+ ...baseGrid
+ }
- if (!showLegend) {
- return defaultGrid
- }
+ if (!showLegend) {
+ return defaultGrid
+ }
- // 根据图例位置调整 grid
- switch (legendPosition) {
- case 'bottom':
- return {
- ...defaultGrid,
- bottom: 40
- }
- case 'top':
- return {
- ...defaultGrid,
- top: 40
- }
- case 'left':
- return {
- ...defaultGrid,
- left: 120
- }
- case 'right':
- return {
- ...defaultGrid,
- right: 120
- }
- default:
- return defaultGrid
- }
- }
+ // 根据图例位置调整 grid
+ switch (legendPosition) {
+ case 'bottom':
+ return {
+ ...defaultGrid,
+ bottom: 40
+ }
+ case 'top':
+ return {
+ ...defaultGrid,
+ top: 40
+ }
+ case 'left':
+ return {
+ ...defaultGrid,
+ left: 120
+ }
+ case 'right':
+ return {
+ ...defaultGrid,
+ right: 120
+ }
+ default:
+ return defaultGrid
+ }
+ }
- // 创建IntersectionObserver
- const createIntersectionObserver = () => {
- if (intersectionObserver || !chartRef.value) return
+ // 创建IntersectionObserver
+ const createIntersectionObserver = () => {
+ if (intersectionObserver || !chartRef.value) return
- intersectionObserver = new IntersectionObserver(
- (entries) => {
- entries.forEach((entry) => {
- if (entry.isIntersecting && pendingOptions && !isDestroyed) {
- // 使用 requestAnimationFrame 确保在下一帧初始化图表
- requestAnimationFrame(() => {
- if (!isDestroyed && pendingOptions) {
- try {
- // 元素变为可见,初始化图表
- if (!chart) {
- chart = echarts.init(entry.target as HTMLElement)
- }
+ intersectionObserver = new IntersectionObserver(
+ (entries) => {
+ entries.forEach((entry) => {
+ if (entry.isIntersecting && pendingOptions && !isDestroyed) {
+ // 使用 requestAnimationFrame 确保在下一帧初始化图表
+ requestAnimationFrame(() => {
+ if (!isDestroyed && pendingOptions) {
+ try {
+ // 元素变为可见,初始化图表
+ if (!chart) {
+ chart = echarts.init(entry.target as HTMLElement)
+ }
- // 触发自定义事件,让组件处理动画逻辑
- const event = new CustomEvent('chartVisible', {
- detail: { options: pendingOptions }
- })
- entry.target.dispatchEvent(event)
+ // 触发自定义事件,让组件处理动画逻辑
+ const event = new CustomEvent('chartVisible', {
+ detail: { options: pendingOptions }
+ })
+ entry.target.dispatchEvent(event)
- pendingOptions = null
- cleanupIntersectionObserver()
- } catch (error) {
- console.error('图表初始化失败:', error)
- }
- }
- })
- }
- })
- },
- { threshold }
- )
+ pendingOptions = null
+ cleanupIntersectionObserver()
+ } catch (error) {
+ console.error('图表初始化失败:', error)
+ }
+ }
+ })
+ }
+ })
+ },
+ { threshold }
+ )
- intersectionObserver.observe(chartRef.value)
- }
+ intersectionObserver.observe(chartRef.value)
+ }
- // 清理IntersectionObserver
- const cleanupIntersectionObserver = () => {
- if (intersectionObserver) {
- intersectionObserver.disconnect()
- intersectionObserver = null
- }
- }
+ // 清理IntersectionObserver
+ const cleanupIntersectionObserver = () => {
+ if (intersectionObserver) {
+ intersectionObserver.disconnect()
+ intersectionObserver = null
+ }
+ }
- // 检查容器是否可见
- const isContainerVisible = (element: HTMLElement): boolean => {
- const rect = element.getBoundingClientRect()
- return rect.width > 0 && rect.height > 0 && rect.top < window.innerHeight && rect.bottom > 0
- }
+ // 检查容器是否可见
+ const isContainerVisible = (element: HTMLElement): boolean => {
+ const rect = element.getBoundingClientRect()
+ return rect.width > 0 && rect.height > 0 && rect.top < window.innerHeight && rect.bottom > 0
+ }
- // 图表初始化核心逻辑
- const performChartInit = (options: EChartsOption) => {
- if (!chart && chartRef.value && !isDestroyed) {
- chart = echarts.init(chartRef.value)
- // 图表创建后立即设置监听器
- setupMenuWatchers()
- setupThemeWatcher()
- }
- if (chart && !isDestroyed) {
- chart.setOption(options)
- pendingOptions = null
- }
- }
+ // 图表初始化核心逻辑
+ const performChartInit = (options: EChartsOption) => {
+ if (!chart && chartRef.value && !isDestroyed) {
+ chart = echarts.init(chartRef.value)
+ // 图表创建后立即设置监听器
+ setupMenuWatchers()
+ setupThemeWatcher()
+ }
+ if (chart && !isDestroyed) {
+ chart.setOption(options)
+ pendingOptions = null
+ }
+ }
- // 空状态管理器
- const emptyStateManager = {
- create: () => {
- if (!chartRef.value || emptyStateDiv) return
+ // 空状态管理器
+ const emptyStateManager = {
+ create: () => {
+ if (!chartRef.value || emptyStateDiv) return
- emptyStateDiv = document.createElement('div')
- emptyStateDiv.style.cssText = `
+ emptyStateDiv = document.createElement('div')
+ emptyStateDiv.style.cssText = `
position: absolute;
top: 0;
left: 0;
@@ -468,278 +468,278 @@ export function useChart(options: UseChartOptions = {}) {
background: transparent;
z-index: 10;
`
- emptyStateDiv.innerHTML = `暂无数据`
+ emptyStateDiv.innerHTML = `暂无数据`
- // 确保父容器有相对定位
- if (
- chartRef.value.style.position !== 'relative' &&
- chartRef.value.style.position !== 'absolute'
- ) {
- chartRef.value.style.position = 'relative'
- }
+ // 确保父容器有相对定位
+ if (
+ chartRef.value.style.position !== 'relative' &&
+ chartRef.value.style.position !== 'absolute'
+ ) {
+ chartRef.value.style.position = 'relative'
+ }
- chartRef.value.appendChild(emptyStateDiv)
- },
+ chartRef.value.appendChild(emptyStateDiv)
+ },
- remove: () => {
- if (emptyStateDiv && chartRef.value) {
- chartRef.value.removeChild(emptyStateDiv)
- emptyStateDiv = null
- }
- },
+ remove: () => {
+ if (emptyStateDiv && chartRef.value) {
+ chartRef.value.removeChild(emptyStateDiv)
+ emptyStateDiv = null
+ }
+ },
- updateStyle: () => {
- if (emptyStateDiv) {
- emptyStateDiv.style.color = isDark.value ? '#666' : '#999'
- }
- }
- }
+ updateStyle: () => {
+ if (emptyStateDiv) {
+ emptyStateDiv.style.color = isDark.value ? '#666' : '#999'
+ }
+ }
+ }
- // 初始化图表
- const initChart = (options: EChartsOption = {}, isEmpty: boolean = false) => {
- if (!chartRef.value || isDestroyed) return
+ // 初始化图表
+ const initChart = (options: EChartsOption = {}, isEmpty: boolean = false) => {
+ if (!chartRef.value || isDestroyed) return
- const mergedOptions = { ...initOptions, ...options }
+ const mergedOptions = { ...initOptions, ...options }
- try {
- if (isEmpty) {
- // 处理空数据情况 - 显示自定义空状态div
- if (chart) {
- chart.clear()
- }
- emptyStateManager.create()
- return
- } else {
- // 有数据时移除空状态div
- emptyStateManager.remove()
- }
+ try {
+ if (isEmpty) {
+ // 处理空数据情况 - 显示自定义空状态div
+ if (chart) {
+ chart.clear()
+ }
+ emptyStateManager.create()
+ return
+ } else {
+ // 有数据时移除空状态div
+ emptyStateManager.remove()
+ }
- if (isContainerVisible(chartRef.value)) {
- // 容器可见,正常初始化
- if (initDelay > 0) {
- setTimeout(() => performChartInit(mergedOptions), initDelay)
- } else {
- performChartInit(mergedOptions)
- }
- } else {
- // 容器不可见,保存选项并设置监听器
- pendingOptions = mergedOptions
- createIntersectionObserver()
- }
- } catch (error) {
- console.error('图表初始化失败:', error)
- }
- }
+ if (isContainerVisible(chartRef.value)) {
+ // 容器可见,正常初始化
+ if (initDelay > 0) {
+ setTimeout(() => performChartInit(mergedOptions), initDelay)
+ } else {
+ performChartInit(mergedOptions)
+ }
+ } else {
+ // 容器不可见,保存选项并设置监听器
+ pendingOptions = mergedOptions
+ createIntersectionObserver()
+ }
+ } catch (error) {
+ console.error('图表初始化失败:', error)
+ }
+ }
- // 更新图表
- const updateChart = (options: EChartsOption) => {
- if (isDestroyed) return
+ // 更新图表
+ const updateChart = (options: EChartsOption) => {
+ if (isDestroyed) return
- try {
- if (!chart) {
- // 如果图表不存在,先初始化
- initChart(options)
- return
- }
- chart.setOption(options)
- } catch (error) {
- console.error('图表更新失败:', error)
- }
- }
+ try {
+ if (!chart) {
+ // 如果图表不存在,先初始化
+ initChart(options)
+ return
+ }
+ chart.setOption(options)
+ } catch (error) {
+ console.error('图表更新失败:', error)
+ }
+ }
- // 处理窗口大小变化
- const handleResize = () => {
- if (chart && !isDestroyed) {
- try {
- chart.resize()
- } catch (error) {
- console.error('图表resize失败:', error)
- }
- }
- }
+ // 处理窗口大小变化
+ const handleResize = () => {
+ if (chart && !isDestroyed) {
+ try {
+ chart.resize()
+ } catch (error) {
+ console.error('图表resize失败:', error)
+ }
+ }
+ }
- // 销毁图表
- const destroyChart = () => {
- isDestroyed = true
+ // 销毁图表
+ const destroyChart = () => {
+ isDestroyed = true
- if (chart) {
- try {
- chart.dispose()
- } catch (error) {
- console.error('图表销毁失败:', error)
- } finally {
- chart = null
- }
- }
+ if (chart) {
+ try {
+ chart.dispose()
+ } catch (error) {
+ console.error('图表销毁失败:', error)
+ } finally {
+ chart = null
+ }
+ }
- // 清理所有监听器和资源
- cleanupMenuWatchers()
- cleanupThemeWatcher()
- emptyStateManager.remove()
- cleanupIntersectionObserver()
- clearTimers()
- clearStyleCache()
- pendingOptions = null
- }
+ // 清理所有监听器和资源
+ cleanupMenuWatchers()
+ cleanupThemeWatcher()
+ emptyStateManager.remove()
+ cleanupIntersectionObserver()
+ clearTimers()
+ clearStyleCache()
+ pendingOptions = null
+ }
- // 获取图表实例
- const getChartInstance = () => chart
+ // 获取图表实例
+ const getChartInstance = () => chart
- // 获取图表是否已初始化
- const isChartInitialized = () => chart !== null
+ // 获取图表是否已初始化
+ const isChartInitialized = () => chart !== null
- onMounted(() => {
- window.addEventListener('resize', debouncedResize)
- })
+ onMounted(() => {
+ window.addEventListener('resize', debouncedResize)
+ })
- onBeforeUnmount(() => {
- window.removeEventListener('resize', debouncedResize)
- })
+ onBeforeUnmount(() => {
+ window.removeEventListener('resize', debouncedResize)
+ })
- onUnmounted(() => {
- destroyChart()
- })
+ onUnmounted(() => {
+ destroyChart()
+ })
- return {
- isDark,
- chartRef,
- initChart,
- updateChart,
- handleResize,
- destroyChart,
- getChartInstance,
- isChartInitialized,
- emptyStateManager,
- getAxisLineStyle,
- getSplitLineStyle,
- getAxisLabelStyle,
- getAxisTickStyle,
- getAnimationConfig,
- getTooltipStyle,
- getLegendStyle,
- useChartOps,
- getGridWithLegend
- }
+ return {
+ isDark,
+ chartRef,
+ initChart,
+ updateChart,
+ handleResize,
+ destroyChart,
+ getChartInstance,
+ isChartInitialized,
+ emptyStateManager,
+ getAxisLineStyle,
+ getSplitLineStyle,
+ getAxisLabelStyle,
+ getAxisTickStyle,
+ getAnimationConfig,
+ getTooltipStyle,
+ getLegendStyle,
+ useChartOps,
+ getGridWithLegend
+ }
}
// 高级图表组件抽象
interface UseChartComponentOptions {
- /** Props响应式对象 */
- props: T
- /** 图表配置生成函数 */
- generateOptions: () => EChartsOption
- /** 空数据检查函数 */
- checkEmpty?: () => boolean
- /** 自定义监听的响应式数据 */
- watchSources?: (() => any)[]
- /** 自定义可视事件处理 */
- onVisible?: () => void
- /** useChart选项 */
- chartOptions?: UseChartOptions
+ /** Props响应式对象 */
+ props: T
+ /** 图表配置生成函数 */
+ generateOptions: () => EChartsOption
+ /** 空数据检查函数 */
+ checkEmpty?: () => boolean
+ /** 自定义监听的响应式数据 */
+ watchSources?: (() => any)[]
+ /** 自定义可视事件处理 */
+ onVisible?: () => void
+ /** useChart选项 */
+ chartOptions?: UseChartOptions
}
export function useChartComponent(options: UseChartComponentOptions) {
- const {
- props,
- generateOptions,
- checkEmpty,
- watchSources = [],
- onVisible,
- chartOptions = {}
- } = options
+ const {
+ props,
+ generateOptions,
+ checkEmpty,
+ watchSources = [],
+ onVisible,
+ chartOptions = {}
+ } = options
- const chart = useChart(chartOptions)
- const { chartRef, initChart, isDark, emptyStateManager } = chart
+ const chart = useChart(chartOptions)
+ const { chartRef, initChart, isDark, emptyStateManager } = chart
- // 检查是否为空数据
- const isEmpty = computed(() => {
- if (props.isEmpty) return true
- if (checkEmpty) return checkEmpty()
- return false
- })
+ // 检查是否为空数据
+ const isEmpty = computed(() => {
+ if (props.isEmpty) return true
+ if (checkEmpty) return checkEmpty()
+ return false
+ })
- // 更新图表
- const updateChart = () => {
- nextTick(() => {
- if (isEmpty.value) {
- // 处理空数据情况 - 显示自定义空状态div
- if (chart.getChartInstance()) {
- chart.getChartInstance()?.clear()
- }
- emptyStateManager.create()
- } else {
- // 有数据时移除空状态div并初始化图表
- emptyStateManager.remove()
- initChart(generateOptions())
- }
- })
- }
+ // 更新图表
+ const updateChart = () => {
+ nextTick(() => {
+ if (isEmpty.value) {
+ // 处理空数据情况 - 显示自定义空状态div
+ if (chart.getChartInstance()) {
+ chart.getChartInstance()?.clear()
+ }
+ emptyStateManager.create()
+ } else {
+ // 有数据时移除空状态div并初始化图表
+ emptyStateManager.remove()
+ initChart(generateOptions())
+ }
+ })
+ }
- // 处理图表进入可视区域时的逻辑
- const handleChartVisible = () => {
- if (onVisible) {
- onVisible()
- } else {
- updateChart()
- }
- }
+ // 处理图表进入可视区域时的逻辑
+ const handleChartVisible = () => {
+ if (onVisible) {
+ onVisible()
+ } else {
+ updateChart()
+ }
+ }
- // 存储监听器停止函数
- const stopHandles: (() => void)[] = []
+ // 存储监听器停止函数
+ const stopHandles: (() => void)[] = []
- // 设置数据监听
- const setupWatchers = () => {
- // 监听自定义数据源
- if (watchSources.length > 0) {
- const stopHandle = watch(watchSources, updateChart, { deep: true })
- stopHandles.push(stopHandle)
- }
+ // 设置数据监听
+ const setupWatchers = () => {
+ // 监听自定义数据源
+ if (watchSources.length > 0) {
+ const stopHandle = watch(watchSources, updateChart, { deep: true })
+ stopHandles.push(stopHandle)
+ }
- // 监听主题变化
- const themeStopHandle = watch(isDark, () => {
- emptyStateManager.updateStyle()
- updateChart()
- })
- stopHandles.push(themeStopHandle)
- }
+ // 监听主题变化
+ const themeStopHandle = watch(isDark, () => {
+ emptyStateManager.updateStyle()
+ updateChart()
+ })
+ stopHandles.push(themeStopHandle)
+ }
- // 清理所有监听器
- const cleanupWatchers = () => {
- stopHandles.forEach((stop) => stop())
- stopHandles.length = 0
- }
+ // 清理所有监听器
+ const cleanupWatchers = () => {
+ stopHandles.forEach((stop) => stop())
+ stopHandles.length = 0
+ }
- // 设置生命周期
- const setupLifecycle = () => {
- onMounted(() => {
- updateChart()
+ // 设置生命周期
+ const setupLifecycle = () => {
+ onMounted(() => {
+ updateChart()
- // 监听图表可见事件
- if (chartRef.value) {
- chartRef.value.addEventListener('chartVisible', handleChartVisible)
- }
- })
+ // 监听图表可见事件
+ if (chartRef.value) {
+ chartRef.value.addEventListener('chartVisible', handleChartVisible)
+ }
+ })
- onBeforeUnmount(() => {
- // 清理事件监听器
- if (chartRef.value) {
- chartRef.value.removeEventListener('chartVisible', handleChartVisible)
- }
- // 清理所有监听器
- cleanupWatchers()
- // 清理空状态div
- emptyStateManager.remove()
- })
- }
+ onBeforeUnmount(() => {
+ // 清理事件监听器
+ if (chartRef.value) {
+ chartRef.value.removeEventListener('chartVisible', handleChartVisible)
+ }
+ // 清理所有监听器
+ cleanupWatchers()
+ // 清理空状态div
+ emptyStateManager.remove()
+ })
+ }
- // 初始化
- setupWatchers()
- setupLifecycle()
+ // 初始化
+ setupWatchers()
+ setupLifecycle()
- return {
- ...chart,
- isEmpty,
- updateChart,
- handleChartVisible
- }
+ return {
+ ...chart,
+ isEmpty,
+ updateChart,
+ handleChartVisible
+ }
}
diff --git a/src/hooks/core/useCommon.ts b/src/hooks/core/useCommon.ts
index c936854..f06e42f 100644
--- a/src/hooks/core/useCommon.ts
+++ b/src/hooks/core/useCommon.ts
@@ -20,68 +20,68 @@ import { useMenuStore } from '@/store/modules/menu'
import { useSettingStore } from '@/store/modules/setting'
export function useCommon() {
- const menuStore = useMenuStore()
- const settingStore = useSettingStore()
+ const menuStore = useMenuStore()
+ const settingStore = useSettingStore()
- /**
- * 首页路径
- * 从菜单 store 中获取配置的首页路径
- */
- const homePath = computed(() => menuStore.getHomePath())
+ /**
+ * 首页路径
+ * 从菜单 store 中获取配置的首页路径
+ */
+ const homePath = computed(() => menuStore.getHomePath())
- /**
- * 刷新当前页面
- * 通过切换 setting store 中的 refresh 状态触发页面重新渲染
- */
- const refresh = () => {
- settingStore.reload()
- }
+ /**
+ * 刷新当前页面
+ * 通过切换 setting store 中的 refresh 状态触发页面重新渲染
+ */
+ const refresh = () => {
+ settingStore.reload()
+ }
- /**
- * 滚动到页面顶部
- * 查找主内容区域并将其滚动位置重置为顶部
- */
- const scrollToTop = () => {
- const scrollContainer = document.getElementById('app-main')
- if (scrollContainer) {
- scrollContainer.scrollTop = 0
- }
- }
+ /**
+ * 滚动到页面顶部
+ * 查找主内容区域并将其滚动位置重置为顶部
+ */
+ const scrollToTop = () => {
+ const scrollContainer = document.getElementById('app-main')
+ if (scrollContainer) {
+ scrollContainer.scrollTop = 0
+ }
+ }
- /**
- * 平滑滚动到页面顶部
- * 使用 smooth 行为实现平滑滚动效果
- */
- const smoothScrollToTop = () => {
- const scrollContainer = document.getElementById('app-main')
- if (scrollContainer) {
- scrollContainer.scrollTo({
- top: 0,
- behavior: 'smooth'
- })
- }
- }
+ /**
+ * 平滑滚动到页面顶部
+ * 使用 smooth 行为实现平滑滚动效果
+ */
+ const smoothScrollToTop = () => {
+ const scrollContainer = document.getElementById('app-main')
+ if (scrollContainer) {
+ scrollContainer.scrollTo({
+ top: 0,
+ behavior: 'smooth'
+ })
+ }
+ }
- /**
- * 滚动到指定位置
- * @param top 目标滚动位置(像素)
- * @param smooth 是否使用平滑滚动
- */
- const scrollTo = (top: number, smooth: boolean = false) => {
- const scrollContainer = document.getElementById('app-main')
- if (scrollContainer) {
- scrollContainer.scrollTo({
- top,
- behavior: smooth ? 'smooth' : 'auto'
- })
- }
- }
+ /**
+ * 滚动到指定位置
+ * @param top 目标滚动位置(像素)
+ * @param smooth 是否使用平滑滚动
+ */
+ const scrollTo = (top: number, smooth: boolean = false) => {
+ const scrollContainer = document.getElementById('app-main')
+ if (scrollContainer) {
+ scrollContainer.scrollTo({
+ top,
+ behavior: smooth ? 'smooth' : 'auto'
+ })
+ }
+ }
- return {
- homePath,
- refresh,
- scrollTo,
- scrollToTop,
- smoothScrollToTop
- }
+ return {
+ homePath,
+ refresh,
+ scrollTo,
+ scrollToTop,
+ smoothScrollToTop
+ }
}
diff --git a/src/hooks/core/useFastEnter.ts b/src/hooks/core/useFastEnter.ts
index 555eb65..ef168a9 100644
--- a/src/hooks/core/useFastEnter.ts
+++ b/src/hooks/core/useFastEnter.ts
@@ -20,36 +20,36 @@ import appConfig from '@/config'
import type { FastEnterApplication, FastEnterQuickLink } from '@/types/config'
export function useFastEnter() {
- // 获取快速入口配置
- const fastEnterConfig = computed(() => appConfig.fastEnter)
+ // 获取快速入口配置
+ const fastEnterConfig = computed(() => appConfig.fastEnter)
- // 获取启用的应用列表(按排序权重排序)
- const enabledApplications = computed(() => {
- if (!fastEnterConfig.value?.applications) return []
+ // 获取启用的应用列表(按排序权重排序)
+ const enabledApplications = computed(() => {
+ if (!fastEnterConfig.value?.applications) return []
- return fastEnterConfig.value.applications
- .filter((app) => app.enabled !== false)
- .sort((a, b) => (a.order || 0) - (b.order || 0))
- })
+ return fastEnterConfig.value.applications
+ .filter((app) => app.enabled !== false)
+ .sort((a, b) => (a.order || 0) - (b.order || 0))
+ })
- // 获取启用的快速链接(按排序权重排序)
- const enabledQuickLinks = computed(() => {
- if (!fastEnterConfig.value?.quickLinks) return []
+ // 获取启用的快速链接(按排序权重排序)
+ const enabledQuickLinks = computed(() => {
+ if (!fastEnterConfig.value?.quickLinks) return []
- return fastEnterConfig.value.quickLinks
- .filter((link) => link.enabled !== false)
- .sort((a, b) => (a.order || 0) - (b.order || 0))
- })
+ return fastEnterConfig.value.quickLinks
+ .filter((link) => link.enabled !== false)
+ .sort((a, b) => (a.order || 0) - (b.order || 0))
+ })
- // 获取最小显示宽度
- const minWidth = computed(() => {
- return fastEnterConfig.value?.minWidth || 1200
- })
+ // 获取最小显示宽度
+ const minWidth = computed(() => {
+ return fastEnterConfig.value?.minWidth || 1200
+ })
- return {
- fastEnterConfig,
- enabledApplications,
- enabledQuickLinks,
- minWidth
- }
+ return {
+ fastEnterConfig,
+ enabledApplications,
+ enabledQuickLinks,
+ minWidth
+ }
}
diff --git a/src/hooks/core/useHeaderBar.ts b/src/hooks/core/useHeaderBar.ts
index be10712..d8c265d 100644
--- a/src/hooks/core/useHeaderBar.ts
+++ b/src/hooks/core/useHeaderBar.ts
@@ -26,176 +26,176 @@ import { HeaderBarFeatureConfig } from '@/types'
* @returns 顶部栏功能相关的状态和方法
*/
export function useHeaderBar() {
- const settingStore = useSettingStore()
+ const settingStore = useSettingStore()
- // 获取顶部栏配置
- const headerBarConfigRef = computed(() => headerBarConfig)
+ // 获取顶部栏配置
+ const headerBarConfigRef = computed(() => headerBarConfig)
- // 从store中获取相关状态
- const { showMenuButton, showFastEnter, showRefreshButton, showCrumbs, showLanguage } =
- storeToRefs(settingStore)
+ // 从store中获取相关状态
+ const { showMenuButton, showFastEnter, showRefreshButton, showCrumbs, showLanguage } =
+ storeToRefs(settingStore)
- /**
- * 检查特定功能是否启用
- * @param feature 功能名称
- * @returns 是否启用
- */
- const isFeatureEnabled = (feature: keyof HeaderBarFeatureConfig): boolean => {
- return headerBarConfigRef.value[feature]?.enabled ?? false
- }
+ /**
+ * 检查特定功能是否启用
+ * @param feature 功能名称
+ * @returns 是否启用
+ */
+ const isFeatureEnabled = (feature: keyof HeaderBarFeatureConfig): boolean => {
+ return headerBarConfigRef.value[feature]?.enabled ?? false
+ }
- /**
- * 获取功能配置信息
- * @param feature 功能名称
- * @returns 功能配置信息
- */
- const getFeatureConfig = (feature: keyof HeaderBarFeatureConfig) => {
- return headerBarConfigRef.value[feature]
- }
+ /**
+ * 获取功能配置信息
+ * @param feature 功能名称
+ * @returns 功能配置信息
+ */
+ const getFeatureConfig = (feature: keyof HeaderBarFeatureConfig) => {
+ return headerBarConfigRef.value[feature]
+ }
- // 检查菜单按钮是否显示
- const shouldShowMenuButton = computed(() => {
- return isFeatureEnabled('menuButton') && showMenuButton.value
- })
+ // 检查菜单按钮是否显示
+ const shouldShowMenuButton = computed(() => {
+ return isFeatureEnabled('menuButton') && showMenuButton.value
+ })
- // 检查刷新按钮是否显示
- const shouldShowRefreshButton = computed(() => {
- return isFeatureEnabled('refreshButton') && showRefreshButton.value
- })
+ // 检查刷新按钮是否显示
+ const shouldShowRefreshButton = computed(() => {
+ return isFeatureEnabled('refreshButton') && showRefreshButton.value
+ })
- // 检查快速入口是否显示
- const shouldShowFastEnter = computed(() => {
- return isFeatureEnabled('fastEnter') && showFastEnter.value
- })
+ // 检查快速入口是否显示
+ const shouldShowFastEnter = computed(() => {
+ return isFeatureEnabled('fastEnter') && showFastEnter.value
+ })
- // 检查面包屑是否显示
- const shouldShowBreadcrumb = computed(() => {
- return isFeatureEnabled('breadcrumb') && showCrumbs.value
- })
+ // 检查面包屑是否显示
+ const shouldShowBreadcrumb = computed(() => {
+ return isFeatureEnabled('breadcrumb') && showCrumbs.value
+ })
- // 检查全局搜索是否显示
- const shouldShowGlobalSearch = computed(() => {
- return isFeatureEnabled('globalSearch')
- })
+ // 检查全局搜索是否显示
+ const shouldShowGlobalSearch = computed(() => {
+ return isFeatureEnabled('globalSearch')
+ })
- // 检查全屏按钮是否显示
- const shouldShowFullscreen = computed(() => {
- return isFeatureEnabled('fullscreen')
- })
+ // 检查全屏按钮是否显示
+ const shouldShowFullscreen = computed(() => {
+ return isFeatureEnabled('fullscreen')
+ })
- // 检查通知中心是否显示
- const shouldShowNotification = computed(() => {
- return isFeatureEnabled('notification')
- })
+ // 检查通知中心是否显示
+ const shouldShowNotification = computed(() => {
+ return isFeatureEnabled('notification')
+ })
- // 检查聊天功能是否显示
- const shouldShowChat = computed(() => {
- return isFeatureEnabled('chat')
- })
+ // 检查聊天功能是否显示
+ const shouldShowChat = computed(() => {
+ return isFeatureEnabled('chat')
+ })
- // 检查语言切换是否显示
- const shouldShowLanguage = computed(() => {
- return isFeatureEnabled('language') && showLanguage.value
- })
+ // 检查语言切换是否显示
+ const shouldShowLanguage = computed(() => {
+ return isFeatureEnabled('language') && showLanguage.value
+ })
- // 检查设置面板是否显示
- const shouldShowSettings = computed(() => {
- return isFeatureEnabled('settings')
- })
+ // 检查设置面板是否显示
+ const shouldShowSettings = computed(() => {
+ return isFeatureEnabled('settings')
+ })
- // 检查主题切换是否显示
- const shouldShowThemeToggle = computed(() => {
- return isFeatureEnabled('themeToggle')
- })
+ // 检查主题切换是否显示
+ const shouldShowThemeToggle = computed(() => {
+ return isFeatureEnabled('themeToggle')
+ })
- // 获取快速入口的最小宽度
- const fastEnterMinWidth = computed(() => {
- const config = getFeatureConfig('fastEnter')
- return (config as any)?.minWidth || 1200
- })
+ // 获取快速入口的最小宽度
+ const fastEnterMinWidth = computed(() => {
+ const config = getFeatureConfig('fastEnter')
+ return (config as any)?.minWidth || 1200
+ })
- /**
- * 检查功能是否启用(别名)
- * @param feature 功能名称
- * @returns 是否启用
- */
- const isFeatureActive = (feature: keyof HeaderBarFeatureConfig): boolean => {
- return isFeatureEnabled(feature)
- }
+ /**
+ * 检查功能是否启用(别名)
+ * @param feature 功能名称
+ * @returns 是否启用
+ */
+ const isFeatureActive = (feature: keyof HeaderBarFeatureConfig): boolean => {
+ return isFeatureEnabled(feature)
+ }
- /**
- * 获取功能配置(别名)
- * @param feature 功能名称
- * @returns 功能配置
- */
- const getFeatureInfo = (feature: keyof HeaderBarFeatureConfig) => {
- return getFeatureConfig(feature)
- }
+ /**
+ * 获取功能配置(别名)
+ * @param feature 功能名称
+ * @returns 功能配置
+ */
+ const getFeatureInfo = (feature: keyof HeaderBarFeatureConfig) => {
+ return getFeatureConfig(feature)
+ }
- /**
- * 获取所有启用的功能列表
- * @returns 启用的功能名称数组
- */
- const getEnabledFeatures = (): (keyof HeaderBarFeatureConfig)[] => {
- return Object.keys(headerBarConfigRef.value).filter(
- (key) => headerBarConfigRef.value[key as keyof HeaderBarFeatureConfig]?.enabled
- ) as (keyof HeaderBarFeatureConfig)[]
- }
+ /**
+ * 获取所有启用的功能列表
+ * @returns 启用的功能名称数组
+ */
+ const getEnabledFeatures = (): (keyof HeaderBarFeatureConfig)[] => {
+ return Object.keys(headerBarConfigRef.value).filter(
+ (key) => headerBarConfigRef.value[key as keyof HeaderBarFeatureConfig]?.enabled
+ ) as (keyof HeaderBarFeatureConfig)[]
+ }
- /**
- * 获取所有禁用的功能列表
- * @returns 禁用的功能名称数组
- */
- const getDisabledFeatures = (): (keyof HeaderBarFeatureConfig)[] => {
- return Object.keys(headerBarConfigRef.value).filter(
- (key) => !headerBarConfigRef.value[key as keyof HeaderBarFeatureConfig]?.enabled
- ) as (keyof HeaderBarFeatureConfig)[]
- }
+ /**
+ * 获取所有禁用的功能列表
+ * @returns 禁用的功能名称数组
+ */
+ const getDisabledFeatures = (): (keyof HeaderBarFeatureConfig)[] => {
+ return Object.keys(headerBarConfigRef.value).filter(
+ (key) => !headerBarConfigRef.value[key as keyof HeaderBarFeatureConfig]?.enabled
+ ) as (keyof HeaderBarFeatureConfig)[]
+ }
- /**
- * 获取所有启用的功能(别名)
- * @returns 启用的功能列表
- */
- const getActiveFeatures = () => {
- return getEnabledFeatures()
- }
+ /**
+ * 获取所有启用的功能(别名)
+ * @returns 启用的功能列表
+ */
+ const getActiveFeatures = () => {
+ return getEnabledFeatures()
+ }
- /**
- * 获取所有禁用的功能(别名)
- * @returns 禁用的功能列表
- */
- const getInactiveFeatures = () => {
- return getDisabledFeatures()
- }
+ /**
+ * 获取所有禁用的功能(别名)
+ * @returns 禁用的功能列表
+ */
+ const getInactiveFeatures = () => {
+ return getDisabledFeatures()
+ }
- return {
- // 配置
- headerBarConfig: headerBarConfigRef,
+ return {
+ // 配置
+ headerBarConfig: headerBarConfigRef,
- // 显示状态计算属性
- shouldShowMenuButton, // 是否显示菜单按钮
- shouldShowRefreshButton, // 是否显示刷新按钮
- shouldShowFastEnter, // 是否显示快速入口
- shouldShowBreadcrumb, // 是否显示面包屑
- shouldShowGlobalSearch, // 是否显示全局搜索
- shouldShowFullscreen, // 是否显示全屏按钮
- shouldShowNotification, // 是否显示通知中心
- shouldShowChat, // 是否显示聊天功能
- shouldShowLanguage, // 是否显示语言切换
- shouldShowSettings, // 是否显示设置面板
- shouldShowThemeToggle, // 是否显示主题切换
+ // 显示状态计算属性
+ shouldShowMenuButton, // 是否显示菜单按钮
+ shouldShowRefreshButton, // 是否显示刷新按钮
+ shouldShowFastEnter, // 是否显示快速入口
+ shouldShowBreadcrumb, // 是否显示面包屑
+ shouldShowGlobalSearch, // 是否显示全局搜索
+ shouldShowFullscreen, // 是否显示全屏按钮
+ shouldShowNotification, // 是否显示通知中心
+ shouldShowChat, // 是否显示聊天功能
+ shouldShowLanguage, // 是否显示语言切换
+ shouldShowSettings, // 是否显示设置面板
+ shouldShowThemeToggle, // 是否显示主题切换
- // 配置相关
- fastEnterMinWidth, // 快速入口最小宽度
+ // 配置相关
+ fastEnterMinWidth, // 快速入口最小宽度
- // 方法
- isFeatureEnabled, // 检查功能是否启用
- isFeatureActive, // 检查功能是否启用(别名)
- getFeatureConfig, // 获取功能配置
- getFeatureInfo, // 获取功能配置(别名)
- getEnabledFeatures, // 获取所有启用的功能
- getDisabledFeatures, // 获取所有禁用的功能
- getActiveFeatures, // 获取所有启用的功能(别名)
- getInactiveFeatures // 获取所有禁用的功能(别名)
- }
+ // 方法
+ isFeatureEnabled, // 检查功能是否启用
+ isFeatureActive, // 检查功能是否启用(别名)
+ getFeatureConfig, // 获取功能配置
+ getFeatureInfo, // 获取功能配置(别名)
+ getEnabledFeatures, // 获取所有启用的功能
+ getDisabledFeatures, // 获取所有禁用的功能
+ getActiveFeatures, // 获取所有启用的功能(别名)
+ getInactiveFeatures // 获取所有禁用的功能(别名)
+ }
}
diff --git a/src/hooks/core/useLayoutHeight.ts b/src/hooks/core/useLayoutHeight.ts
index 4b1171a..24e68f3 100644
--- a/src/hooks/core/useLayoutHeight.ts
+++ b/src/hooks/core/useLayoutHeight.ts
@@ -23,55 +23,55 @@ import { useElementSize } from '@vueuse/core'
* 页面容器高度配置
*/
interface LayoutHeightOptions {
- /** 额外的间距(默认 15px) */
- extraSpacing?: number
- /** 是否自动更新 CSS 变量(默认 true) */
- updateCssVar?: boolean
- /** CSS 变量名称(默认 '--art-full-height') */
- cssVarName?: string
+ /** 额外的间距(默认 15px) */
+ extraSpacing?: number
+ /** 是否自动更新 CSS 变量(默认 true) */
+ updateCssVar?: boolean
+ /** CSS 变量名称(默认 '--art-full-height') */
+ cssVarName?: string
}
export function useLayoutHeight(options: LayoutHeightOptions = {}) {
- const { extraSpacing = 15, updateCssVar = true, cssVarName = '--art-full-height' } = options
+ const { extraSpacing = 15, updateCssVar = true, cssVarName = '--art-full-height' } = options
- // 元素引用
- const headerRef = ref()
- const contentHeaderRef = ref()
+ // 元素引用
+ const headerRef = ref()
+ const contentHeaderRef = ref()
- // 使用 VueUse 自动监听元素尺寸变化
- const { height: headerHeight } = useElementSize(headerRef)
- const { height: contentHeaderHeight } = useElementSize(contentHeaderRef)
+ // 使用 VueUse 自动监听元素尺寸变化
+ const { height: headerHeight } = useElementSize(headerRef)
+ const { height: contentHeaderHeight } = useElementSize(contentHeaderRef)
- // 计算容器最小高度(响应式)
- const containerMinHeight = computed(() => {
- const totalHeight = headerHeight.value + contentHeaderHeight.value + extraSpacing
- return `calc(100vh - ${totalHeight}px)`
- })
+ // 计算容器最小高度(响应式)
+ const containerMinHeight = computed(() => {
+ const totalHeight = headerHeight.value + contentHeaderHeight.value + extraSpacing
+ return `calc(100vh - ${totalHeight}px)`
+ })
- if (updateCssVar) {
- watch(
- containerMinHeight,
- (newHeight) => {
- requestAnimationFrame(() => {
- document.documentElement.style.setProperty(cssVarName, newHeight)
- })
- },
- { immediate: true }
- )
- }
+ if (updateCssVar) {
+ watch(
+ containerMinHeight,
+ (newHeight) => {
+ requestAnimationFrame(() => {
+ document.documentElement.style.setProperty(cssVarName, newHeight)
+ })
+ },
+ { immediate: true }
+ )
+ }
- return {
- /** 容器最小高度(响应式) */
- containerMinHeight,
- /** 头部元素引用 */
- headerRef,
- /** 内容头部元素引用 */
- contentHeaderRef,
- /** 头部高度(响应式) */
- headerHeight,
- /** 内容头部高度(响应式) */
- contentHeaderHeight
- }
+ return {
+ /** 容器最小高度(响应式) */
+ containerMinHeight,
+ /** 头部元素引用 */
+ headerRef,
+ /** 内容头部元素引用 */
+ contentHeaderRef,
+ /** 头部高度(响应式) */
+ headerHeight,
+ /** 内容头部高度(响应式) */
+ contentHeaderHeight
+ }
}
/**
@@ -84,65 +84,65 @@ export function useLayoutHeight(options: LayoutHeightOptions = {}) {
* ```
*/
export function useAutoLayoutHeight(
- headerIds: string[] = ['app-header', 'app-content-header'],
- options: LayoutHeightOptions = {}
+ headerIds: string[] = ['app-header', 'app-content-header'],
+ options: LayoutHeightOptions = {}
) {
- const { extraSpacing = 15, updateCssVar = true, cssVarName = '--art-full-height' } = options
+ const { extraSpacing = 15, updateCssVar = true, cssVarName = '--art-full-height' } = options
- // 创建元素引用
- const headerRef = ref()
- const contentHeaderRef = ref()
+ // 创建元素引用
+ const headerRef = ref()
+ const contentHeaderRef = ref()
- // 使用 VueUse 自动监听元素尺寸变化
- const { height: headerHeight } = useElementSize(headerRef)
- const { height: contentHeaderHeight } = useElementSize(contentHeaderRef)
+ // 使用 VueUse 自动监听元素尺寸变化
+ const { height: headerHeight } = useElementSize(headerRef)
+ const { height: contentHeaderHeight } = useElementSize(contentHeaderRef)
- // 计算容器最小高度(响应式)
- const containerMinHeight = computed(() => {
- const totalHeight = headerHeight.value + contentHeaderHeight.value + extraSpacing
- return `calc(100vh - ${totalHeight}px)`
- })
+ // 计算容器最小高度(响应式)
+ const containerMinHeight = computed(() => {
+ const totalHeight = headerHeight.value + contentHeaderHeight.value + extraSpacing
+ return `calc(100vh - ${totalHeight}px)`
+ })
- if (updateCssVar) {
- watch(
- containerMinHeight,
- (newHeight) => {
- requestAnimationFrame(() => {
- document.documentElement.style.setProperty(cssVarName, newHeight)
- })
- },
- { immediate: true }
- )
- }
+ if (updateCssVar) {
+ watch(
+ containerMinHeight,
+ (newHeight) => {
+ requestAnimationFrame(() => {
+ document.documentElement.style.setProperty(cssVarName, newHeight)
+ })
+ },
+ { immediate: true }
+ )
+ }
- // 在 DOM 挂载后查找元素
- onMounted(() => {
- if (typeof document !== 'undefined') {
- // 使用 nextTick 确保 DOM 完全渲染
- requestAnimationFrame(() => {
- const header = document.getElementById(headerIds[0])
- const contentHeader = document.getElementById(headerIds[1])
+ // 在 DOM 挂载后查找元素
+ onMounted(() => {
+ if (typeof document !== 'undefined') {
+ // 使用 nextTick 确保 DOM 完全渲染
+ requestAnimationFrame(() => {
+ const header = document.getElementById(headerIds[0])
+ const contentHeader = document.getElementById(headerIds[1])
- if (header) {
- headerRef.value = header
- }
- if (contentHeader) {
- contentHeaderRef.value = contentHeader
- }
- })
- }
- })
+ if (header) {
+ headerRef.value = header
+ }
+ if (contentHeader) {
+ contentHeaderRef.value = contentHeader
+ }
+ })
+ }
+ })
- return {
- /** 容器最小高度(响应式) */
- containerMinHeight,
- /** 头部元素引用 */
- headerRef,
- /** 内容头部元素引用 */
- contentHeaderRef,
- /** 头部高度(响应式) */
- headerHeight,
- /** 内容头部高度(响应式) */
- contentHeaderHeight
- }
+ return {
+ /** 容器最小高度(响应式) */
+ containerMinHeight,
+ /** 头部元素引用 */
+ headerRef,
+ /** 内容头部元素引用 */
+ contentHeaderRef,
+ /** 头部高度(响应式) */
+ headerHeight,
+ /** 内容头部高度(响应式) */
+ contentHeaderHeight
+ }
}
diff --git a/src/hooks/core/useTable.ts b/src/hooks/core/useTable.ts
index afe9ebe..698c632 100644
--- a/src/hooks/core/useTable.ts
+++ b/src/hooks/core/useTable.ts
@@ -22,17 +22,17 @@ import { useWindowSize } from '@vueuse/core'
import { useTableColumns } from './useTableColumns'
import type { ColumnOption } from '@/types/component'
import {
- TableCache,
- CacheInvalidationStrategy,
- type ApiResponse
+ TableCache,
+ CacheInvalidationStrategy,
+ type ApiResponse
} from '../../utils/table/tableCache'
import {
- type TableError,
- defaultResponseAdapter,
- extractTableData,
- updatePaginationFromResponse,
- createSmartDebounce,
- createErrorHandler
+ type TableError,
+ defaultResponseAdapter,
+ extractTableData,
+ updatePaginationFromResponse,
+ createSmartDebounce,
+ createErrorHandler
} from '../../utils/table/tableUtils'
import { tableConfig } from '../../utils/table/tableConfig'
@@ -43,79 +43,79 @@ type InferRecordType = T extends Api.Common.PaginatedResponse ? U :
// 优化的配置接口 - 支持自动类型推导
export interface UseTableConfig<
- TApiFn extends (params: any) => Promise = (params: any) => Promise,
- TRecord = InferRecordType>,
- TParams = InferApiParams,
- TResponse = InferApiResponse
+ TApiFn extends (params: any) => Promise = (params: any) => Promise,
+ TRecord = InferRecordType>,
+ TParams = InferApiParams,
+ TResponse = InferApiResponse
> {
- // 核心配置
- core: {
- /** API 请求函数 */
- apiFn: TApiFn
- /** 默认请求参数 */
- apiParams?: Partial
- /** 排除 apiParams 中的属性 */
- excludeParams?: string[]
- /** 是否立即加载数据 */
- immediate?: boolean
- /** 列配置工厂函数 */
- columnsFactory?: () => ColumnOption[]
- /** 自定义分页字段映射 */
- paginationKey?: {
- /** 当前页码字段名,默认为 'current' */
- current?: string
- /** 每页条数字段名,默认为 'size' */
- size?: string
- }
- }
+ // 核心配置
+ core: {
+ /** API 请求函数 */
+ apiFn: TApiFn
+ /** 默认请求参数 */
+ apiParams?: Partial
+ /** 排除 apiParams 中的属性 */
+ excludeParams?: string[]
+ /** 是否立即加载数据 */
+ immediate?: boolean
+ /** 列配置工厂函数 */
+ columnsFactory?: () => ColumnOption[]
+ /** 自定义分页字段映射 */
+ paginationKey?: {
+ /** 当前页码字段名,默认为 'current' */
+ current?: string
+ /** 每页条数字段名,默认为 'size' */
+ size?: string
+ }
+ }
- // 数据处理
- transform?: {
- /** 数据转换函数 */
- dataTransformer?: (data: TRecord[]) => TRecord[]
- /** 响应数据适配器 */
- responseAdapter?: (response: TResponse) => ApiResponse
- }
+ // 数据处理
+ transform?: {
+ /** 数据转换函数 */
+ dataTransformer?: (data: TRecord[]) => TRecord[]
+ /** 响应数据适配器 */
+ responseAdapter?: (response: TResponse) => ApiResponse
+ }
- // 性能优化
- performance?: {
- /** 是否启用缓存 */
- enableCache?: boolean
- /** 缓存时间(毫秒) */
- cacheTime?: number
- /** 防抖延迟时间(毫秒) */
- debounceTime?: number
- /** 最大缓存条数限制 */
- maxCacheSize?: number
- }
+ // 性能优化
+ performance?: {
+ /** 是否启用缓存 */
+ enableCache?: boolean
+ /** 缓存时间(毫秒) */
+ cacheTime?: number
+ /** 防抖延迟时间(毫秒) */
+ debounceTime?: number
+ /** 最大缓存条数限制 */
+ maxCacheSize?: number
+ }
- // 生命周期钩子
- hooks?: {
- /** 数据加载成功回调(仅网络请求成功时触发) */
- onSuccess?: (data: TRecord[], response: ApiResponse) => void
- /** 错误处理回调 */
- onError?: (error: TableError) => void
- /** 缓存命中回调(从缓存获取数据时触发) */
- onCacheHit?: (data: TRecord[], response: ApiResponse) => void
- /** 加载状态变化回调 */
- onLoading?: (loading: boolean) => void
- /** 重置表单回调函数 */
- resetFormCallback?: () => void
- }
+ // 生命周期钩子
+ hooks?: {
+ /** 数据加载成功回调(仅网络请求成功时触发) */
+ onSuccess?: (data: TRecord[], response: ApiResponse) => void
+ /** 错误处理回调 */
+ onError?: (error: TableError) => void
+ /** 缓存命中回调(从缓存获取数据时触发) */
+ onCacheHit?: (data: TRecord[], response: ApiResponse) => void
+ /** 加载状态变化回调 */
+ onLoading?: (loading: boolean) => void
+ /** 重置表单回调函数 */
+ resetFormCallback?: () => void
+ }
- // 调试配置
- debug?: {
- /** 是否启用日志输出 */
- enableLog?: boolean
- /** 日志级别 */
- logLevel?: 'info' | 'warn' | 'error'
- }
+ // 调试配置
+ debug?: {
+ /** 是否启用日志输出 */
+ enableLog?: boolean
+ /** 日志级别 */
+ logLevel?: 'info' | 'warn' | 'error'
+ }
}
export function useTable Promise>(
- config: UseTableConfig
+ config: UseTableConfig
) {
- return useTableImpl(config)
+ return useTableImpl(config)
}
/**
@@ -130,604 +130,606 @@ export function useTable Promise>(
* - 列配置管理
*/
function useTableImpl Promise>(
- config: UseTableConfig
+ config: UseTableConfig
) {
- type TRecord = InferRecordType>
- type TParams = InferApiParams
- const {
- core: {
- apiFn,
- apiParams = {} as Partial,
- excludeParams = [],
- immediate = true,
- columnsFactory,
- paginationKey
- },
- transform: { dataTransformer, responseAdapter = defaultResponseAdapter } = {},
- performance: {
- enableCache = false,
- cacheTime = 5 * 60 * 1000,
- debounceTime = 300,
- maxCacheSize = 50
- } = {},
- hooks: { onSuccess, onError, onCacheHit, resetFormCallback } = {},
- debug: { enableLog = false } = {}
- } = config
-
- // 分页字段名配置:优先使用传入的配置,否则使用全局配置
- const pageKey = paginationKey?.current || tableConfig.paginationKey.current
- const sizeKey = paginationKey?.size || tableConfig.paginationKey.size
-
- // 响应式触发器,用于手动更新缓存统计信息
- const cacheUpdateTrigger = ref(0)
-
- // 日志工具函数
- const logger = {
- log: (message: string, ...args: unknown[]) => {
- if (enableLog) {
- console.log(`[useTable] ${message}`, ...args)
- }
- },
- warn: (message: string, ...args: unknown[]) => {
- if (enableLog) {
- console.warn(`[useTable] ${message}`, ...args)
- }
- },
- error: (message: string, ...args: unknown[]) => {
- if (enableLog) {
- console.error(`[useTable] ${message}`, ...args)
- }
- }
- }
-
- // 缓存实例
- const cache = enableCache ? new TableCache(cacheTime, maxCacheSize, enableLog) : null
-
- // 加载状态机
- type LoadingState = 'idle' | 'loading' | 'success' | 'error'
- const loadingState = ref('idle')
- const loading = computed(() => loadingState.value === 'loading')
-
- // 错误状态
- const error = ref(null)
-
- // 表格数据
- const data = ref([])
-
- // 请求取消控制器
- let abortController: AbortController | null = null
-
- // 缓存清理定时器
- let cacheCleanupTimer: NodeJS.Timeout | null = null
-
- // 搜索参数
- const searchParams = reactive(
- Object.assign(
- {
- [pageKey]: 1,
- [sizeKey]: 10
- },
- apiParams || {}
- ) as TParams
- )
-
- // 分页配置
- const pagination = reactive({
- current: ((searchParams as Record)[pageKey] as number) || 1,
- size: ((searchParams as Record)[sizeKey] as number) || 10,
- total: 0
- })
-
- // 移动端分页 (响应式)
- const { width } = useWindowSize()
- const mobilePagination = computed(() => ({
- ...pagination,
- small: width.value < 768
- }))
-
- // 列配置
- const columnConfig = columnsFactory ? useTableColumns(columnsFactory) : null
- const columns = columnConfig?.columns
- const columnChecks = columnConfig?.columnChecks
-
- // 是否有数据
- const hasData = computed(() => data.value.length > 0)
-
- // 缓存统计信息
- const cacheInfo = computed(() => {
- // 依赖触发器,确保缓存变化时重新计算
- void cacheUpdateTrigger.value
- if (!cache) return { total: 0, size: '0KB', hitRate: '0 avg hits' }
- return cache.getStats()
- })
-
- // 错误处理函数
- const handleError = createErrorHandler(onError, enableLog)
-
- // 清理缓存,根据不同的业务场景选择性地清理缓存
- const clearCache = (strategy: CacheInvalidationStrategy, context?: string): void => {
- if (!cache) return
-
- let clearedCount = 0
-
- switch (strategy) {
- case CacheInvalidationStrategy.CLEAR_ALL:
- cache.clear()
- logger.log(`清空所有缓存 - ${context || ''}`)
- break
-
- case CacheInvalidationStrategy.CLEAR_CURRENT:
- clearedCount = cache.clearCurrentSearch(searchParams)
- logger.log(`清空当前搜索缓存 ${clearedCount} 条 - ${context || ''}`)
- break
-
- case CacheInvalidationStrategy.CLEAR_PAGINATION:
- clearedCount = cache.clearPagination()
- logger.log(`清空分页缓存 ${clearedCount} 条 - ${context || ''}`)
- break
-
- case CacheInvalidationStrategy.KEEP_ALL:
- default:
- logger.log(`保持缓存不变 - ${context || ''}`)
- break
- }
- // 手动触发缓存状态更新
- cacheUpdateTrigger.value++
- }
-
- // 获取数据的核心方法
- const fetchData = async (
- params?: Partial,
- useCache = enableCache
- ): Promise> => {
- // 取消上一个请求
- if (abortController) {
- abortController.abort()
- }
-
- // 创建新的取消控制器
- const currentController = new AbortController()
- abortController = currentController
-
- // 状态机:进入 loading 状态
- loadingState.value = 'loading'
- error.value = null
-
- try {
- let requestParams = Object.assign(
- {},
- searchParams,
- {
- [pageKey]: pagination.current,
- [sizeKey]: pagination.size
- },
- params || {}
- ) as TParams
-
- // 剔除不需要的参数
- if (excludeParams.length > 0) {
- const filteredParams = { ...requestParams }
- excludeParams.forEach((key) => {
- delete (filteredParams as Record)[key]
- })
- requestParams = filteredParams as TParams
- }
-
- // 检查缓存
- if (useCache && cache) {
- const cachedItem = cache.get(requestParams)
- if (cachedItem) {
- data.value = cachedItem.data
- updatePaginationFromResponse(pagination, cachedItem.response)
-
- // 修复:避免重复设置相同的值,防止响应式循环更新
- const paramsRecord = searchParams as Record
- if (paramsRecord[pageKey] !== pagination.current) {
- paramsRecord[pageKey] = pagination.current
- }
- if (paramsRecord[sizeKey] !== pagination.size) {
- paramsRecord[sizeKey] = pagination.size
- }
-
- // 状态机:缓存命中,进入 success 状态
- loadingState.value = 'success'
-
- // 缓存命中时触发专门的回调,而不是 onSuccess
- if (onCacheHit) {
- onCacheHit(cachedItem.data, cachedItem.response)
- }
-
- logger.log(`缓存命中`)
- return cachedItem.response
- }
- }
-
- const response = await apiFn(requestParams)
-
- // 检查请求是否被取消
- if (currentController.signal.aborted) {
- throw new Error('请求已取消')
- }
-
- // 使用响应适配器转换为标准格式
- const standardResponse = responseAdapter(response)
-
- // 处理响应数据
- let tableData = extractTableData(standardResponse)
-
- // 应用数据转换函数
- if (dataTransformer) {
- tableData = dataTransformer(tableData)
- }
-
- // 更新状态
- data.value = tableData
- updatePaginationFromResponse(pagination, standardResponse)
-
- // 修复:避免重复设置相同的值,防止响应式循环更新
- const paramsRecord = searchParams as Record
- if (paramsRecord[pageKey] !== pagination.current) {
- paramsRecord[pageKey] = pagination.current
- }
- if (paramsRecord[sizeKey] !== pagination.size) {
- paramsRecord[sizeKey] = pagination.size
- }
-
- // 缓存数据
- if (useCache && cache) {
- cache.set(requestParams, tableData, standardResponse)
- // 手动触发缓存状态更新
- cacheUpdateTrigger.value++
- logger.log(`数据已缓存`)
- }
-
- // 状态机:请求成功,进入 success 状态
- loadingState.value = 'success'
-
- // 成功回调
- if (onSuccess) {
- onSuccess(tableData, standardResponse)
- }
-
- return standardResponse
- } catch (err) {
- if (err instanceof Error && err.message === '请求已取消') {
- // 请求被取消,回到 idle 状态
- loadingState.value = 'idle'
- return { records: [], total: 0, current: 1, size: 10 }
- }
-
- // 状态机:请求失败,进入 error 状态
- loadingState.value = 'error'
- data.value = []
- const tableError = handleError(err, '获取表格数据失败')
- throw tableError
- } finally {
- // 只有当前控制器是活跃的才清空
- if (abortController === currentController) {
- abortController = null
- }
- }
- }
-
- // 获取数据 (保持当前页)
- const getData = async (params?: Partial): Promise | void> => {
- try {
- return await fetchData(params)
- } catch {
- // 错误已在 fetchData 中处理
- return Promise.resolve()
- }
- }
-
- // 分页获取数据 (重置到第一页) - 专门用于搜索场景
- const getDataByPage = async (params?: Partial): Promise | void> => {
- pagination.current = 1
- ;(searchParams as Record)[pageKey] = 1
-
- // 搜索时清空当前搜索条件的缓存,确保获取最新数据
- clearCache(CacheInvalidationStrategy.CLEAR_CURRENT, '搜索数据')
-
- try {
- return await fetchData(params, false) // 搜索时不使用缓存
- } catch {
- // 错误已在 fetchData 中处理
- return Promise.resolve()
- }
- }
-
- // 智能防抖搜索函数
- const debouncedGetDataByPage = createSmartDebounce(getDataByPage, debounceTime)
-
- // 重置搜索参数
- const resetSearchParams = async (): Promise => {
- // 取消防抖的搜索
- debouncedGetDataByPage.cancel()
-
- // 保存分页相关的默认值
- const paramsRecord = searchParams as Record
- const defaultPagination = {
- [pageKey]: 1,
- [sizeKey]: (paramsRecord[sizeKey] as number) || 10
- }
-
- // 清空所有搜索参数
- Object.keys(searchParams).forEach((key) => {
- delete paramsRecord[key]
- })
-
- // 重新设置默认参数
- Object.assign(searchParams, apiParams || {}, defaultPagination)
-
- // 重置分页
- pagination.current = 1
- pagination.size = defaultPagination[sizeKey] as number
-
- // 清空错误状态
- error.value = null
-
- // 清空缓存
- clearCache(CacheInvalidationStrategy.CLEAR_ALL, '重置搜索')
-
- // 重新获取数据
- await getData()
-
- // 执行重置回调
- if (resetFormCallback) {
- await nextTick()
- resetFormCallback()
- }
- }
-
- // 防重复调用的标志
- let isCurrentChanging = false
-
- // 处理分页大小变化
- const handleSizeChange = async (newSize: number): Promise => {
- if (newSize <= 0) return
-
- debouncedGetDataByPage.cancel()
-
- const paramsRecord = searchParams as Record
- pagination.size = newSize
- pagination.current = 1
- paramsRecord[sizeKey] = newSize
- paramsRecord[pageKey] = 1
-
- clearCache(CacheInvalidationStrategy.CLEAR_CURRENT, '分页大小变化')
-
- await getData()
- }
-
- // 处理当前页变化
- const handleCurrentChange = async (newCurrent: number): Promise => {
- if (newCurrent <= 0) return
-
- // 修复:防止重复调用
- if (isCurrentChanging) {
- return
- }
-
- // 修复:如果当前页没有变化,不需要重新请求
- if (pagination.current === newCurrent) {
- logger.log('分页页码未变化,跳过请求')
- return
- }
-
- try {
- isCurrentChanging = true
-
- // 修复:只更新必要的状态
- const paramsRecord = searchParams as Record
- pagination.current = newCurrent
- // 只有当 searchParams 的分页字段与新值不同时才更新
- if (paramsRecord[pageKey] !== newCurrent) {
- paramsRecord[pageKey] = newCurrent
- }
-
- await getData()
- } finally {
- isCurrentChanging = false
- }
- }
-
- // 针对不同业务场景的刷新方法
-
- // 新增后刷新:回到第一页并清空分页缓存(适用于新增数据后)
- const refreshCreate = async (): Promise => {
- debouncedGetDataByPage.cancel()
- pagination.current = 1
- ;(searchParams as Record)[pageKey] = 1
- clearCache(CacheInvalidationStrategy.CLEAR_PAGINATION, '新增数据')
- await getData()
- }
-
- // 更新后刷新:保持当前页,仅清空当前搜索缓存(适用于更新数据后)
- const refreshUpdate = async (): Promise => {
- clearCache(CacheInvalidationStrategy.CLEAR_CURRENT, '编辑数据')
- await getData()
- }
-
- // 删除后刷新:智能处理页码,避免空页面(适用于删除数据后)
- const refreshRemove = async (): Promise => {
- const { current } = pagination
-
- // 清除缓存并获取最新数据
- clearCache(CacheInvalidationStrategy.CLEAR_CURRENT, '删除数据')
- await getData()
-
- // 如果当前页为空且不是第一页,回到上一页
- if (data.value.length === 0 && current > 1) {
- pagination.current = current - 1
- ;(searchParams as Record)[pageKey] = current - 1
- await getData()
- }
- }
-
- // 全量刷新:清空所有缓存,重新获取数据(适用于手动刷新按钮)
- const refreshData = async (): Promise => {
- debouncedGetDataByPage.cancel()
- clearCache(CacheInvalidationStrategy.CLEAR_ALL, '手动刷新')
- await getData()
- }
-
- // 轻量刷新:仅清空当前搜索条件的缓存,保持分页状态(适用于定时刷新)
- const refreshSoft = async (): Promise => {
- clearCache(CacheInvalidationStrategy.CLEAR_CURRENT, '软刷新')
- await getData()
- }
-
- // 取消当前请求
- const cancelRequest = (): void => {
- if (abortController) {
- abortController.abort()
- }
- debouncedGetDataByPage.cancel()
- }
-
- // 清空数据
- const clearData = (): void => {
- data.value = []
- error.value = null
- clearCache(CacheInvalidationStrategy.CLEAR_ALL, '清空数据')
- }
-
- // 清理已过期的缓存条目,释放内存空间
- const clearExpiredCache = (): number => {
- if (!cache) return 0
- const cleanedCount = cache.cleanupExpired()
- if (cleanedCount > 0) {
- // 手动触发缓存状态更新
- cacheUpdateTrigger.value++
- }
- return cleanedCount
- }
-
- // 设置定期清理过期缓存
- if (enableCache && cache) {
- cacheCleanupTimer = setInterval(() => {
- const cleanedCount = cache.cleanupExpired()
- if (cleanedCount > 0) {
- logger.log(`自动清理 ${cleanedCount} 条过期缓存`)
- // 手动触发缓存状态更新
- cacheUpdateTrigger.value++
- }
- }, cacheTime / 2) // 每半个缓存周期清理一次
- }
-
- // 挂载时自动加载数据
- if (immediate) {
- onMounted(async () => {
- await getData()
- })
- }
-
- // 组件卸载时彻底清理
- onUnmounted(() => {
- cancelRequest()
- if (cache) {
- cache.clear()
- }
- if (cacheCleanupTimer) {
- clearInterval(cacheCleanupTimer)
- }
- })
-
- // 优化的返回值结构
- return {
- // 数据相关
- /** 表格数据 */
- data,
- /** 数据加载状态 */
- loading: readonly(loading),
- /** 错误状态 */
- error: readonly(error),
- /** 数据是否为空 */
- isEmpty: computed(() => data.value.length === 0),
- /** 是否有数据 */
- hasData,
-
- // 分页相关
- /** 分页状态信息 */
- pagination: readonly(pagination),
- /** 移动端分页配置 */
- paginationMobile: mobilePagination,
- /** 页面大小变化处理 */
- handleSizeChange,
- /** 当前页变化处理 */
- handleCurrentChange,
-
- // 搜索相关 - 统一前缀
- /** 搜索参数 */
- searchParams,
- /** 重置搜索参数 */
- resetSearchParams,
-
- // 数据操作 - 更明确的操作意图
- /** 加载数据 */
- fetchData: getData,
- /** 获取数据 */
- getData: getDataByPage,
- /** 获取数据(防抖) */
- getDataDebounced: debouncedGetDataByPage,
- /** 清空数据 */
- clearData,
-
- // 刷新策略
- /** 全量刷新:清空所有缓存,重新获取数据(适用于手动刷新按钮) */
- refreshData,
- /** 轻量刷新:仅清空当前搜索条件的缓存,保持分页状态(适用于定时刷新) */
- refreshSoft,
- /** 新增后刷新:回到第一页并清空分页缓存(适用于新增数据后) */
- refreshCreate,
- /** 更新后刷新:保持当前页,仅清空当前搜索缓存(适用于更新数据后) */
- refreshUpdate,
- /** 删除后刷新:智能处理页码,避免空页面(适用于删除数据后) */
- refreshRemove,
-
- // 缓存控制
- /** 缓存统计信息 */
- cacheInfo,
- /** 清除缓存,根据不同的业务场景选择性地清理缓存: */
- clearCache,
- // 支持4种清理策略
- // clearCache(CacheInvalidationStrategy.CLEAR_ALL, '手动刷新') // 清空所有缓存
- // clearCache(CacheInvalidationStrategy.CLEAR_CURRENT, '搜索数据') // 只清空当前搜索条件的缓存
- // clearCache(CacheInvalidationStrategy.CLEAR_PAGINATION, '新增数据') // 清空分页相关缓存
- // clearCache(CacheInvalidationStrategy.KEEP_ALL, '保持缓存') // 不清理任何缓存
- /** 清理已过期的缓存条目,释放内存空间 */
- clearExpiredCache,
-
- // 请求控制
- /** 取消当前请求 */
- cancelRequest,
-
- // 列配置 (如果提供了 columnsFactory)
- ...(columnConfig && {
- /** 表格列配置 */
- columns,
- /** 列显示控制 */
- columnChecks,
- /** 新增列 */
- addColumn: columnConfig.addColumn,
- /** 删除列 */
- removeColumn: columnConfig.removeColumn,
- /** 切换列显示状态 */
- toggleColumn: columnConfig.toggleColumn,
- /** 更新列配置 */
- updateColumn: columnConfig.updateColumn,
- /** 批量更新列配置 */
- batchUpdateColumns: columnConfig.batchUpdateColumns,
- /** 重新排序列 */
- reorderColumns: columnConfig.reorderColumns,
- /** 获取指定列配置 */
- getColumnConfig: columnConfig.getColumnConfig,
- /** 获取所有列配置 */
- getAllColumns: columnConfig.getAllColumns,
- /** 重置所有列配置到默认状态 */
- resetColumns: columnConfig.resetColumns
- })
- }
+ type TRecord = InferRecordType>
+ type TParams = InferApiParams
+ const {
+ core: {
+ apiFn,
+ apiParams = {} as Partial,
+ excludeParams = [],
+ immediate = true,
+ columnsFactory,
+ paginationKey
+ },
+ transform: { dataTransformer, responseAdapter = defaultResponseAdapter } = {},
+ performance: {
+ enableCache = false,
+ cacheTime = 5 * 60 * 1000,
+ debounceTime = 300,
+ maxCacheSize = 50
+ } = {},
+ hooks: { onSuccess, onError, onCacheHit, resetFormCallback } = {},
+ debug: { enableLog = false } = {}
+ } = config
+
+ // 分页字段名配置:优先使用传入的配置,否则使用全局配置
+ const pageKey = paginationKey?.current || tableConfig.paginationKey.current
+ const sizeKey = paginationKey?.size || tableConfig.paginationKey.size
+
+ // 响应式触发器,用于手动更新缓存统计信息
+ const cacheUpdateTrigger = ref(0)
+
+ // 日志工具函数
+ const logger = {
+ log: (message: string, ...args: unknown[]) => {
+ if (enableLog) {
+ console.log(`[useTable] ${message}`, ...args)
+ }
+ },
+ warn: (message: string, ...args: unknown[]) => {
+ if (enableLog) {
+ console.warn(`[useTable] ${message}`, ...args)
+ }
+ },
+ error: (message: string, ...args: unknown[]) => {
+ if (enableLog) {
+ console.error(`[useTable] ${message}`, ...args)
+ }
+ }
+ }
+
+ // 缓存实例
+ const cache = enableCache ? new TableCache(cacheTime, maxCacheSize, enableLog) : null
+
+ // 加载状态机
+ type LoadingState = 'idle' | 'loading' | 'success' | 'error'
+ const loadingState = ref('idle')
+ const loading = computed(() => loadingState.value === 'loading')
+
+ // 错误状态
+ const error = ref(null)
+
+ // 表格数据
+ const data = ref([])
+
+ // 请求取消控制器
+ let abortController: AbortController | null = null
+
+ // 缓存清理定时器
+ let cacheCleanupTimer: NodeJS.Timeout | null = null
+
+ // 搜索参数
+ const searchParams = reactive(
+ Object.assign(
+ {
+ [pageKey]: 1,
+ [sizeKey]: 10
+ },
+ apiParams || {}
+ ) as TParams
+ )
+
+ // 分页配置
+ const pagination = reactive({
+ current: ((searchParams as Record)[pageKey] as number) || 1,
+ size: ((searchParams as Record)[sizeKey] as number) || 10,
+ total: 0
+ })
+
+ // 移动端分页 (响应式)
+ const { width } = useWindowSize()
+ const mobilePagination = computed(() => ({
+ ...pagination,
+ small: width.value < 768
+ }))
+
+ // 列配置
+ const columnConfig = columnsFactory ? useTableColumns(columnsFactory) : null
+ const columns = columnConfig?.columns
+ const columnChecks = columnConfig?.columnChecks
+
+ // 是否有数据
+ const hasData = computed(() => data.value.length > 0)
+
+ // 缓存统计信息
+ const cacheInfo = computed(() => {
+ // 依赖触发器,确保缓存变化时重新计算
+ void cacheUpdateTrigger.value
+ if (!cache) return { total: 0, size: '0KB', hitRate: '0 avg hits' }
+ return cache.getStats()
+ })
+
+ // 错误处理函数
+ const handleError = createErrorHandler(onError, enableLog)
+
+ // 清理缓存,根据不同的业务场景选择性地清理缓存
+ const clearCache = (strategy: CacheInvalidationStrategy, context?: string): void => {
+ if (!cache) return
+
+ let clearedCount = 0
+
+ switch (strategy) {
+ case CacheInvalidationStrategy.CLEAR_ALL:
+ cache.clear()
+ logger.log(`清空所有缓存 - ${context || ''}`)
+ break
+
+ case CacheInvalidationStrategy.CLEAR_CURRENT:
+ clearedCount = cache.clearCurrentSearch(searchParams)
+ logger.log(`清空当前搜索缓存 ${clearedCount} 条 - ${context || ''}`)
+ break
+
+ case CacheInvalidationStrategy.CLEAR_PAGINATION:
+ clearedCount = cache.clearPagination()
+ logger.log(`清空分页缓存 ${clearedCount} 条 - ${context || ''}`)
+ break
+
+ case CacheInvalidationStrategy.KEEP_ALL:
+ default:
+ logger.log(`保持缓存不变 - ${context || ''}`)
+ break
+ }
+ // 手动触发缓存状态更新
+ cacheUpdateTrigger.value++
+ }
+
+ // 获取数据的核心方法
+ const fetchData = async (
+ params?: Partial,
+ useCache = enableCache
+ ): Promise> => {
+ // 取消上一个请求
+ if (abortController) {
+ abortController.abort()
+ }
+
+ // 创建新的取消控制器
+ const currentController = new AbortController()
+ abortController = currentController
+
+ // 状态机:进入 loading 状态
+ loadingState.value = 'loading'
+ error.value = null
+
+ try {
+ let requestParams = Object.assign(
+ {},
+ searchParams,
+ {
+ [pageKey]: pagination.current,
+ [sizeKey]: pagination.size
+ },
+ params || {}
+ ) as TParams
+
+ // 剔除不需要的参数
+ if (excludeParams.length > 0) {
+ const filteredParams = { ...requestParams }
+ excludeParams.forEach((key) => {
+ delete (filteredParams as Record)[key]
+ })
+ requestParams = filteredParams as TParams
+ }
+
+ // 检查缓存
+ if (useCache && cache) {
+ const cachedItem = cache.get(requestParams)
+ if (cachedItem) {
+ data.value = cachedItem.data
+ updatePaginationFromResponse(pagination, cachedItem.response)
+
+ // 修复:避免重复设置相同的值,防止响应式循环更新
+ const paramsRecord = searchParams as Record
+ if (paramsRecord[pageKey] !== pagination.current) {
+ paramsRecord[pageKey] = pagination.current
+ }
+ if (paramsRecord[sizeKey] !== pagination.size) {
+ paramsRecord[sizeKey] = pagination.size
+ }
+
+ // 状态机:缓存命中,进入 success 状态
+ loadingState.value = 'success'
+
+ // 缓存命中时触发专门的回调,而不是 onSuccess
+ if (onCacheHit) {
+ onCacheHit(cachedItem.data, cachedItem.response)
+ }
+
+ logger.log(`缓存命中`)
+ return cachedItem.response
+ }
+ }
+
+ const response = await apiFn(requestParams)
+
+ // 检查请求是否被取消
+ if (currentController.signal.aborted) {
+ throw new Error('请求已取消')
+ }
+
+ // 使用响应适配器转换为标准格式
+ const standardResponse = responseAdapter(response)
+
+ // 处理响应数据
+ let tableData = extractTableData(standardResponse)
+
+ // 应用数据转换函数
+ if (dataTransformer) {
+ tableData = dataTransformer(tableData)
+ }
+
+ // 更新状态
+ data.value = tableData
+ updatePaginationFromResponse(pagination, standardResponse)
+
+ // 修复:避免重复设置相同的值,防止响应式循环更新
+ const paramsRecord = searchParams as Record
+ if (paramsRecord[pageKey] !== pagination.current) {
+ paramsRecord[pageKey] = pagination.current
+ }
+ if (paramsRecord[sizeKey] !== pagination.size) {
+ paramsRecord[sizeKey] = pagination.size
+ }
+
+ // 缓存数据
+ if (useCache && cache) {
+ cache.set(requestParams, tableData, standardResponse)
+ // 手动触发缓存状态更新
+ cacheUpdateTrigger.value++
+ logger.log(`数据已缓存`)
+ }
+
+ // 状态机:请求成功,进入 success 状态
+ loadingState.value = 'success'
+
+ // 成功回调
+ if (onSuccess) {
+ onSuccess(tableData, standardResponse)
+ }
+
+ return standardResponse
+ } catch (err) {
+ if (err instanceof Error && err.message === '请求已取消') {
+ // 请求被取消,回到 idle 状态
+ loadingState.value = 'idle'
+ return { records: [], total: 0, current: 1, size: 10 }
+ }
+
+ // 状态机:请求失败,进入 error 状态
+ loadingState.value = 'error'
+ data.value = []
+ const tableError = handleError(err, '获取表格数据失败')
+ throw tableError
+ } finally {
+ // 只有当前控制器是活跃的才清空
+ if (abortController === currentController) {
+ abortController = null
+ }
+ }
+ }
+
+ // 获取数据 (保持当前页)
+ const getData = async (params?: Partial): Promise | void> => {
+ try {
+ return await fetchData(params)
+ } catch {
+ // 错误已在 fetchData 中处理
+ return Promise.resolve()
+ }
+ }
+
+ // 分页获取数据 (重置到第一页) - 专门用于搜索场景
+ const getDataByPage = async (
+ params?: Partial
+ ): Promise | void> => {
+ pagination.current = 1
+ ;(searchParams as Record)[pageKey] = 1
+
+ // 搜索时清空当前搜索条件的缓存,确保获取最新数据
+ clearCache(CacheInvalidationStrategy.CLEAR_CURRENT, '搜索数据')
+
+ try {
+ return await fetchData(params, false) // 搜索时不使用缓存
+ } catch {
+ // 错误已在 fetchData 中处理
+ return Promise.resolve()
+ }
+ }
+
+ // 智能防抖搜索函数
+ const debouncedGetDataByPage = createSmartDebounce(getDataByPage, debounceTime)
+
+ // 重置搜索参数
+ const resetSearchParams = async (): Promise => {
+ // 取消防抖的搜索
+ debouncedGetDataByPage.cancel()
+
+ // 保存分页相关的默认值
+ const paramsRecord = searchParams as Record
+ const defaultPagination = {
+ [pageKey]: 1,
+ [sizeKey]: (paramsRecord[sizeKey] as number) || 10
+ }
+
+ // 清空所有搜索参数
+ Object.keys(searchParams).forEach((key) => {
+ delete paramsRecord[key]
+ })
+
+ // 重新设置默认参数
+ Object.assign(searchParams, apiParams || {}, defaultPagination)
+
+ // 重置分页
+ pagination.current = 1
+ pagination.size = defaultPagination[sizeKey] as number
+
+ // 清空错误状态
+ error.value = null
+
+ // 清空缓存
+ clearCache(CacheInvalidationStrategy.CLEAR_ALL, '重置搜索')
+
+ // 重新获取数据
+ await getData()
+
+ // 执行重置回调
+ if (resetFormCallback) {
+ await nextTick()
+ resetFormCallback()
+ }
+ }
+
+ // 防重复调用的标志
+ let isCurrentChanging = false
+
+ // 处理分页大小变化
+ const handleSizeChange = async (newSize: number): Promise => {
+ if (newSize <= 0) return
+
+ debouncedGetDataByPage.cancel()
+
+ const paramsRecord = searchParams as Record
+ pagination.size = newSize
+ pagination.current = 1
+ paramsRecord[sizeKey] = newSize
+ paramsRecord[pageKey] = 1
+
+ clearCache(CacheInvalidationStrategy.CLEAR_CURRENT, '分页大小变化')
+
+ await getData()
+ }
+
+ // 处理当前页变化
+ const handleCurrentChange = async (newCurrent: number): Promise => {
+ if (newCurrent <= 0) return
+
+ // 修复:防止重复调用
+ if (isCurrentChanging) {
+ return
+ }
+
+ // 修复:如果当前页没有变化,不需要重新请求
+ if (pagination.current === newCurrent) {
+ logger.log('分页页码未变化,跳过请求')
+ return
+ }
+
+ try {
+ isCurrentChanging = true
+
+ // 修复:只更新必要的状态
+ const paramsRecord = searchParams as Record
+ pagination.current = newCurrent
+ // 只有当 searchParams 的分页字段与新值不同时才更新
+ if (paramsRecord[pageKey] !== newCurrent) {
+ paramsRecord[pageKey] = newCurrent
+ }
+
+ await getData()
+ } finally {
+ isCurrentChanging = false
+ }
+ }
+
+ // 针对不同业务场景的刷新方法
+
+ // 新增后刷新:回到第一页并清空分页缓存(适用于新增数据后)
+ const refreshCreate = async (): Promise => {
+ debouncedGetDataByPage.cancel()
+ pagination.current = 1
+ ;(searchParams as Record)[pageKey] = 1
+ clearCache(CacheInvalidationStrategy.CLEAR_PAGINATION, '新增数据')
+ await getData()
+ }
+
+ // 更新后刷新:保持当前页,仅清空当前搜索缓存(适用于更新数据后)
+ const refreshUpdate = async (): Promise => {
+ clearCache(CacheInvalidationStrategy.CLEAR_CURRENT, '编辑数据')
+ await getData()
+ }
+
+ // 删除后刷新:智能处理页码,避免空页面(适用于删除数据后)
+ const refreshRemove = async (): Promise => {
+ const { current } = pagination
+
+ // 清除缓存并获取最新数据
+ clearCache(CacheInvalidationStrategy.CLEAR_CURRENT, '删除数据')
+ await getData()
+
+ // 如果当前页为空且不是第一页,回到上一页
+ if (data.value.length === 0 && current > 1) {
+ pagination.current = current - 1
+ ;(searchParams as Record)[pageKey] = current - 1
+ await getData()
+ }
+ }
+
+ // 全量刷新:清空所有缓存,重新获取数据(适用于手动刷新按钮)
+ const refreshData = async (): Promise => {
+ debouncedGetDataByPage.cancel()
+ clearCache(CacheInvalidationStrategy.CLEAR_ALL, '手动刷新')
+ await getData()
+ }
+
+ // 轻量刷新:仅清空当前搜索条件的缓存,保持分页状态(适用于定时刷新)
+ const refreshSoft = async (): Promise => {
+ clearCache(CacheInvalidationStrategy.CLEAR_CURRENT, '软刷新')
+ await getData()
+ }
+
+ // 取消当前请求
+ const cancelRequest = (): void => {
+ if (abortController) {
+ abortController.abort()
+ }
+ debouncedGetDataByPage.cancel()
+ }
+
+ // 清空数据
+ const clearData = (): void => {
+ data.value = []
+ error.value = null
+ clearCache(CacheInvalidationStrategy.CLEAR_ALL, '清空数据')
+ }
+
+ // 清理已过期的缓存条目,释放内存空间
+ const clearExpiredCache = (): number => {
+ if (!cache) return 0
+ const cleanedCount = cache.cleanupExpired()
+ if (cleanedCount > 0) {
+ // 手动触发缓存状态更新
+ cacheUpdateTrigger.value++
+ }
+ return cleanedCount
+ }
+
+ // 设置定期清理过期缓存
+ if (enableCache && cache) {
+ cacheCleanupTimer = setInterval(() => {
+ const cleanedCount = cache.cleanupExpired()
+ if (cleanedCount > 0) {
+ logger.log(`自动清理 ${cleanedCount} 条过期缓存`)
+ // 手动触发缓存状态更新
+ cacheUpdateTrigger.value++
+ }
+ }, cacheTime / 2) // 每半个缓存周期清理一次
+ }
+
+ // 挂载时自动加载数据
+ if (immediate) {
+ onMounted(async () => {
+ await getData()
+ })
+ }
+
+ // 组件卸载时彻底清理
+ onUnmounted(() => {
+ cancelRequest()
+ if (cache) {
+ cache.clear()
+ }
+ if (cacheCleanupTimer) {
+ clearInterval(cacheCleanupTimer)
+ }
+ })
+
+ // 优化的返回值结构
+ return {
+ // 数据相关
+ /** 表格数据 */
+ data,
+ /** 数据加载状态 */
+ loading: readonly(loading),
+ /** 错误状态 */
+ error: readonly(error),
+ /** 数据是否为空 */
+ isEmpty: computed(() => data.value.length === 0),
+ /** 是否有数据 */
+ hasData,
+
+ // 分页相关
+ /** 分页状态信息 */
+ pagination: readonly(pagination),
+ /** 移动端分页配置 */
+ paginationMobile: mobilePagination,
+ /** 页面大小变化处理 */
+ handleSizeChange,
+ /** 当前页变化处理 */
+ handleCurrentChange,
+
+ // 搜索相关 - 统一前缀
+ /** 搜索参数 */
+ searchParams,
+ /** 重置搜索参数 */
+ resetSearchParams,
+
+ // 数据操作 - 更明确的操作意图
+ /** 加载数据 */
+ fetchData: getData,
+ /** 获取数据 */
+ getData: getDataByPage,
+ /** 获取数据(防抖) */
+ getDataDebounced: debouncedGetDataByPage,
+ /** 清空数据 */
+ clearData,
+
+ // 刷新策略
+ /** 全量刷新:清空所有缓存,重新获取数据(适用于手动刷新按钮) */
+ refreshData,
+ /** 轻量刷新:仅清空当前搜索条件的缓存,保持分页状态(适用于定时刷新) */
+ refreshSoft,
+ /** 新增后刷新:回到第一页并清空分页缓存(适用于新增数据后) */
+ refreshCreate,
+ /** 更新后刷新:保持当前页,仅清空当前搜索缓存(适用于更新数据后) */
+ refreshUpdate,
+ /** 删除后刷新:智能处理页码,避免空页面(适用于删除数据后) */
+ refreshRemove,
+
+ // 缓存控制
+ /** 缓存统计信息 */
+ cacheInfo,
+ /** 清除缓存,根据不同的业务场景选择性地清理缓存: */
+ clearCache,
+ // 支持4种清理策略
+ // clearCache(CacheInvalidationStrategy.CLEAR_ALL, '手动刷新') // 清空所有缓存
+ // clearCache(CacheInvalidationStrategy.CLEAR_CURRENT, '搜索数据') // 只清空当前搜索条件的缓存
+ // clearCache(CacheInvalidationStrategy.CLEAR_PAGINATION, '新增数据') // 清空分页相关缓存
+ // clearCache(CacheInvalidationStrategy.KEEP_ALL, '保持缓存') // 不清理任何缓存
+ /** 清理已过期的缓存条目,释放内存空间 */
+ clearExpiredCache,
+
+ // 请求控制
+ /** 取消当前请求 */
+ cancelRequest,
+
+ // 列配置 (如果提供了 columnsFactory)
+ ...(columnConfig && {
+ /** 表格列配置 */
+ columns,
+ /** 列显示控制 */
+ columnChecks,
+ /** 新增列 */
+ addColumn: columnConfig.addColumn,
+ /** 删除列 */
+ removeColumn: columnConfig.removeColumn,
+ /** 切换列显示状态 */
+ toggleColumn: columnConfig.toggleColumn,
+ /** 更新列配置 */
+ updateColumn: columnConfig.updateColumn,
+ /** 批量更新列配置 */
+ batchUpdateColumns: columnConfig.batchUpdateColumns,
+ /** 重新排序列 */
+ reorderColumns: columnConfig.reorderColumns,
+ /** 获取指定列配置 */
+ getColumnConfig: columnConfig.getColumnConfig,
+ /** 获取所有列配置 */
+ getAllColumns: columnConfig.getAllColumns,
+ /** 重置所有列配置到默认状态 */
+ resetColumns: columnConfig.resetColumns
+ })
+ }
}
// 重新导出类型和枚举,方便使用
diff --git a/src/hooks/core/useTableColumns.ts b/src/hooks/core/useTableColumns.ts
index 84b6e13..9ad8592 100644
--- a/src/hooks/core/useTableColumns.ts
+++ b/src/hooks/core/useTableColumns.ts
@@ -40,273 +40,286 @@ import type { ColumnOption } from '@/types/component'
* 特殊列类型
*/
const SPECIAL_COLUMNS: Record = {
- selection: { prop: '__selection__', label: $t('table.column.selection') },
- expand: { prop: '__expand__', label: $t('table.column.expand') },
- index: { prop: '__index__', label: $t('table.column.index') }
+ selection: { prop: '__selection__', label: $t('table.column.selection') },
+ expand: { prop: '__expand__', label: $t('table.column.expand') },
+ index: { prop: '__index__', label: $t('table.column.index') }
}
/**
* 获取列的唯一标识
*/
export const getColumnKey = (col: ColumnOption) =>
- SPECIAL_COLUMNS[col.type as keyof typeof SPECIAL_COLUMNS]?.prop ?? (col.prop as string)
+ SPECIAL_COLUMNS[col.type as keyof typeof SPECIAL_COLUMNS]?.prop ?? (col.prop as string)
/**
* 获取列的显示状态
* 优先使用 visible 字段,如果不存在则使用 checked 字段
*/
export const getColumnVisibility = (col: ColumnOption): boolean => {
- // visible 优先级高于 checked
- if (col.visible !== undefined) {
- return col.visible
- }
- // 如果 visible 未定义,使用 checked,默认为 true
- return col.checked ?? true
+ // visible 优先级高于 checked
+ if (col.visible !== undefined) {
+ return col.visible
+ }
+ // 如果 visible 未定义,使用 checked,默认为 true
+ return col.checked ?? true
}
/**
* 获取列的检查状态
*/
export const getColumnChecks = (columns: ColumnOption[]) =>
- columns.map((col) => {
- const special = col.type && SPECIAL_COLUMNS[col.type]
- const visibility = getColumnVisibility(col)
+ columns.map((col) => {
+ const special = col.type && SPECIAL_COLUMNS[col.type]
+ const visibility = getColumnVisibility(col)
- if (special) {
- return { ...col, prop: special.prop, label: special.label, checked: true, visible: true }
- }
- return { ...col, checked: visibility, visible: visibility }
- })
+ if (special) {
+ return {
+ ...col,
+ prop: special.prop,
+ label: special.label,
+ checked: true,
+ visible: true
+ }
+ }
+ return { ...col, checked: visibility, visible: visibility }
+ })
/**
* 动态列配置接口
*/
export interface DynamicColumnConfig {
- /**
- * 新增列(支持单个或批量)
- * @param column 列配置或列配置数组
- * @param index 可选的插入位置,默认末尾(批量时为第一个列的位置)
- */
- addColumn: (column: ColumnOption | ColumnOption[], index?: number) => void
- /**
- * 删除列(支持单个或批量)
- * @param prop 列的唯一标识或标识数组
- */
- removeColumn: (prop: string | string[]) => void
- /**
- * 切换列显示状态(支持单个或批量)
- * @param prop 列的唯一标识或标识数组
- * @param visible 可选的显示状态,默认取反
- */
- toggleColumn: (prop: string | string[], visible?: boolean) => void
+ /**
+ * 新增列(支持单个或批量)
+ * @param column 列配置或列配置数组
+ * @param index 可选的插入位置,默认末尾(批量时为第一个列的位置)
+ */
+ addColumn: (column: ColumnOption | ColumnOption[], index?: number) => void
+ /**
+ * 删除列(支持单个或批量)
+ * @param prop 列的唯一标识或标识数组
+ */
+ removeColumn: (prop: string | string[]) => void
+ /**
+ * 切换列显示状态(支持单个或批量)
+ * @param prop 列的唯一标识或标识数组
+ * @param visible 可选的显示状态,默认取反
+ */
+ toggleColumn: (prop: string | string[], visible?: boolean) => void
- /**
- * 更新列(支持单个或批量)
- * @param prop 列的唯一标识或更新配置数组
- * @param updates 列配置更新(当 prop 为字符串时使用)
- */
- updateColumn: (
- prop: string | Array<{ prop: string; updates: Partial> }>,
- updates?: Partial>
- ) => void
- /**
- * 批量更新列(兼容旧版本,推荐使用 updateColumn 的数组模式)
- * @param updates 列更新配置
- * @deprecated 推荐使用 updateColumn 的数组模式
- */
- batchUpdateColumns: (updates: Array<{ prop: string; updates: Partial> }>) => void
- /**
- * 重新排序列
- * @param fromIndex 源索引
- * @param toIndex 目标索引
- */
- reorderColumns: (fromIndex: number, toIndex: number) => void
- /**
- * 获取列配置
- * @param prop 列的唯一标识
- * @returns 列配置
- */
- getColumnConfig: (prop: string) => ColumnOption | undefined
- /**
- * 获取所有列配置
- * @returns 所有列配置
- */
- getAllColumns: () => ColumnOption[]
- /**
- * 重置所有列
- */
- resetColumns: () => void
+ /**
+ * 更新列(支持单个或批量)
+ * @param prop 列的唯一标识或更新配置数组
+ * @param updates 列配置更新(当 prop 为字符串时使用)
+ */
+ updateColumn: (
+ prop: string | Array<{ prop: string; updates: Partial> }>,
+ updates?: Partial>
+ ) => void
+ /**
+ * 批量更新列(兼容旧版本,推荐使用 updateColumn 的数组模式)
+ * @param updates 列更新配置
+ * @deprecated 推荐使用 updateColumn 的数组模式
+ */
+ batchUpdateColumns: (
+ updates: Array<{ prop: string; updates: Partial> }>
+ ) => void
+ /**
+ * 重新排序列
+ * @param fromIndex 源索引
+ * @param toIndex 目标索引
+ */
+ reorderColumns: (fromIndex: number, toIndex: number) => void
+ /**
+ * 获取列配置
+ * @param prop 列的唯一标识
+ * @returns 列配置
+ */
+ getColumnConfig: (prop: string) => ColumnOption | undefined
+ /**
+ * 获取所有列配置
+ * @returns 所有列配置
+ */
+ getAllColumns: () => ColumnOption[]
+ /**
+ * 重置所有列
+ */
+ resetColumns: () => void
}
export function useTableColumns(
- columnsFactory: () => ColumnOption[]
+ columnsFactory: () => ColumnOption[]
): {
- columns: any
- columnChecks: any
+ columns: any
+ columnChecks: any
} & DynamicColumnConfig {
- const dynamicColumns = ref[]>(columnsFactory())
- const columnChecks = ref[]>(getColumnChecks(dynamicColumns.value))
+ const dynamicColumns = ref[]>(columnsFactory())
+ const columnChecks = ref[]>(getColumnChecks(dynamicColumns.value))
- // 当 dynamicColumns 变动时,重新生成 columnChecks 且保留已存在的显示状态
- watch(
- dynamicColumns,
- (newCols) => {
- const visibilityMap = new Map(
- columnChecks.value.map((c) => [getColumnKey(c), getColumnVisibility(c)])
- )
- const newChecks = getColumnChecks(newCols).map((c) => {
- const key = getColumnKey(c)
- const visibility = visibilityMap.has(key) ? visibilityMap.get(key) : getColumnVisibility(c)
- return {
- ...c,
- checked: visibility,
- visible: visibility
- }
- })
- columnChecks.value = newChecks
- },
- { deep: true }
- )
+ // 当 dynamicColumns 变动时,重新生成 columnChecks 且保留已存在的显示状态
+ watch(
+ dynamicColumns,
+ (newCols) => {
+ const visibilityMap = new Map(
+ columnChecks.value.map((c) => [getColumnKey(c), getColumnVisibility(c)])
+ )
+ const newChecks = getColumnChecks(newCols).map((c) => {
+ const key = getColumnKey(c)
+ const visibility = visibilityMap.has(key)
+ ? visibilityMap.get(key)
+ : getColumnVisibility(c)
+ return {
+ ...c,
+ checked: visibility,
+ visible: visibility
+ }
+ })
+ columnChecks.value = newChecks
+ },
+ { deep: true }
+ )
- // 当前显示列(基于 columnChecks 的 checked 或 visible)
- const columns = computed(() => {
- const colMap = new Map(dynamicColumns.value.map((c) => [getColumnKey(c), c]))
- return columnChecks.value
- .filter((c) => getColumnVisibility(c))
- .map((c) => colMap.get(getColumnKey(c)))
- .filter(Boolean) as ColumnOption[]
- })
+ // 当前显示列(基于 columnChecks 的 checked 或 visible)
+ const columns = computed(() => {
+ const colMap = new Map(dynamicColumns.value.map((c) => [getColumnKey(c), c]))
+ return columnChecks.value
+ .filter((c) => getColumnVisibility(c))
+ .map((c) => colMap.get(getColumnKey(c)))
+ .filter(Boolean) as ColumnOption[]
+ })
- // 支持 updater 返回新数组或直接在传入数组上 mutate
- const setDynamicColumns = (updater: (cols: ColumnOption[]) => void | ColumnOption[]) => {
- const copy = [...dynamicColumns.value]
- const result = updater(copy)
- dynamicColumns.value = Array.isArray(result) ? result : copy
- }
+ // 支持 updater 返回新数组或直接在传入数组上 mutate
+ const setDynamicColumns = (updater: (cols: ColumnOption[]) => void | ColumnOption[]) => {
+ const copy = [...dynamicColumns.value]
+ const result = updater(copy)
+ dynamicColumns.value = Array.isArray(result) ? result : copy
+ }
- return {
- columns,
- columnChecks,
+ return {
+ columns,
+ columnChecks,
- /**
- * 新增列(支持单个或批量)
- */
- addColumn: (column: ColumnOption | ColumnOption[], index?: number) =>
- setDynamicColumns((cols) => {
- const next = [...cols]
- const columnsToAdd = Array.isArray(column) ? column : [column]
- const insertIndex =
- typeof index === 'number' && index >= 0 && index <= next.length ? index : next.length
+ /**
+ * 新增列(支持单个或批量)
+ */
+ addColumn: (column: ColumnOption | ColumnOption[], index?: number) =>
+ setDynamicColumns((cols) => {
+ const next = [...cols]
+ const columnsToAdd = Array.isArray(column) ? column : [column]
+ const insertIndex =
+ typeof index === 'number' && index >= 0 && index <= next.length
+ ? index
+ : next.length
- // 批量插入
- next.splice(insertIndex, 0, ...columnsToAdd)
- return next
- }),
+ // 批量插入
+ next.splice(insertIndex, 0, ...columnsToAdd)
+ return next
+ }),
- /**
- * 删除列(支持单个或批量)
- */
- removeColumn: (prop: string | string[]) =>
- setDynamicColumns((cols) => {
- const propsToRemove = Array.isArray(prop) ? prop : [prop]
- return cols.filter((c) => !propsToRemove.includes(getColumnKey(c)))
- }),
+ /**
+ * 删除列(支持单个或批量)
+ */
+ removeColumn: (prop: string | string[]) =>
+ setDynamicColumns((cols) => {
+ const propsToRemove = Array.isArray(prop) ? prop : [prop]
+ return cols.filter((c) => !propsToRemove.includes(getColumnKey(c)))
+ }),
- /**
- * 更新列(支持单个或批量)
- */
- updateColumn: (
- prop: string | Array<{ prop: string; updates: Partial> }>,
- updates?: Partial>
- ) => {
- // 批量模式:prop 是数组
- if (Array.isArray(prop)) {
- setDynamicColumns((cols) => {
- const map = new Map(prop.map((u) => [u.prop, u.updates]))
- return cols.map((c) => {
- const key = getColumnKey(c)
- const upd = map.get(key)
- return upd ? { ...c, ...upd } : c
- })
- })
- }
- // 单个模式:prop 是字符串
- else if (updates) {
- setDynamicColumns((cols) =>
- cols.map((c) => (getColumnKey(c) === prop ? { ...c, ...updates } : c))
- )
- }
- },
+ /**
+ * 更新列(支持单个或批量)
+ */
+ updateColumn: (
+ prop: string | Array<{ prop: string; updates: Partial> }>,
+ updates?: Partial>
+ ) => {
+ // 批量模式:prop 是数组
+ if (Array.isArray(prop)) {
+ setDynamicColumns((cols) => {
+ const map = new Map(prop.map((u) => [u.prop, u.updates]))
+ return cols.map((c) => {
+ const key = getColumnKey(c)
+ const upd = map.get(key)
+ return upd ? { ...c, ...upd } : c
+ })
+ })
+ }
+ // 单个模式:prop 是字符串
+ else if (updates) {
+ setDynamicColumns((cols) =>
+ cols.map((c) => (getColumnKey(c) === prop ? { ...c, ...updates } : c))
+ )
+ }
+ },
- /**
- * 切换列显示状态(支持单个或批量)
- */
- toggleColumn: (prop: string | string[], visible?: boolean) => {
- const propsToToggle = Array.isArray(prop) ? prop : [prop]
- const next = [...columnChecks.value]
+ /**
+ * 切换列显示状态(支持单个或批量)
+ */
+ toggleColumn: (prop: string | string[], visible?: boolean) => {
+ const propsToToggle = Array.isArray(prop) ? prop : [prop]
+ const next = [...columnChecks.value]
- propsToToggle.forEach((p) => {
- const i = next.findIndex((c) => getColumnKey(c) === p)
- if (i > -1) {
- const currentVisibility = getColumnVisibility(next[i])
- const newVisibility = visible ?? !currentVisibility
- // 同时更新 checked 和 visible 以保持兼容性
- next[i] = { ...next[i], checked: newVisibility, visible: newVisibility }
- }
- })
+ propsToToggle.forEach((p) => {
+ const i = next.findIndex((c) => getColumnKey(c) === p)
+ if (i > -1) {
+ const currentVisibility = getColumnVisibility(next[i])
+ const newVisibility = visible ?? !currentVisibility
+ // 同时更新 checked 和 visible 以保持兼容性
+ next[i] = { ...next[i], checked: newVisibility, visible: newVisibility }
+ }
+ })
- columnChecks.value = next
- },
+ columnChecks.value = next
+ },
- /**
- * 重置所有列
- */
- resetColumns: () => {
- dynamicColumns.value = columnsFactory()
- },
+ /**
+ * 重置所有列
+ */
+ resetColumns: () => {
+ dynamicColumns.value = columnsFactory()
+ },
- /**
- * 批量更新列(兼容旧版本)
- * @deprecated 推荐使用 updateColumn 的数组模式
- */
- batchUpdateColumns: (updates) =>
- setDynamicColumns((cols) => {
- const map = new Map(updates.map((u) => [u.prop, u.updates]))
- return cols.map((c) => {
- const key = getColumnKey(c)
- const upd = map.get(key)
- return upd ? { ...c, ...upd } : c
- })
- }),
+ /**
+ * 批量更新列(兼容旧版本)
+ * @deprecated 推荐使用 updateColumn 的数组模式
+ */
+ batchUpdateColumns: (updates) =>
+ setDynamicColumns((cols) => {
+ const map = new Map(updates.map((u) => [u.prop, u.updates]))
+ return cols.map((c) => {
+ const key = getColumnKey(c)
+ const upd = map.get(key)
+ return upd ? { ...c, ...upd } : c
+ })
+ }),
- /**
- * 重新排序列
- */
- reorderColumns: (fromIndex: number, toIndex: number) =>
- setDynamicColumns((cols) => {
- if (
- fromIndex < 0 ||
- fromIndex >= cols.length ||
- toIndex < 0 ||
- toIndex >= cols.length ||
- fromIndex === toIndex
- ) {
- return cols
- }
- const next = [...cols]
- const [moved] = next.splice(fromIndex, 1)
- next.splice(toIndex, 0, moved)
- return next
- }),
+ /**
+ * 重新排序列
+ */
+ reorderColumns: (fromIndex: number, toIndex: number) =>
+ setDynamicColumns((cols) => {
+ if (
+ fromIndex < 0 ||
+ fromIndex >= cols.length ||
+ toIndex < 0 ||
+ toIndex >= cols.length ||
+ fromIndex === toIndex
+ ) {
+ return cols
+ }
+ const next = [...cols]
+ const [moved] = next.splice(fromIndex, 1)
+ next.splice(toIndex, 0, moved)
+ return next
+ }),
- /**
- * 获取列配置
- */
- getColumnConfig: (prop: string) => dynamicColumns.value.find((c) => getColumnKey(c) === prop),
+ /**
+ * 获取列配置
+ */
+ getColumnConfig: (prop: string) =>
+ dynamicColumns.value.find((c) => getColumnKey(c) === prop),
- /**
- * 获取所有列配置
- */
- getAllColumns: () => [...dynamicColumns.value]
- }
+ /**
+ * 获取所有列配置
+ */
+ getAllColumns: () => [...dynamicColumns.value]
+ }
}
diff --git a/src/hooks/core/useTableHeight.ts b/src/hooks/core/useTableHeight.ts
index 8fdf6da..7e2d068 100644
--- a/src/hooks/core/useTableHeight.ts
+++ b/src/hooks/core/useTableHeight.ts
@@ -21,64 +21,67 @@ import { computed, type Ref } from 'vue'
* 表格高度计算器配置接口
*/
interface TableHeightOptions {
- /** 是否显示表格头部 */
- showTableHeader: Ref
- /** 分页器高度 */
- paginationHeight: Ref
- /** 表格头部高度 */
- tableHeaderHeight: Ref
- /** 分页器间距 */
- paginationSpacing: Ref
+ /** 是否显示表格头部 */
+ showTableHeader: Ref
+ /** 分页器高度 */
+ paginationHeight: Ref
+ /** 表格头部高度 */
+ tableHeaderHeight: Ref
+ /** 分页器间距 */
+ paginationSpacing: Ref
}
/**
* 表格高度计算器类
*/
class TableHeightCalculator {
- // 常量配置
- private static readonly DEFAULT_TABLE_HEADER_HEIGHT = 44
- private static readonly TABLE_HEADER_SPACING = 12
+ // 常量配置
+ private static readonly DEFAULT_TABLE_HEADER_HEIGHT = 44
+ private static readonly TABLE_HEADER_SPACING = 12
- constructor(private options: TableHeightOptions) {}
+ constructor(private options: TableHeightOptions) {}
- /**
- * 计算容器高度
- */
- calculate(): { height: string } {
- const offset = this.calculateOffset()
- return {
- height: offset === 0 ? '100%' : `calc(100% - ${offset}px)`
- }
- }
+ /**
+ * 计算容器高度
+ */
+ calculate(): { height: string } {
+ const offset = this.calculateOffset()
+ return {
+ height: offset === 0 ? '100%' : `calc(100% - ${offset}px)`
+ }
+ }
- /**
- * 计算偏移量
- */
- private calculateOffset(): number {
- if (!this.options.showTableHeader.value) {
- return this.calculatePaginationOffset()
- }
+ /**
+ * 计算偏移量
+ */
+ private calculateOffset(): number {
+ if (!this.options.showTableHeader.value) {
+ return this.calculatePaginationOffset()
+ }
- const headerHeight = this.getHeaderHeight()
- const paginationOffset = this.calculatePaginationOffset()
+ const headerHeight = this.getHeaderHeight()
+ const paginationOffset = this.calculatePaginationOffset()
- return headerHeight + paginationOffset + TableHeightCalculator.TABLE_HEADER_SPACING
- }
+ return headerHeight + paginationOffset + TableHeightCalculator.TABLE_HEADER_SPACING
+ }
- /**
- * 获取表格头部高度
- */
- private getHeaderHeight(): number {
- return this.options.tableHeaderHeight.value || TableHeightCalculator.DEFAULT_TABLE_HEADER_HEIGHT
- }
+ /**
+ * 获取表格头部高度
+ */
+ private getHeaderHeight(): number {
+ return (
+ this.options.tableHeaderHeight.value ||
+ TableHeightCalculator.DEFAULT_TABLE_HEADER_HEIGHT
+ )
+ }
- /**
- * 计算分页器偏移量
- */
- private calculatePaginationOffset(): number {
- const { paginationHeight, paginationSpacing } = this.options
- return paginationHeight.value === 0 ? 0 : paginationHeight.value + paginationSpacing.value
- }
+ /**
+ * 计算分页器偏移量
+ */
+ private calculatePaginationOffset(): number {
+ const { paginationHeight, paginationSpacing } = this.options
+ return paginationHeight.value === 0 ? 0 : paginationHeight.value + paginationSpacing.value
+ }
}
/**
@@ -93,13 +96,13 @@ class TableHeightCalculator {
* @returns 容器高度计算结果
*/
export function useTableHeight(options: TableHeightOptions) {
- const containerHeight = computed(() => {
- const calculator = new TableHeightCalculator(options)
- return calculator.calculate()
- })
+ const containerHeight = computed(() => {
+ const calculator = new TableHeightCalculator(options)
+ return calculator.calculate()
+ })
- return {
- /** 容器高度样式对象 */
- containerHeight
- }
+ return {
+ /** 容器高度样式对象 */
+ containerHeight
+ }
}
diff --git a/src/hooks/core/useTheme.ts b/src/hooks/core/useTheme.ts
index 187c3e0..a6a9295 100644
--- a/src/hooks/core/useTheme.ts
+++ b/src/hooks/core/useTheme.ts
@@ -40,135 +40,138 @@ import { usePreferredDark } from '@vueuse/core'
import { watch } from 'vue'
export function useTheme() {
- const settingStore = useSettingStore()
+ const settingStore = useSettingStore()
- // 禁用过渡效果
- const disableTransitions = () => {
- const style = document.createElement('style')
- style.setAttribute('id', 'disable-transitions')
- style.textContent = '* { transition: none !important; }'
- document.head.appendChild(style)
- }
+ // 禁用过渡效果
+ const disableTransitions = () => {
+ const style = document.createElement('style')
+ style.setAttribute('id', 'disable-transitions')
+ style.textContent = '* { transition: none !important; }'
+ document.head.appendChild(style)
+ }
- // 启用过渡效果
- const enableTransitions = () => {
- const style = document.getElementById('disable-transitions')
- if (style) {
- style.remove()
- }
- }
+ // 启用过渡效果
+ const enableTransitions = () => {
+ const style = document.getElementById('disable-transitions')
+ if (style) {
+ style.remove()
+ }
+ }
- // 设置系统主题
- const setSystemTheme = (theme: SystemThemeEnum, themeMode?: SystemThemeEnum) => {
- // 临时禁用过渡效果
- disableTransitions()
+ // 设置系统主题
+ const setSystemTheme = (theme: SystemThemeEnum, themeMode?: SystemThemeEnum) => {
+ // 临时禁用过渡效果
+ disableTransitions()
- const el = document.getElementsByTagName('html')[0]
- const isDark = theme === SystemThemeEnum.DARK
+ const el = document.getElementsByTagName('html')[0]
+ const isDark = theme === SystemThemeEnum.DARK
- if (!themeMode) {
- themeMode = theme
- }
+ if (!themeMode) {
+ themeMode = theme
+ }
- const currentTheme = AppConfig.systemThemeStyles[theme as keyof SystemThemeTypes]
+ const currentTheme = AppConfig.systemThemeStyles[theme as keyof SystemThemeTypes]
- if (currentTheme) {
- el.setAttribute('class', currentTheme.className)
- }
+ if (currentTheme) {
+ el.setAttribute('class', currentTheme.className)
+ }
- // 设置按钮颜色加深或变浅
- const primary = settingStore.systemThemeColor
+ // 设置按钮颜色加深或变浅
+ const primary = settingStore.systemThemeColor
- for (let i = 1; i <= 9; i++) {
- document.documentElement.style.setProperty(
- `--el-color-primary-light-${i}`,
- isDark ? `${getDarkColor(primary, i / 10)}` : `${getLightColor(primary, i / 10)}`
- )
- }
+ for (let i = 1; i <= 9; i++) {
+ document.documentElement.style.setProperty(
+ `--el-color-primary-light-${i}`,
+ isDark ? `${getDarkColor(primary, i / 10)}` : `${getLightColor(primary, i / 10)}`
+ )
+ }
- // 更新store中的主题设置
- settingStore.setGlopTheme(theme, themeMode)
+ // 更新store中的主题设置
+ settingStore.setGlopTheme(theme, themeMode)
- // 使用 requestAnimationFrame 确保在下一帧恢复过渡效果
- requestAnimationFrame(() => {
- requestAnimationFrame(() => {
- enableTransitions()
- })
- })
- }
+ // 使用 requestAnimationFrame 确保在下一帧恢复过渡效果
+ requestAnimationFrame(() => {
+ requestAnimationFrame(() => {
+ enableTransitions()
+ })
+ })
+ }
- // 使用 VueUse 的 usePreferredDark 检测系统主题偏好
- const prefersDark = usePreferredDark()
+ // 使用 VueUse 的 usePreferredDark 检测系统主题偏好
+ const prefersDark = usePreferredDark()
- // 自动设置系统主题
- const setSystemAutoTheme = () => {
- const theme = prefersDark.value ? SystemThemeEnum.DARK : SystemThemeEnum.LIGHT
- setSystemTheme(theme, SystemThemeEnum.AUTO)
- }
+ // 自动设置系统主题
+ const setSystemAutoTheme = () => {
+ const theme = prefersDark.value ? SystemThemeEnum.DARK : SystemThemeEnum.LIGHT
+ setSystemTheme(theme, SystemThemeEnum.AUTO)
+ }
- // 切换主题
- const switchThemeStyles = (theme: SystemThemeEnum) => {
- if (theme === SystemThemeEnum.AUTO) {
- setSystemAutoTheme()
- } else {
- setSystemTheme(theme)
- }
- }
+ // 切换主题
+ const switchThemeStyles = (theme: SystemThemeEnum) => {
+ if (theme === SystemThemeEnum.AUTO) {
+ setSystemAutoTheme()
+ } else {
+ setSystemTheme(theme)
+ }
+ }
- return {
- setSystemTheme,
- setSystemAutoTheme,
- switchThemeStyles,
- prefersDark
- }
+ return {
+ setSystemTheme,
+ setSystemAutoTheme,
+ switchThemeStyles,
+ prefersDark
+ }
}
/**
* 初始化主题系统
*/
export function initializeTheme() {
- const settingStore = useSettingStore()
- const prefersDark = usePreferredDark()
+ const settingStore = useSettingStore()
+ const prefersDark = usePreferredDark()
- // 根据系统偏好应用主题
- const applyThemeByMode = () => {
- const el = document.getElementsByTagName('html')[0]
- let actualTheme = settingStore.systemThemeType
+ // 根据系统偏好应用主题
+ const applyThemeByMode = () => {
+ const el = document.getElementsByTagName('html')[0]
+ let actualTheme = settingStore.systemThemeType
- // 如果是 AUTO 模式,检测系统偏好
- if (settingStore.systemThemeMode === SystemThemeEnum.AUTO) {
- actualTheme = prefersDark.value ? SystemThemeEnum.DARK : SystemThemeEnum.LIGHT
- // 更新实际应用的主题类型
- settingStore.systemThemeType = actualTheme
- }
+ // 如果是 AUTO 模式,检测系统偏好
+ if (settingStore.systemThemeMode === SystemThemeEnum.AUTO) {
+ actualTheme = prefersDark.value ? SystemThemeEnum.DARK : SystemThemeEnum.LIGHT
+ // 更新实际应用的主题类型
+ settingStore.systemThemeType = actualTheme
+ }
- // 设置主题 class
- const currentTheme = AppConfig.systemThemeStyles[actualTheme as keyof SystemThemeTypes]
- if (currentTheme) {
- el.setAttribute('class', currentTheme.className)
- }
+ // 设置主题 class
+ const currentTheme = AppConfig.systemThemeStyles[actualTheme as keyof SystemThemeTypes]
+ if (currentTheme) {
+ el.setAttribute('class', currentTheme.className)
+ }
- // 设置主题颜色
- setElementThemeColor(settingStore.systemThemeColor)
+ // 设置主题颜色
+ setElementThemeColor(settingStore.systemThemeColor)
- // 设置圆角
- document.documentElement.style.setProperty('--custom-radius', `${settingStore.customRadius}rem`)
- }
+ // 设置圆角
+ document.documentElement.style.setProperty(
+ '--custom-radius',
+ `${settingStore.customRadius}rem`
+ )
+ }
- // 应用主题
- applyThemeByMode()
+ // 应用主题
+ applyThemeByMode()
- // 如果是 AUTO 模式,监听系统主题变化(使用 VueUse 的响应式特性)
- if (settingStore.systemThemeMode === SystemThemeEnum.AUTO) {
- watch(
- prefersDark,
- () => {
- // 只有在 AUTO 模式下才响应系统主题变化
- if (settingStore.systemThemeMode === SystemThemeEnum.AUTO) {
- applyThemeByMode()
- }
- },
- { immediate: false }
- )
- }
+ // 如果是 AUTO 模式,监听系统主题变化(使用 VueUse 的响应式特性)
+ if (settingStore.systemThemeMode === SystemThemeEnum.AUTO) {
+ watch(
+ prefersDark,
+ () => {
+ // 只有在 AUTO 模式下才响应系统主题变化
+ if (settingStore.systemThemeMode === SystemThemeEnum.AUTO) {
+ applyThemeByMode()
+ }
+ },
+ { immediate: false }
+ )
+ }
}
diff --git a/src/locales/index.ts b/src/locales/index.ts
index 36c2648..9263f5a 100644
--- a/src/locales/index.ts
+++ b/src/locales/index.ts
@@ -40,8 +40,8 @@ const storageKeyManager = new StorageKeyManager()
* 语言消息对象
*/
const messages = {
- [LanguageEnum.EN]: enMessages,
- [LanguageEnum.ZH]: zhMessages
+ [LanguageEnum.EN]: enMessages,
+ [LanguageEnum.ZH]: zhMessages
}
/**
@@ -49,8 +49,8 @@ const messages = {
* 用于语言切换下拉框
*/
export const languageOptions = [
- { value: LanguageEnum.ZH, label: '简体中文' },
- { value: LanguageEnum.EN, label: 'English' }
+ { value: LanguageEnum.ZH, label: '简体中文' },
+ { value: LanguageEnum.EN, label: 'English' }
]
/**
@@ -58,48 +58,48 @@ export const languageOptions = [
* @returns 语言设置,如果获取失败则返回默认语言
*/
const getDefaultLanguage = (): LanguageEnum => {
- // 尝试从版本化的存储中获取语言设置
- try {
- const storageKey = storageKeyManager.getStorageKey('user')
- const userStore = localStorage.getItem(storageKey)
+ // 尝试从版本化的存储中获取语言设置
+ try {
+ const storageKey = storageKeyManager.getStorageKey('user')
+ const userStore = localStorage.getItem(storageKey)
- if (userStore) {
- const { language } = JSON.parse(userStore)
- if (language && Object.values(LanguageEnum).includes(language)) {
- return language
- }
- }
- } catch (error) {
- console.warn('[i18n] 从版本化存储获取语言设置失败:', error)
- }
+ if (userStore) {
+ const { language } = JSON.parse(userStore)
+ if (language && Object.values(LanguageEnum).includes(language)) {
+ return language
+ }
+ }
+ } catch (error) {
+ console.warn('[i18n] 从版本化存储获取语言设置失败:', error)
+ }
- // 尝试从系统存储中获取语言设置
- try {
- const sys = getSystemStorage()
- if (sys) {
- const { user } = JSON.parse(sys)
- if (user?.language && Object.values(LanguageEnum).includes(user.language)) {
- return user.language
- }
- }
- } catch (error) {
- console.warn('[i18n] 从系统存储获取语言设置失败:', error)
- }
+ // 尝试从系统存储中获取语言设置
+ try {
+ const sys = getSystemStorage()
+ if (sys) {
+ const { user } = JSON.parse(sys)
+ if (user?.language && Object.values(LanguageEnum).includes(user.language)) {
+ return user.language
+ }
+ }
+ } catch (error) {
+ console.warn('[i18n] 从系统存储获取语言设置失败:', error)
+ }
- // 返回默认语言
- console.debug('[i18n] 使用默认语言:', LanguageEnum.ZH)
- return LanguageEnum.ZH
+ // 返回默认语言
+ console.debug('[i18n] 使用默认语言:', LanguageEnum.ZH)
+ return LanguageEnum.ZH
}
/**
* i18n 配置选项
*/
const i18nOptions: I18nOptions = {
- locale: getDefaultLanguage(),
- legacy: false,
- globalInjection: true,
- fallbackLocale: LanguageEnum.ZH,
- messages
+ locale: getDefaultLanguage(),
+ legacy: false,
+ globalInjection: true,
+ fallbackLocale: LanguageEnum.ZH,
+ messages
}
/**
@@ -111,7 +111,7 @@ const i18n: I18n = createI18n(i18nOptions)
* 翻译函数类型
*/
interface Translation {
- (key: string): string
+ (key: string): string
}
/**
diff --git a/src/locales/langs/en.json b/src/locales/langs/en.json
index 51e196b..76c8225 100644
--- a/src/locales/langs/en.json
+++ b/src/locales/langs/en.json
@@ -1,296 +1,275 @@
{
- "httpMsg": {
- "unauthorized": "Unauthorized access, please login again",
- "forbidden": "Access to this resource is forbidden",
- "notFound": "The requested resource does not exist",
- "methodNotAllowed": "Request method not allowed",
- "requestTimeout": "Request timeout, please try again later",
- "internalServerError": "Internal server error, please try again later",
- "badGateway": "Bad gateway error, please try again later",
- "serviceUnavailable": "Service temporarily unavailable, please try again later",
- "gatewayTimeout": "Gateway timeout, please try again later",
- "requestCancelled": "Request cancelled",
- "networkError": "Network connection error, please check your connection",
- "requestFailed": "Request failed",
- "requestConfigError": "Request configuration error"
- },
- "topBar": {
- "search": {
- "title": "Search"
- },
- "user": {
- "userCenter": "User center",
- "docs": "Document",
- "github": "Github",
- "lockScreen": "Lock screen",
- "logout": "Log out"
- },
- "guide": {
- "title": "Click here to view",
- "theme": "Theme style",
- "menu": "Open top menu",
- "description": "More configurations"
- }
- },
- "common": {
- "tips": "Prompt",
- "cancel": "Cancel",
- "confirm": "Confirm",
- "logOutTips": "Do you want to log out?"
- },
- "search": {
- "placeholder": "Search page",
- "historyTitle": "Search history",
- "switchKeydown": "Navigate",
- "selectKeydown": "Select",
- "exitKeydown": "Close"
- },
- "setting": {
- "menuType": {
- "title": "Menu Layout",
- "list": [
- "Vertical",
- "Horizontal",
- "Mixed",
- "Dual"
- ]
- },
- "theme": {
- "title": "Theme Style",
- "list": [
- "Light",
- "Dark",
- "System"
- ]
- },
- "menu": {
- "title": "Menu Style"
- },
- "color": {
- "title": "Theme Color"
- },
- "box": {
- "title": "Box Style",
- "list": [
- "Border",
- "Shadow"
- ]
- },
- "container": {
- "title": "Container Width",
- "list": [
- "Full",
- "Boxed"
- ]
- },
- "basics": {
- "title": "Basic Config",
- "list": {
- "multiTab": "Show work tab",
- "accordion": "Sidebar opens accordion",
- "collapseSidebar": "Show sidebar button",
- "reloadPage": "Show reload page button",
- "fastEnter": "Show fast enter",
- "breadcrumb": "Show crumb navigation",
- "language": "Show multilingual selection",
- "progressBar": "Show top progress bar",
- "weakMode": "Color Weakness Mode",
- "watermark": "Global watermark",
- "menuWidth": "Menu width",
- "tabStyle": "Tab style",
- "pageTransition": "Page animation",
- "borderRadius": "Custom radius"
- }
- },
- "tabStyle": {
- "default": "Default",
- "card": "Card",
- "google": "Chrome"
- },
- "transition": {
- "list": {
- "none": "None",
- "fade": "Fade",
- "slideLeft": "Slide Left",
- "slideBottom": "Slide Bottom",
- "slideTop": "Slide Top"
- }
- },
- "actions": {
- "resetConfig": "Reset Config",
- "copyConfig": "Copy Config",
- "copySuccess": "Configuration copied to clipboard, paste it into src/config/setting.ts file",
- "copyFailed": "Copy failed, please try again",
- "resetFailed": "Reset failed, please refresh the page and try again"
- }
- },
- "notice": {
- "title": "Notice",
- "btnRead": "Mark as read",
- "bar": [
- "Notice",
- "Message",
- "Todo"
- ],
- "text": [
- "No"
- ],
- "viewAll": "View all"
- },
- "worktab": {
- "btn": {
- "refresh": "Refresh",
- "fixed": "Fixed",
- "unfixed": "Unfixed",
- "closeLeft": "Close left",
- "closeRight": "Close right",
- "closeOther": "Close other",
- "closeAll": "Close all"
- }
- },
- "login": {
- "leftView": {
- "title": "A backend system of beauty and efficiency",
- "subTitle": "A sleek and practical interface for a great user experience"
- },
- "title": "Welcome back",
- "subTitle": "Please enter your account and password to login",
- "roles": {
- "super": "Super Admin",
- "admin": "Admin",
- "user": "User"
- },
- "placeholder": {
- "username": "Please enter your account",
- "password": "Please enter your password",
- "slider": "Please slide to verify"
- },
- "sliderText": "Please slide to verify",
- "sliderSuccessText": "Verification successful",
- "rememberPwd": "Remember password",
- "forgetPwd": "Forgot password",
- "btnText": "Login",
- "noAccount": "No account yet?",
- "register": "Register",
- "success": {
- "title": "Login successful",
- "message": "Welcome back"
- }
- },
- "forgetPassword": {
- "title": "Forgot password?",
- "subTitle": "Enter your email to reset your password",
- "placeholder": "Please enter your email",
- "submitBtnText": "Submit",
- "backBtnText": "Back"
- },
- "register": {
- "title": "Create account",
- "subTitle": "Welcome to join us, please fill in the following information to complete the registration",
- "placeholder": {
- "username": "Please enter your account",
- "password": "Please enter your password",
- "confirmPassword": "Please enter your password again"
- },
- "rule": {
- "confirmPasswordRequired": "Please enter your password again",
- "passwordMismatch": "The two passwords are inconsistent!",
- "usernameLength": "The length is 3 to 20 characters",
- "passwordLength": "The password length cannot be less than 6 digits",
- "agreementRequired": "Please agree to the privacy policy"
- },
- "agreeText": "I agree",
- "privacyPolicy": "Privacy policy",
- "submitBtnText": "Register",
- "hasAccount": "Already have an account?",
- "toLogin": "To login"
- },
- "lockScreen": {
- "pwdError": "Password error",
- "lock": {
- "inputPlaceholder": "Please input lock screen password",
- "btnText": "Lock"
- },
- "unlock": {
- "inputPlaceholder": "Please input unlock password",
- "btnText": "Unlock",
- "backBtnText": "Back to login"
- }
- },
- "greeting": {
- "dawn": "Good morning!",
- "morning": "Good morning!",
- "afternoon": "Good afternoon!",
- "evening": "Good evening!"
- },
- "exceptionPage": {
- "403": "Sorry, you do not have permission to access this page",
- "404": "Sorry, the page you are trying to access does not exist",
- "500": "Sorry, there was an error on the server",
- "gohome": "Go Home"
- },
- "menus": {
- "login": {
- "title": "Login"
- },
- "register": {
- "title": "Register"
- },
- "forgetPassword": {
- "title": "Forget Password"
- },
- "outside": {
- "title": "Outside"
- },
- "dashboard": {
- "title": "Dashboard",
- "console": "Console"
- },
- "result": {
- "title": "Result Page",
- "success": "Success",
- "fail": "Fail"
- },
- "exception": {
- "title": "Exception",
- "forbidden": "403",
- "notFound": "404",
- "serverError": "500"
- },
- "system": {
- "title": "System Settings",
- "user": "User Manage",
- "role": "Role Manage",
- "userCenter": "User Center",
- "menu": "Menu Manage"
- }
- },
- "table": {
- "form": {
- "reset": "Reset",
- "submit": "Submit"
- },
- "searchBar": {
- "reset": "Reset",
- "search": "Search",
- "expand": "Expand",
- "collapse": "Collapse",
- "searchInputPlaceholder": "Please enter",
- "searchSelectPlaceholder": "Please select"
- },
- "selection": "Select",
- "sizeOptions": {
- "small": "Compact",
- "default": "Default",
- "large": "Loose"
- },
- "column": {
- "selection": "Select",
- "expand": "Expand",
- "index": "Index"
- },
- "zebra": "Zebra",
- "border": "Border",
- "headerBackground": "Header BG"
- }
-}
\ No newline at end of file
+ "httpMsg": {
+ "unauthorized": "Unauthorized access, please login again",
+ "forbidden": "Access to this resource is forbidden",
+ "notFound": "The requested resource does not exist",
+ "methodNotAllowed": "Request method not allowed",
+ "requestTimeout": "Request timeout, please try again later",
+ "internalServerError": "Internal server error, please try again later",
+ "badGateway": "Bad gateway error, please try again later",
+ "serviceUnavailable": "Service temporarily unavailable, please try again later",
+ "gatewayTimeout": "Gateway timeout, please try again later",
+ "requestCancelled": "Request cancelled",
+ "networkError": "Network connection error, please check your connection",
+ "requestFailed": "Request failed",
+ "requestConfigError": "Request configuration error"
+ },
+ "topBar": {
+ "search": {
+ "title": "Search"
+ },
+ "user": {
+ "userCenter": "User center",
+ "docs": "Document",
+ "github": "Github",
+ "lockScreen": "Lock screen",
+ "logout": "Log out"
+ },
+ "guide": {
+ "title": "Click here to view",
+ "theme": "Theme style",
+ "menu": "Open top menu",
+ "description": "More configurations"
+ }
+ },
+ "common": {
+ "tips": "Prompt",
+ "cancel": "Cancel",
+ "confirm": "Confirm",
+ "logOutTips": "Do you want to log out?"
+ },
+ "search": {
+ "placeholder": "Search page",
+ "historyTitle": "Search history",
+ "switchKeydown": "Navigate",
+ "selectKeydown": "Select",
+ "exitKeydown": "Close"
+ },
+ "setting": {
+ "menuType": {
+ "title": "Menu Layout",
+ "list": ["Vertical", "Horizontal", "Mixed", "Dual"]
+ },
+ "theme": {
+ "title": "Theme Style",
+ "list": ["Light", "Dark", "System"]
+ },
+ "menu": {
+ "title": "Menu Style"
+ },
+ "color": {
+ "title": "Theme Color"
+ },
+ "box": {
+ "title": "Box Style",
+ "list": ["Border", "Shadow"]
+ },
+ "container": {
+ "title": "Container Width",
+ "list": ["Full", "Boxed"]
+ },
+ "basics": {
+ "title": "Basic Config",
+ "list": {
+ "multiTab": "Show work tab",
+ "accordion": "Sidebar opens accordion",
+ "collapseSidebar": "Show sidebar button",
+ "reloadPage": "Show reload page button",
+ "fastEnter": "Show fast enter",
+ "breadcrumb": "Show crumb navigation",
+ "language": "Show multilingual selection",
+ "progressBar": "Show top progress bar",
+ "weakMode": "Color Weakness Mode",
+ "watermark": "Global watermark",
+ "menuWidth": "Menu width",
+ "tabStyle": "Tab style",
+ "pageTransition": "Page animation",
+ "borderRadius": "Custom radius"
+ }
+ },
+ "tabStyle": {
+ "default": "Default",
+ "card": "Card",
+ "google": "Chrome"
+ },
+ "transition": {
+ "list": {
+ "none": "None",
+ "fade": "Fade",
+ "slideLeft": "Slide Left",
+ "slideBottom": "Slide Bottom",
+ "slideTop": "Slide Top"
+ }
+ },
+ "actions": {
+ "resetConfig": "Reset Config",
+ "copyConfig": "Copy Config",
+ "copySuccess": "Configuration copied to clipboard, paste it into src/config/setting.ts file",
+ "copyFailed": "Copy failed, please try again",
+ "resetFailed": "Reset failed, please refresh the page and try again"
+ }
+ },
+ "notice": {
+ "title": "Notice",
+ "btnRead": "Mark as read",
+ "bar": ["Notice", "Message", "Todo"],
+ "text": ["No"],
+ "viewAll": "View all"
+ },
+ "worktab": {
+ "btn": {
+ "refresh": "Refresh",
+ "fixed": "Fixed",
+ "unfixed": "Unfixed",
+ "closeLeft": "Close left",
+ "closeRight": "Close right",
+ "closeOther": "Close other",
+ "closeAll": "Close all"
+ }
+ },
+ "login": {
+ "leftView": {
+ "title": "A backend system of beauty and efficiency",
+ "subTitle": "A sleek and practical interface for a great user experience"
+ },
+ "title": "Welcome back",
+ "subTitle": "Please enter your account and password to login",
+ "roles": {
+ "super": "Super Admin",
+ "admin": "Admin",
+ "user": "User"
+ },
+ "placeholder": {
+ "username": "Please enter your account",
+ "password": "Please enter your password",
+ "slider": "Please slide to verify"
+ },
+ "sliderText": "Please slide to verify",
+ "sliderSuccessText": "Verification successful",
+ "rememberPwd": "Remember password",
+ "forgetPwd": "Forgot password",
+ "btnText": "Login",
+ "noAccount": "No account yet?",
+ "register": "Register",
+ "success": {
+ "title": "Login successful",
+ "message": "Welcome back"
+ }
+ },
+ "forgetPassword": {
+ "title": "Forgot password?",
+ "subTitle": "Enter your email to reset your password",
+ "placeholder": "Please enter your email",
+ "submitBtnText": "Submit",
+ "backBtnText": "Back"
+ },
+ "register": {
+ "title": "Create account",
+ "subTitle": "Welcome to join us, please fill in the following information to complete the registration",
+ "placeholder": {
+ "username": "Please enter your account",
+ "password": "Please enter your password",
+ "confirmPassword": "Please enter your password again"
+ },
+ "rule": {
+ "confirmPasswordRequired": "Please enter your password again",
+ "passwordMismatch": "The two passwords are inconsistent!",
+ "usernameLength": "The length is 3 to 20 characters",
+ "passwordLength": "The password length cannot be less than 6 digits",
+ "agreementRequired": "Please agree to the privacy policy"
+ },
+ "agreeText": "I agree",
+ "privacyPolicy": "Privacy policy",
+ "submitBtnText": "Register",
+ "hasAccount": "Already have an account?",
+ "toLogin": "To login"
+ },
+ "lockScreen": {
+ "pwdError": "Password error",
+ "lock": {
+ "inputPlaceholder": "Please input lock screen password",
+ "btnText": "Lock"
+ },
+ "unlock": {
+ "inputPlaceholder": "Please input unlock password",
+ "btnText": "Unlock",
+ "backBtnText": "Back to login"
+ }
+ },
+ "greeting": {
+ "dawn": "Good morning!",
+ "morning": "Good morning!",
+ "afternoon": "Good afternoon!",
+ "evening": "Good evening!"
+ },
+ "exceptionPage": {
+ "403": "Sorry, you do not have permission to access this page",
+ "404": "Sorry, the page you are trying to access does not exist",
+ "500": "Sorry, there was an error on the server",
+ "gohome": "Go Home"
+ },
+ "menus": {
+ "login": {
+ "title": "Login"
+ },
+ "register": {
+ "title": "Register"
+ },
+ "forgetPassword": {
+ "title": "Forget Password"
+ },
+ "outside": {
+ "title": "Outside"
+ },
+ "dashboard": {
+ "title": "Dashboard",
+ "console": "Console"
+ },
+ "result": {
+ "title": "Result Page",
+ "success": "Success",
+ "fail": "Fail"
+ },
+ "exception": {
+ "title": "Exception",
+ "forbidden": "403",
+ "notFound": "404",
+ "serverError": "500"
+ },
+ "system": {
+ "title": "System Settings",
+ "user": "User Manage",
+ "role": "Role Manage",
+ "userCenter": "User Center",
+ "menu": "Menu Manage"
+ }
+ },
+ "table": {
+ "form": {
+ "reset": "Reset",
+ "submit": "Submit"
+ },
+ "searchBar": {
+ "reset": "Reset",
+ "search": "Search",
+ "expand": "Expand",
+ "collapse": "Collapse",
+ "searchInputPlaceholder": "Please enter",
+ "searchSelectPlaceholder": "Please select"
+ },
+ "selection": "Select",
+ "sizeOptions": {
+ "small": "Compact",
+ "default": "Default",
+ "large": "Loose"
+ },
+ "column": {
+ "selection": "Select",
+ "expand": "Expand",
+ "index": "Index"
+ },
+ "zebra": "Zebra",
+ "border": "Border",
+ "headerBackground": "Header BG"
+ }
+}
diff --git a/src/locales/langs/zh.json b/src/locales/langs/zh.json
index 77a23a5..879c363 100644
--- a/src/locales/langs/zh.json
+++ b/src/locales/langs/zh.json
@@ -1,296 +1,275 @@
{
- "httpMsg": {
- "unauthorized": "未授权访问,请重新登录",
- "forbidden": "禁止访问该资源",
- "notFound": "请求的资源不存在",
- "methodNotAllowed": "请求方法不允许",
- "requestTimeout": "请求超时,请稍后重试",
- "internalServerError": "服务器内部错误,请稍后重试",
- "badGateway": "网关错误,请稍后重试",
- "serviceUnavailable": "服务暂时不可用,请稍后重试",
- "gatewayTimeout": "网关超时,请稍后重试",
- "requestCancelled": "请求已取消",
- "networkError": "网络连接异常,请检查网络连接",
- "requestFailed": "请求失败",
- "requestConfigError": "请求配置错误"
- },
- "topBar": {
- "search": {
- "title": "搜索"
- },
- "user": {
- "userCenter": "个人中心",
- "docs": "使用文档",
- "github": "Github",
- "lockScreen": "锁定屏幕",
- "logout": "退出登录"
- },
- "guide": {
- "title": "点击这里查看",
- "theme": "主题风格",
- "menu": "开启顶栏菜单",
- "description": "等更多配置"
- }
- },
- "common": {
- "tips": "提示",
- "cancel": "取消",
- "confirm": "确定",
- "logOutTips": "您是否要退出登录?"
- },
- "search": {
- "placeholder": "搜索页面",
- "historyTitle": "搜索历史",
- "switchKeydown": "切换",
- "selectKeydown": "选择",
- "exitKeydown": "关闭"
- },
- "setting": {
- "menuType": {
- "title": "菜单布局",
- "list": [
- "垂直",
- "水平",
- "混合",
- "双列"
- ]
- },
- "theme": {
- "title": "主题风格",
- "list": [
- "浅色",
- "深色",
- "系统"
- ]
- },
- "menu": {
- "title": "菜单风格"
- },
- "color": {
- "title": "系统主题色"
- },
- "box": {
- "title": "盒子样式",
- "list": [
- "边框",
- "阴影"
- ]
- },
- "container": {
- "title": "容器宽度",
- "list": [
- "铺满",
- "定宽"
- ]
- },
- "basics": {
- "title": "基础配置",
- "list": {
- "multiTab": "开启多标签栏",
- "accordion": "侧边栏开启手风琴模式",
- "collapseSidebar": "显示折叠侧边栏按钮",
- "fastEnter": "显示快速入口",
- "reloadPage": "显示重载页面按钮",
- "breadcrumb": "显示全局面包屑导航",
- "language": "显示多语言选择",
- "progressBar": "显示顶部进度条",
- "weakMode": "色弱模式",
- "watermark": "全局水印",
- "menuWidth": "菜单宽度",
- "tabStyle": "标签页风格",
- "pageTransition": "页面切换动画",
- "borderRadius": "自定义圆角"
- }
- },
- "tabStyle": {
- "default": "默认",
- "card": "卡片",
- "google": "谷歌"
- },
- "transition": {
- "list": {
- "none": "无动画",
- "fade": "淡入淡出",
- "slideLeft": "左侧滑入",
- "slideBottom": "下方滑入",
- "slideTop": "上方滑入"
- }
- },
- "actions": {
- "resetConfig": "重置配置",
- "copyConfig": "复制配置",
- "copySuccess": "配置已复制到剪贴板,可粘贴到 src/config/setting.ts 文件中",
- "copyFailed": "复制失败,请重试",
- "resetFailed": "重置失败,请刷新页面后重试"
- }
- },
- "notice": {
- "title": "通知",
- "btnRead": "标为已读",
- "bar": [
- "通知",
- "消息",
- "代办"
- ],
- "text": [
- "暂无"
- ],
- "viewAll": "查看全部"
- },
- "worktab": {
- "btn": {
- "refresh": "刷新",
- "fixed": "固定",
- "unfixed": "取消固定",
- "closeLeft": "关闭左侧",
- "closeRight": "关闭右侧",
- "closeOther": "关闭其他",
- "closeAll": "关闭全部"
- }
- },
- "login": {
- "leftView": {
- "title": "一款兼具设计美学与高效开发的后台系统",
- "subTitle": "美观实用的界面,经过视觉优化,确保卓越的用户体验"
- },
- "title": "欢迎回来",
- "subTitle": "输入您的账号和密码登录",
- "roles": {
- "super": "超级管理员",
- "admin": "管理员",
- "user": "普通用户"
- },
- "placeholder": {
- "username": "请输入账号",
- "password": "请输入密码",
- "slider": "请拖动滑块完成验证"
- },
- "sliderText": "按住滑块拖动",
- "sliderSuccessText": "验证成功",
- "rememberPwd": "记住密码",
- "forgetPwd": "忘记密码",
- "btnText": "登录",
- "noAccount": "还没有账号?",
- "register": "注册",
- "success": {
- "title": "登录成功",
- "message": "欢迎回来"
- }
- },
- "forgetPassword": {
- "title": "忘记密码?",
- "subTitle": "输入您的电子邮件来重置您的密码",
- "placeholder": "请输入您的电子邮件",
- "submitBtnText": "提交",
- "backBtnText": "返回"
- },
- "register": {
- "title": "创建账号",
- "subTitle": "欢迎加入我们,请填写以下信息完成注册",
- "placeholder": {
- "username": "请输入账号",
- "password": "请输入密码",
- "confirmPassword": "请再次输入密码"
- },
- "rule": {
- "confirmPasswordRequired": "请再次输入密码",
- "passwordMismatch": "两次输入密码不一致!",
- "usernameLength": "长度在 3 到 20 个字符",
- "passwordLength": "密码长度不能小于6位",
- "agreementRequired": "请同意隐私协议"
- },
- "agreeText": "我同意",
- "privacyPolicy": "《隐私政策》",
- "submitBtnText": "注册",
- "hasAccount": "已有账号?",
- "toLogin": "去登录"
- },
- "lockScreen": {
- "pwdError": "密码错误",
- "lock": {
- "inputPlaceholder": "请输入锁屏密码",
- "btnText": "锁定"
- },
- "unlock": {
- "inputPlaceholder": "请输入解锁密码",
- "btnText": "解锁",
- "backBtnText": "返回登录"
- }
- },
- "greeting": {
- "dawn": "凌晨了!",
- "morning": "上午好!",
- "afternoon": "下午好!",
- "evening": "晚上好!"
- },
- "exceptionPage": {
- "403": "抱歉,您无权访问该页面",
- "404": "抱歉,您访问的页面不存在",
- "500": "抱歉,服务器出错了",
- "gohome": "返回首页"
- },
- "menus": {
- "login": {
- "title": "登录"
- },
- "register": {
- "title": "注册"
- },
- "forgetPassword": {
- "title": "忘记密码"
- },
- "outside": {
- "title": "内嵌页面"
- },
- "dashboard": {
- "title": "仪表盘",
- "console": "工作台"
- },
- "result": {
- "title": "结果页面",
- "success": "成功页",
- "fail": "失败页"
- },
- "exception": {
- "title": "异常页面",
- "forbidden": "403",
- "notFound": "404",
- "serverError": "500"
- },
- "system": {
- "title": "系统管理",
- "user": "用户管理",
- "role": "角色管理",
- "userCenter": "个人中心",
- "menu": "菜单管理"
- }
- },
- "table": {
- "form": {
- "reset": "重置",
- "submit": "提交"
- },
- "searchBar": {
- "reset": "重置",
- "search": "查询",
- "expand": "展开",
- "collapse": "收起",
- "searchInputPlaceholder": "请输入",
- "searchSelectPlaceholder": "请选择"
- },
- "selection": "选择",
- "sizeOptions": {
- "small": "紧凑",
- "default": "默认",
- "large": "宽松"
- },
- "column": {
- "selection": "勾选",
- "expand": "展开",
- "index": "序号"
- },
- "zebra": "斑马纹",
- "border": "边框",
- "headerBackground": "表头背景"
- }
-}
\ No newline at end of file
+ "httpMsg": {
+ "unauthorized": "未授权访问,请重新登录",
+ "forbidden": "禁止访问该资源",
+ "notFound": "请求的资源不存在",
+ "methodNotAllowed": "请求方法不允许",
+ "requestTimeout": "请求超时,请稍后重试",
+ "internalServerError": "服务器内部错误,请稍后重试",
+ "badGateway": "网关错误,请稍后重试",
+ "serviceUnavailable": "服务暂时不可用,请稍后重试",
+ "gatewayTimeout": "网关超时,请稍后重试",
+ "requestCancelled": "请求已取消",
+ "networkError": "网络连接异常,请检查网络连接",
+ "requestFailed": "请求失败",
+ "requestConfigError": "请求配置错误"
+ },
+ "topBar": {
+ "search": {
+ "title": "搜索"
+ },
+ "user": {
+ "userCenter": "个人中心",
+ "docs": "使用文档",
+ "github": "Github",
+ "lockScreen": "锁定屏幕",
+ "logout": "退出登录"
+ },
+ "guide": {
+ "title": "点击这里查看",
+ "theme": "主题风格",
+ "menu": "开启顶栏菜单",
+ "description": "等更多配置"
+ }
+ },
+ "common": {
+ "tips": "提示",
+ "cancel": "取消",
+ "confirm": "确定",
+ "logOutTips": "您是否要退出登录?"
+ },
+ "search": {
+ "placeholder": "搜索页面",
+ "historyTitle": "搜索历史",
+ "switchKeydown": "切换",
+ "selectKeydown": "选择",
+ "exitKeydown": "关闭"
+ },
+ "setting": {
+ "menuType": {
+ "title": "菜单布局",
+ "list": ["垂直", "水平", "混合", "双列"]
+ },
+ "theme": {
+ "title": "主题风格",
+ "list": ["浅色", "深色", "系统"]
+ },
+ "menu": {
+ "title": "菜单风格"
+ },
+ "color": {
+ "title": "系统主题色"
+ },
+ "box": {
+ "title": "盒子样式",
+ "list": ["边框", "阴影"]
+ },
+ "container": {
+ "title": "容器宽度",
+ "list": ["铺满", "定宽"]
+ },
+ "basics": {
+ "title": "基础配置",
+ "list": {
+ "multiTab": "开启多标签栏",
+ "accordion": "侧边栏开启手风琴模式",
+ "collapseSidebar": "显示折叠侧边栏按钮",
+ "fastEnter": "显示快速入口",
+ "reloadPage": "显示重载页面按钮",
+ "breadcrumb": "显示全局面包屑导航",
+ "language": "显示多语言选择",
+ "progressBar": "显示顶部进度条",
+ "weakMode": "色弱模式",
+ "watermark": "全局水印",
+ "menuWidth": "菜单宽度",
+ "tabStyle": "标签页风格",
+ "pageTransition": "页面切换动画",
+ "borderRadius": "自定义圆角"
+ }
+ },
+ "tabStyle": {
+ "default": "默认",
+ "card": "卡片",
+ "google": "谷歌"
+ },
+ "transition": {
+ "list": {
+ "none": "无动画",
+ "fade": "淡入淡出",
+ "slideLeft": "左侧滑入",
+ "slideBottom": "下方滑入",
+ "slideTop": "上方滑入"
+ }
+ },
+ "actions": {
+ "resetConfig": "重置配置",
+ "copyConfig": "复制配置",
+ "copySuccess": "配置已复制到剪贴板,可粘贴到 src/config/setting.ts 文件中",
+ "copyFailed": "复制失败,请重试",
+ "resetFailed": "重置失败,请刷新页面后重试"
+ }
+ },
+ "notice": {
+ "title": "通知",
+ "btnRead": "标为已读",
+ "bar": ["通知", "消息", "代办"],
+ "text": ["暂无"],
+ "viewAll": "查看全部"
+ },
+ "worktab": {
+ "btn": {
+ "refresh": "刷新",
+ "fixed": "固定",
+ "unfixed": "取消固定",
+ "closeLeft": "关闭左侧",
+ "closeRight": "关闭右侧",
+ "closeOther": "关闭其他",
+ "closeAll": "关闭全部"
+ }
+ },
+ "login": {
+ "leftView": {
+ "title": "一款兼具设计美学与高效开发的后台系统",
+ "subTitle": "美观实用的界面,经过视觉优化,确保卓越的用户体验"
+ },
+ "title": "欢迎回来",
+ "subTitle": "输入您的账号和密码登录",
+ "roles": {
+ "super": "超级管理员",
+ "admin": "管理员",
+ "user": "普通用户"
+ },
+ "placeholder": {
+ "username": "请输入账号",
+ "password": "请输入密码",
+ "slider": "请拖动滑块完成验证"
+ },
+ "sliderText": "按住滑块拖动",
+ "sliderSuccessText": "验证成功",
+ "rememberPwd": "记住密码",
+ "forgetPwd": "忘记密码",
+ "btnText": "登录",
+ "noAccount": "还没有账号?",
+ "register": "注册",
+ "success": {
+ "title": "登录成功",
+ "message": "欢迎回来"
+ }
+ },
+ "forgetPassword": {
+ "title": "忘记密码?",
+ "subTitle": "输入您的电子邮件来重置您的密码",
+ "placeholder": "请输入您的电子邮件",
+ "submitBtnText": "提交",
+ "backBtnText": "返回"
+ },
+ "register": {
+ "title": "创建账号",
+ "subTitle": "欢迎加入我们,请填写以下信息完成注册",
+ "placeholder": {
+ "username": "请输入账号",
+ "password": "请输入密码",
+ "confirmPassword": "请再次输入密码"
+ },
+ "rule": {
+ "confirmPasswordRequired": "请再次输入密码",
+ "passwordMismatch": "两次输入密码不一致!",
+ "usernameLength": "长度在 3 到 20 个字符",
+ "passwordLength": "密码长度不能小于6位",
+ "agreementRequired": "请同意隐私协议"
+ },
+ "agreeText": "我同意",
+ "privacyPolicy": "《隐私政策》",
+ "submitBtnText": "注册",
+ "hasAccount": "已有账号?",
+ "toLogin": "去登录"
+ },
+ "lockScreen": {
+ "pwdError": "密码错误",
+ "lock": {
+ "inputPlaceholder": "请输入锁屏密码",
+ "btnText": "锁定"
+ },
+ "unlock": {
+ "inputPlaceholder": "请输入解锁密码",
+ "btnText": "解锁",
+ "backBtnText": "返回登录"
+ }
+ },
+ "greeting": {
+ "dawn": "凌晨了!",
+ "morning": "上午好!",
+ "afternoon": "下午好!",
+ "evening": "晚上好!"
+ },
+ "exceptionPage": {
+ "403": "抱歉,您无权访问该页面",
+ "404": "抱歉,您访问的页面不存在",
+ "500": "抱歉,服务器出错了",
+ "gohome": "返回首页"
+ },
+ "menus": {
+ "login": {
+ "title": "登录"
+ },
+ "register": {
+ "title": "注册"
+ },
+ "forgetPassword": {
+ "title": "忘记密码"
+ },
+ "outside": {
+ "title": "内嵌页面"
+ },
+ "dashboard": {
+ "title": "仪表盘",
+ "console": "工作台"
+ },
+ "result": {
+ "title": "结果页面",
+ "success": "成功页",
+ "fail": "失败页"
+ },
+ "exception": {
+ "title": "异常页面",
+ "forbidden": "403",
+ "notFound": "404",
+ "serverError": "500"
+ },
+ "system": {
+ "title": "系统管理",
+ "user": "用户管理",
+ "role": "角色管理",
+ "userCenter": "个人中心",
+ "menu": "菜单管理"
+ }
+ },
+ "table": {
+ "form": {
+ "reset": "重置",
+ "submit": "提交"
+ },
+ "searchBar": {
+ "reset": "重置",
+ "search": "查询",
+ "expand": "展开",
+ "collapse": "收起",
+ "searchInputPlaceholder": "请输入",
+ "searchSelectPlaceholder": "请选择"
+ },
+ "selection": "选择",
+ "sizeOptions": {
+ "small": "紧凑",
+ "default": "默认",
+ "large": "宽松"
+ },
+ "column": {
+ "selection": "勾选",
+ "expand": "展开",
+ "index": "序号"
+ },
+ "zebra": "斑马纹",
+ "border": "边框",
+ "headerBackground": "表头背景"
+ }
+}
diff --git a/src/mock/temp/formData.ts b/src/mock/temp/formData.ts
index 8aa7ae5..2c06829 100644
--- a/src/mock/temp/formData.ts
+++ b/src/mock/temp/formData.ts
@@ -10,264 +10,264 @@ import avatar9 from '@/assets/images/avatar/avatar9.webp'
import avatar10 from '@/assets/images/avatar/avatar10.webp'
export interface User {
- id: number
- username: string
- gender: 1 | 0
- mobile: string
- email: string
- dep: string
- status: string
- create_time: string
- avatar: string
+ id: number
+ username: string
+ gender: 1 | 0
+ mobile: string
+ email: string
+ dep: string
+ status: string
+ create_time: string
+ avatar: string
}
// 用户列表
export const ACCOUNT_TABLE_DATA: User[] = [
- {
- id: 1,
- username: 'alexmorgan',
- gender: 1,
- mobile: '18670001591',
- email: 'alexmorgan@company.com',
- dep: '研发部',
- status: '1',
- create_time: '2020-09-09 10:01:10',
- avatar: avatar1
- },
- {
- id: 2,
- username: 'sophiabaker',
- gender: 1,
- mobile: '17766664444',
- email: 'sophiabaker@company.com',
- dep: '电商部',
- status: '1',
- create_time: '2020-10-10 13:01:12',
- avatar: avatar2
- },
- {
- id: 3,
- username: 'liampark',
- gender: 1,
- mobile: '18670001597',
- email: 'liampark@company.com',
- dep: '人事部',
- status: '1',
- create_time: '2020-11-14 12:01:45',
- avatar: avatar3
- },
- {
- id: 4,
- username: 'oliviagrant',
- gender: 0,
- mobile: '18670001596',
- email: 'oliviagrant@company.com',
- dep: '产品部',
- status: '1',
- create_time: '2020-11-14 09:01:20',
- avatar: avatar4
- },
- {
- id: 5,
- username: 'emmawilson',
- gender: 0,
- mobile: '18670001595',
- email: 'emmawilson@company.com',
- dep: '财务部',
- status: '1',
- create_time: '2020-11-13 11:01:05',
- avatar: avatar5
- },
- {
- id: 6,
- username: 'noahevan',
- gender: 1,
- mobile: '18670001594',
- email: 'noahevan@company.com',
- dep: '运营部',
- status: '1',
- create_time: '2020-10-11 13:10:26',
- avatar: avatar6
- },
- {
- id: 7,
- username: 'avamartin',
- gender: 1,
- mobile: '18123820191',
- email: 'avamartin@company.com',
- dep: '客服部',
- status: '2',
- create_time: '2020-05-14 12:05:10',
- avatar: avatar7
- },
- {
- id: 8,
- username: 'jacoblee',
- gender: 1,
- mobile: '18670001592',
- email: 'jacoblee@company.com',
- dep: '总经办',
- status: '3',
- create_time: '2020-11-12 07:22:25',
- avatar: avatar8
- },
- {
- id: 9,
- username: 'miaclark',
- gender: 0,
- mobile: '18670001581',
- email: 'miaclark@company.com',
- dep: '研发部',
- status: '4',
- create_time: '2020-06-12 05:04:20',
- avatar: avatar9
- },
- {
- id: 10,
- username: 'ethanharris',
- gender: 1,
- mobile: '13755554444',
- email: 'ethanharris@company.com',
- dep: '研发部',
- status: '1',
- create_time: '2020-11-12 16:01:10',
- avatar: avatar10
- },
- {
- id: 11,
- username: 'isabellamoore',
- gender: 1,
- mobile: '13766660000',
- email: 'isabellamoore@company.com',
- dep: '研发部',
- status: '1',
- create_time: '2020-11-14 12:01:20',
- avatar: avatar6
- },
- {
- id: 12,
- username: 'masonwhite',
- gender: 1,
- mobile: '18670001502',
- email: 'masonwhite@company.com',
- dep: '研发部',
- status: '1',
- create_time: '2020-11-14 12:01:20',
- avatar: avatar7
- },
- {
- id: 13,
- username: 'charlottehall',
- gender: 1,
- mobile: '13006644977',
- email: 'charlottehall@company.com',
- dep: '研发部',
- status: '1',
- create_time: '2020-11-14 12:01:20',
- avatar: avatar8
- },
- {
- id: 14,
- username: 'benjaminscott',
- gender: 0,
- mobile: '13599998888',
- email: 'benjaminscott@company.com',
- dep: '研发部',
- status: '1',
- create_time: '2020-11-14 12:01:20',
- avatar: avatar9
- },
- {
- id: 15,
- username: 'ameliaking',
- gender: 1,
- mobile: '13799998888',
- email: 'ameliaking@company.com',
- dep: '研发部',
- status: '1',
- create_time: '2020-11-14 12:01:20',
- avatar: avatar10
- }
+ {
+ id: 1,
+ username: 'alexmorgan',
+ gender: 1,
+ mobile: '18670001591',
+ email: 'alexmorgan@company.com',
+ dep: '研发部',
+ status: '1',
+ create_time: '2020-09-09 10:01:10',
+ avatar: avatar1
+ },
+ {
+ id: 2,
+ username: 'sophiabaker',
+ gender: 1,
+ mobile: '17766664444',
+ email: 'sophiabaker@company.com',
+ dep: '电商部',
+ status: '1',
+ create_time: '2020-10-10 13:01:12',
+ avatar: avatar2
+ },
+ {
+ id: 3,
+ username: 'liampark',
+ gender: 1,
+ mobile: '18670001597',
+ email: 'liampark@company.com',
+ dep: '人事部',
+ status: '1',
+ create_time: '2020-11-14 12:01:45',
+ avatar: avatar3
+ },
+ {
+ id: 4,
+ username: 'oliviagrant',
+ gender: 0,
+ mobile: '18670001596',
+ email: 'oliviagrant@company.com',
+ dep: '产品部',
+ status: '1',
+ create_time: '2020-11-14 09:01:20',
+ avatar: avatar4
+ },
+ {
+ id: 5,
+ username: 'emmawilson',
+ gender: 0,
+ mobile: '18670001595',
+ email: 'emmawilson@company.com',
+ dep: '财务部',
+ status: '1',
+ create_time: '2020-11-13 11:01:05',
+ avatar: avatar5
+ },
+ {
+ id: 6,
+ username: 'noahevan',
+ gender: 1,
+ mobile: '18670001594',
+ email: 'noahevan@company.com',
+ dep: '运营部',
+ status: '1',
+ create_time: '2020-10-11 13:10:26',
+ avatar: avatar6
+ },
+ {
+ id: 7,
+ username: 'avamartin',
+ gender: 1,
+ mobile: '18123820191',
+ email: 'avamartin@company.com',
+ dep: '客服部',
+ status: '2',
+ create_time: '2020-05-14 12:05:10',
+ avatar: avatar7
+ },
+ {
+ id: 8,
+ username: 'jacoblee',
+ gender: 1,
+ mobile: '18670001592',
+ email: 'jacoblee@company.com',
+ dep: '总经办',
+ status: '3',
+ create_time: '2020-11-12 07:22:25',
+ avatar: avatar8
+ },
+ {
+ id: 9,
+ username: 'miaclark',
+ gender: 0,
+ mobile: '18670001581',
+ email: 'miaclark@company.com',
+ dep: '研发部',
+ status: '4',
+ create_time: '2020-06-12 05:04:20',
+ avatar: avatar9
+ },
+ {
+ id: 10,
+ username: 'ethanharris',
+ gender: 1,
+ mobile: '13755554444',
+ email: 'ethanharris@company.com',
+ dep: '研发部',
+ status: '1',
+ create_time: '2020-11-12 16:01:10',
+ avatar: avatar10
+ },
+ {
+ id: 11,
+ username: 'isabellamoore',
+ gender: 1,
+ mobile: '13766660000',
+ email: 'isabellamoore@company.com',
+ dep: '研发部',
+ status: '1',
+ create_time: '2020-11-14 12:01:20',
+ avatar: avatar6
+ },
+ {
+ id: 12,
+ username: 'masonwhite',
+ gender: 1,
+ mobile: '18670001502',
+ email: 'masonwhite@company.com',
+ dep: '研发部',
+ status: '1',
+ create_time: '2020-11-14 12:01:20',
+ avatar: avatar7
+ },
+ {
+ id: 13,
+ username: 'charlottehall',
+ gender: 1,
+ mobile: '13006644977',
+ email: 'charlottehall@company.com',
+ dep: '研发部',
+ status: '1',
+ create_time: '2020-11-14 12:01:20',
+ avatar: avatar8
+ },
+ {
+ id: 14,
+ username: 'benjaminscott',
+ gender: 0,
+ mobile: '13599998888',
+ email: 'benjaminscott@company.com',
+ dep: '研发部',
+ status: '1',
+ create_time: '2020-11-14 12:01:20',
+ avatar: avatar9
+ },
+ {
+ id: 15,
+ username: 'ameliaking',
+ gender: 1,
+ mobile: '13799998888',
+ email: 'ameliaking@company.com',
+ dep: '研发部',
+ status: '1',
+ create_time: '2020-11-14 12:01:20',
+ avatar: avatar10
+ }
]
export interface Role {
- roleName: string
- roleCode: string
- des: string
- date: string
- enable: boolean
+ roleName: string
+ roleCode: string
+ des: string
+ date: string
+ enable: boolean
}
// 角色列表
export const ROLE_LIST_DATA: Role[] = [
- {
- roleName: '超级管理员',
- roleCode: 'R_SUPER',
- des: '拥有系统全部权限',
- date: '2025-05-15 12:30:45',
- enable: true
- },
- {
- roleName: '管理员',
- roleCode: 'R_ADMIN',
- des: '拥有系统管理权限',
- date: '2025-05-15 12:30:45',
- enable: true
- },
- {
- roleName: '普通用户',
- roleCode: 'R_USER',
- des: '拥有系统普通权限',
- date: '2025-05-15 12:30:45',
- enable: true
- },
- {
- roleName: '财务管理员',
- roleCode: 'R_FINANCE',
- des: '管理财务相关权限',
- date: '2025-05-16 09:15:30',
- enable: true
- },
- {
- roleName: '数据分析师',
- roleCode: 'R_ANALYST',
- des: '拥有数据分析权限',
- date: '2025-05-16 11:45:00',
- enable: false
- },
- {
- roleName: '客服专员',
- roleCode: 'R_SUPPORT',
- des: '处理客户支持请求',
- date: '2025-05-17 14:30:22',
- enable: true
- },
- {
- roleName: '营销经理',
- roleCode: 'R_MARKETING',
- des: '管理营销活动权限',
- date: '2025-05-17 15:10:50',
- enable: true
- },
- {
- roleName: '访客用户',
- roleCode: 'R_GUEST',
- des: '仅限浏览权限',
- date: '2025-05-18 08:25:40',
- enable: false
- },
- {
- roleName: '系统维护员',
- roleCode: 'R_MAINTAINER',
- des: '负责系统维护和更新',
- date: '2025-05-18 09:50:12',
- enable: true
- },
- {
- roleName: '项目经理',
- roleCode: 'R_PM',
- des: '管理项目相关权限',
- date: '2025-05-19 13:40:35',
- enable: true
- }
+ {
+ roleName: '超级管理员',
+ roleCode: 'R_SUPER',
+ des: '拥有系统全部权限',
+ date: '2025-05-15 12:30:45',
+ enable: true
+ },
+ {
+ roleName: '管理员',
+ roleCode: 'R_ADMIN',
+ des: '拥有系统管理权限',
+ date: '2025-05-15 12:30:45',
+ enable: true
+ },
+ {
+ roleName: '普通用户',
+ roleCode: 'R_USER',
+ des: '拥有系统普通权限',
+ date: '2025-05-15 12:30:45',
+ enable: true
+ },
+ {
+ roleName: '财务管理员',
+ roleCode: 'R_FINANCE',
+ des: '管理财务相关权限',
+ date: '2025-05-16 09:15:30',
+ enable: true
+ },
+ {
+ roleName: '数据分析师',
+ roleCode: 'R_ANALYST',
+ des: '拥有数据分析权限',
+ date: '2025-05-16 11:45:00',
+ enable: false
+ },
+ {
+ roleName: '客服专员',
+ roleCode: 'R_SUPPORT',
+ des: '处理客户支持请求',
+ date: '2025-05-17 14:30:22',
+ enable: true
+ },
+ {
+ roleName: '营销经理',
+ roleCode: 'R_MARKETING',
+ des: '管理营销活动权限',
+ date: '2025-05-17 15:10:50',
+ enable: true
+ },
+ {
+ roleName: '访客用户',
+ roleCode: 'R_GUEST',
+ des: '仅限浏览权限',
+ date: '2025-05-18 08:25:40',
+ enable: false
+ },
+ {
+ roleName: '系统维护员',
+ roleCode: 'R_MAINTAINER',
+ des: '负责系统维护和更新',
+ date: '2025-05-18 09:50:12',
+ enable: true
+ },
+ {
+ roleName: '项目经理',
+ roleCode: 'R_PM',
+ des: '管理项目相关权限',
+ date: '2025-05-19 13:40:35',
+ enable: true
+ }
]
diff --git a/src/mock/upgrade/changeLog.ts b/src/mock/upgrade/changeLog.ts
index dd6b772..97e91f0 100644
--- a/src/mock/upgrade/changeLog.ts
+++ b/src/mock/upgrade/changeLog.ts
@@ -1,12 +1,12 @@
import { ref } from 'vue'
interface UpgradeLog {
- version: string // 版本号
- title: string // 更新标题
- date: string // 更新日期
- detail?: string[] // 更新内容
- requireReLogin?: boolean // 是否需要重新登录
- remark?: string // 备注
+ version: string // 版本号
+ title: string // 更新标题
+ date: string // 更新日期
+ detail?: string[] // 更新内容
+ requireReLogin?: boolean // 是否需要重新登录
+ remark?: string // 备注
}
export const upgradeLogList = ref([])
diff --git a/src/plugins/echarts.ts b/src/plugins/echarts.ts
index 4f56d89..1c3bb17 100644
--- a/src/plugins/echarts.ts
+++ b/src/plugins/echarts.ts
@@ -13,28 +13,28 @@ import * as echarts from 'echarts/core'
// 导入图表类型
import {
- BarChart,
- LineChart,
- PieChart,
- ScatterChart,
- RadarChart,
- MapChart,
- CandlestickChart
+ BarChart,
+ LineChart,
+ PieChart,
+ ScatterChart,
+ RadarChart,
+ MapChart,
+ CandlestickChart
} from 'echarts/charts'
// 导入组件
import {
- TitleComponent,
- TooltipComponent,
- GridComponent,
- LegendComponent,
- DataZoomComponent,
- MarkPointComponent,
- MarkLineComponent,
- ToolboxComponent,
- BrushComponent,
- GeoComponent,
- VisualMapComponent
+ TitleComponent,
+ TooltipComponent,
+ GridComponent,
+ LegendComponent,
+ DataZoomComponent,
+ MarkPointComponent,
+ MarkLineComponent,
+ ToolboxComponent,
+ BrushComponent,
+ GeoComponent,
+ VisualMapComponent
} from 'echarts/components'
// 导入渲染器
@@ -42,30 +42,30 @@ import { CanvasRenderer } from 'echarts/renderers'
// 注册必要的组件
echarts.use([
- // 图表类型
- BarChart,
- LineChart,
- PieChart,
- ScatterChart,
- RadarChart,
- MapChart,
- CandlestickChart,
+ // 图表类型
+ BarChart,
+ LineChart,
+ PieChart,
+ ScatterChart,
+ RadarChart,
+ MapChart,
+ CandlestickChart,
- // 组件
- TitleComponent,
- TooltipComponent,
- GridComponent,
- LegendComponent,
- DataZoomComponent,
- MarkPointComponent,
- MarkLineComponent,
- ToolboxComponent,
- BrushComponent,
- GeoComponent,
- VisualMapComponent,
+ // 组件
+ TitleComponent,
+ TooltipComponent,
+ GridComponent,
+ LegendComponent,
+ DataZoomComponent,
+ MarkPointComponent,
+ MarkLineComponent,
+ ToolboxComponent,
+ BrushComponent,
+ GeoComponent,
+ VisualMapComponent,
- // 渲染器
- CanvasRenderer
+ // 渲染器
+ CanvasRenderer
])
// 导出 echarts 实例和类型
diff --git a/src/router/core/ComponentLoader.ts b/src/router/core/ComponentLoader.ts
index 8af3ce3..ce15077 100644
--- a/src/router/core/ComponentLoader.ts
+++ b/src/router/core/ComponentLoader.ts
@@ -10,73 +10,73 @@
import { h } from 'vue'
export class ComponentLoader {
- private modules: Record Promise>
+ private modules: Record Promise>
- constructor() {
- // 动态导入 views 目录下所有 .vue 组件
- this.modules = import.meta.glob('../../views/**/*.vue')
- }
+ constructor() {
+ // 动态导入 views 目录下所有 .vue 组件
+ this.modules = import.meta.glob('../../views/**/*.vue')
+ }
- /**
- * 加载组件
- */
- load(componentPath: string): () => Promise {
- if (!componentPath) {
- return this.createEmptyComponent()
- }
+ /**
+ * 加载组件
+ */
+ load(componentPath: string): () => Promise {
+ if (!componentPath) {
+ return this.createEmptyComponent()
+ }
- // 构建可能的路径
- const fullPath = `../../views${componentPath}.vue`
- const fullPathWithIndex = `../../views${componentPath}/index.vue`
+ // 构建可能的路径
+ const fullPath = `../../views${componentPath}.vue`
+ const fullPathWithIndex = `../../views${componentPath}/index.vue`
- // 先尝试直接路径,再尝试添加/index的路径
- const module = this.modules[fullPath] || this.modules[fullPathWithIndex]
+ // 先尝试直接路径,再尝试添加/index的路径
+ const module = this.modules[fullPath] || this.modules[fullPathWithIndex]
- if (!module) {
- console.error(
- `[ComponentLoader] 未找到组件: ${componentPath},尝试过的路径: ${fullPath} 和 ${fullPathWithIndex}`
- )
- return this.createErrorComponent(componentPath)
- }
+ if (!module) {
+ console.error(
+ `[ComponentLoader] 未找到组件: ${componentPath},尝试过的路径: ${fullPath} 和 ${fullPathWithIndex}`
+ )
+ return this.createErrorComponent(componentPath)
+ }
- return module
- }
+ return module
+ }
- /**
- * 加载布局组件
- */
- loadLayout(): () => Promise {
- return () => import('@/views/index/index.vue')
- }
+ /**
+ * 加载布局组件
+ */
+ loadLayout(): () => Promise {
+ return () => import('@/views/index/index.vue')
+ }
- /**
- * 加载 iframe 组件
- */
- loadIframe(): () => Promise {
- return () => import('@/views/outside/Iframe.vue')
- }
+ /**
+ * 加载 iframe 组件
+ */
+ loadIframe(): () => Promise {
+ return () => import('@/views/outside/Iframe.vue')
+ }
- /**
- * 创建空组件
- */
- private createEmptyComponent(): () => Promise {
- return () =>
- Promise.resolve({
- render() {
- return h('div', {})
- }
- })
- }
+ /**
+ * 创建空组件
+ */
+ private createEmptyComponent(): () => Promise {
+ return () =>
+ Promise.resolve({
+ render() {
+ return h('div', {})
+ }
+ })
+ }
- /**
- * 创建错误提示组件
- */
- private createErrorComponent(componentPath: string): () => Promise {
- return () =>
- Promise.resolve({
- render() {
- return h('div', { class: 'route-error' }, `组件未找到: ${componentPath}`)
- }
- })
- }
+ /**
+ * 创建错误提示组件
+ */
+ private createErrorComponent(componentPath: string): () => Promise {
+ return () =>
+ Promise.resolve({
+ render() {
+ return h('div', { class: 'route-error' }, `组件未找到: ${componentPath}`)
+ }
+ })
+ }
}
diff --git a/src/router/core/IframeRouteManager.ts b/src/router/core/IframeRouteManager.ts
index c054ca1..4b38e87 100644
--- a/src/router/core/IframeRouteManager.ts
+++ b/src/router/core/IframeRouteManager.ts
@@ -10,69 +10,69 @@
import type { AppRouteRecord } from '@/types/router'
export class IframeRouteManager {
- private static instance: IframeRouteManager
- private iframeRoutes: AppRouteRecord[] = []
+ private static instance: IframeRouteManager
+ private iframeRoutes: AppRouteRecord[] = []
- private constructor() {}
+ private constructor() {}
- static getInstance(): IframeRouteManager {
- if (!IframeRouteManager.instance) {
- IframeRouteManager.instance = new IframeRouteManager()
- }
- return IframeRouteManager.instance
- }
+ static getInstance(): IframeRouteManager {
+ if (!IframeRouteManager.instance) {
+ IframeRouteManager.instance = new IframeRouteManager()
+ }
+ return IframeRouteManager.instance
+ }
- /**
- * 添加 iframe 路由
- */
- add(route: AppRouteRecord): void {
- if (!this.iframeRoutes.find((r) => r.path === route.path)) {
- this.iframeRoutes.push(route)
- }
- }
+ /**
+ * 添加 iframe 路由
+ */
+ add(route: AppRouteRecord): void {
+ if (!this.iframeRoutes.find((r) => r.path === route.path)) {
+ this.iframeRoutes.push(route)
+ }
+ }
- /**
- * 获取所有 iframe 路由
- */
- getAll(): AppRouteRecord[] {
- return this.iframeRoutes
- }
+ /**
+ * 获取所有 iframe 路由
+ */
+ getAll(): AppRouteRecord[] {
+ return this.iframeRoutes
+ }
- /**
- * 根据路径查找 iframe 路由
- */
- findByPath(path: string): AppRouteRecord | undefined {
- return this.iframeRoutes.find((route) => route.path === path)
- }
+ /**
+ * 根据路径查找 iframe 路由
+ */
+ findByPath(path: string): AppRouteRecord | undefined {
+ return this.iframeRoutes.find((route) => route.path === path)
+ }
- /**
- * 清空所有 iframe 路由
- */
- clear(): void {
- this.iframeRoutes = []
- }
+ /**
+ * 清空所有 iframe 路由
+ */
+ clear(): void {
+ this.iframeRoutes = []
+ }
- /**
- * 保存到 sessionStorage
- */
- save(): void {
- if (this.iframeRoutes.length > 0) {
- sessionStorage.setItem('iframeRoutes', JSON.stringify(this.iframeRoutes))
- }
- }
+ /**
+ * 保存到 sessionStorage
+ */
+ save(): void {
+ if (this.iframeRoutes.length > 0) {
+ sessionStorage.setItem('iframeRoutes', JSON.stringify(this.iframeRoutes))
+ }
+ }
- /**
- * 从 sessionStorage 加载
- */
- load(): void {
- try {
- const data = sessionStorage.getItem('iframeRoutes')
- if (data) {
- this.iframeRoutes = JSON.parse(data)
- }
- } catch (error) {
- console.error('[IframeRouteManager] 加载 iframe 路由失败:', error)
- this.iframeRoutes = []
- }
- }
+ /**
+ * 从 sessionStorage 加载
+ */
+ load(): void {
+ try {
+ const data = sessionStorage.getItem('iframeRoutes')
+ if (data) {
+ this.iframeRoutes = JSON.parse(data)
+ }
+ } catch (error) {
+ console.error('[IframeRouteManager] 加载 iframe 路由失败:', error)
+ this.iframeRoutes = []
+ }
+ }
}
diff --git a/src/router/core/MenuProcessor.ts b/src/router/core/MenuProcessor.ts
index 57bf183..35905d1 100644
--- a/src/router/core/MenuProcessor.ts
+++ b/src/router/core/MenuProcessor.ts
@@ -16,226 +16,230 @@ import { RoutesAlias } from '../routesAlias'
import { formatMenuTitle } from '@/utils'
export class MenuProcessor {
- /**
- * 获取菜单数据
- */
- async getMenuList(): Promise {
- const { isFrontendMode } = useAppMode()
+ /**
+ * 获取菜单数据
+ */
+ async getMenuList(): Promise {
+ const { isFrontendMode } = useAppMode()
- let menuList: AppRouteRecord[]
- if (isFrontendMode.value) {
- menuList = await this.processFrontendMenu()
- } else {
- menuList = await this.processBackendMenu()
- }
+ let menuList: AppRouteRecord[]
+ if (isFrontendMode.value) {
+ menuList = await this.processFrontendMenu()
+ } else {
+ menuList = await this.processBackendMenu()
+ }
- // 在规范化路径之前,验证原始路径配置
- this.validateMenuPaths(menuList)
+ // 在规范化路径之前,验证原始路径配置
+ this.validateMenuPaths(menuList)
- // 规范化路径(将相对路径转换为完整路径)
- return this.normalizeMenuPaths(menuList)
- }
+ // 规范化路径(将相对路径转换为完整路径)
+ return this.normalizeMenuPaths(menuList)
+ }
- /**
- * 处理前端控制模式的菜单
- */
- private async processFrontendMenu(): Promise {
- const userStore = useUserStore()
- const roles = userStore.info?.roles
+ /**
+ * 处理前端控制模式的菜单
+ */
+ private async processFrontendMenu(): Promise {
+ const userStore = useUserStore()
+ const roles = userStore.info?.roles
- let menuList = [...asyncRoutes]
+ let menuList = [...asyncRoutes]
- // 根据角色过滤菜单
- if (roles && roles.length > 0) {
- menuList = this.filterMenuByRoles(menuList, roles)
- }
+ // 根据角色过滤菜单
+ if (roles && roles.length > 0) {
+ menuList = this.filterMenuByRoles(menuList, roles)
+ }
- return this.filterEmptyMenus(menuList)
- }
+ return this.filterEmptyMenus(menuList)
+ }
- /**
- * 处理后端控制模式的菜单
- */
- private async processBackendMenu(): Promise {
- const list = await fetchGetMenuList()
- return this.filterEmptyMenus(list)
- }
+ /**
+ * 处理后端控制模式的菜单
+ */
+ private async processBackendMenu(): Promise {
+ const list = await fetchGetMenuList()
+ return this.filterEmptyMenus(list)
+ }
- /**
- * 根据角色过滤菜单
- */
- private filterMenuByRoles(menu: AppRouteRecord[], roles: string[]): AppRouteRecord[] {
- return menu.reduce((acc: AppRouteRecord[], item) => {
- const itemRoles = item.meta?.roles
- const hasPermission = !itemRoles || itemRoles.some((role) => roles?.includes(role))
+ /**
+ * 根据角色过滤菜单
+ */
+ private filterMenuByRoles(menu: AppRouteRecord[], roles: string[]): AppRouteRecord[] {
+ return menu.reduce((acc: AppRouteRecord[], item) => {
+ const itemRoles = item.meta?.roles
+ const hasPermission = !itemRoles || itemRoles.some((role) => roles?.includes(role))
- if (hasPermission) {
- const filteredItem = { ...item }
- if (filteredItem.children?.length) {
- filteredItem.children = this.filterMenuByRoles(filteredItem.children, roles)
- }
- acc.push(filteredItem)
- }
+ if (hasPermission) {
+ const filteredItem = { ...item }
+ if (filteredItem.children?.length) {
+ filteredItem.children = this.filterMenuByRoles(filteredItem.children, roles)
+ }
+ acc.push(filteredItem)
+ }
- return acc
- }, [])
- }
+ return acc
+ }, [])
+ }
- /**
- * 递归过滤空菜单项
- */
- private filterEmptyMenus(menuList: AppRouteRecord[]): AppRouteRecord[] {
- return menuList
- .map((item) => {
- // 如果有子菜单,先递归过滤子菜单
- if (item.children && item.children.length > 0) {
- const filteredChildren = this.filterEmptyMenus(item.children)
- return {
- ...item,
- children: filteredChildren
- }
- }
- return item
- })
- .filter((item) => {
- // 如果定义了 children 属性(即使是空数组),说明这是一个目录菜单,应该保留
- if ('children' in item) {
- return true
- }
+ /**
+ * 递归过滤空菜单项
+ */
+ private filterEmptyMenus(menuList: AppRouteRecord[]): AppRouteRecord[] {
+ return menuList
+ .map((item) => {
+ // 如果有子菜单,先递归过滤子菜单
+ if (item.children && item.children.length > 0) {
+ const filteredChildren = this.filterEmptyMenus(item.children)
+ return {
+ ...item,
+ children: filteredChildren
+ }
+ }
+ return item
+ })
+ .filter((item) => {
+ // 如果定义了 children 属性(即使是空数组),说明这是一个目录菜单,应该保留
+ if ('children' in item) {
+ return true
+ }
- // 如果有外链或 iframe,保留
- if (item.meta?.isIframe === true || item.meta?.link) {
- return true
- }
+ // 如果有外链或 iframe,保留
+ if (item.meta?.isIframe === true || item.meta?.link) {
+ return true
+ }
- // 如果有有效的 component,保留
- if (item.component && item.component !== '' && item.component !== RoutesAlias.Layout) {
- return true
- }
+ // 如果有有效的 component,保留
+ if (
+ item.component &&
+ item.component !== '' &&
+ item.component !== RoutesAlias.Layout
+ ) {
+ return true
+ }
- // 其他情况过滤掉
- return false
- })
- }
+ // 其他情况过滤掉
+ return false
+ })
+ }
- /**
- * 验证菜单列表是否有效
- */
- validateMenuList(menuList: AppRouteRecord[]): boolean {
- return Array.isArray(menuList) && menuList.length > 0
- }
+ /**
+ * 验证菜单列表是否有效
+ */
+ validateMenuList(menuList: AppRouteRecord[]): boolean {
+ return Array.isArray(menuList) && menuList.length > 0
+ }
- /**
- * 规范化菜单路径
- * 将相对路径转换为完整路径,确保菜单跳转正确
- */
- private normalizeMenuPaths(menuList: AppRouteRecord[], parentPath = ''): AppRouteRecord[] {
- return menuList.map((item) => {
- // 构建完整路径
- const fullPath = this.buildFullPath(item.path || '', parentPath)
+ /**
+ * 规范化菜单路径
+ * 将相对路径转换为完整路径,确保菜单跳转正确
+ */
+ private normalizeMenuPaths(menuList: AppRouteRecord[], parentPath = ''): AppRouteRecord[] {
+ return menuList.map((item) => {
+ // 构建完整路径
+ const fullPath = this.buildFullPath(item.path || '', parentPath)
- // 递归处理子菜单
- const children = item.children?.length
- ? this.normalizeMenuPaths(item.children, fullPath)
- : item.children
+ // 递归处理子菜单
+ const children = item.children?.length
+ ? this.normalizeMenuPaths(item.children, fullPath)
+ : item.children
- return {
- ...item,
- path: fullPath,
- children
- }
- })
- }
+ return {
+ ...item,
+ path: fullPath,
+ children
+ }
+ })
+ }
- /**
- * 验证菜单路径配置
- * 检测非一级菜单是否错误使用了 / 开头的路径
- */
- /**
- * 验证菜单路径配置
- * 检测非一级菜单是否错误使用了 / 开头的路径
- */
- private validateMenuPaths(menuList: AppRouteRecord[], level = 1): void {
- menuList.forEach((route) => {
- if (!route.children?.length) return
+ /**
+ * 验证菜单路径配置
+ * 检测非一级菜单是否错误使用了 / 开头的路径
+ */
+ /**
+ * 验证菜单路径配置
+ * 检测非一级菜单是否错误使用了 / 开头的路径
+ */
+ private validateMenuPaths(menuList: AppRouteRecord[], level = 1): void {
+ menuList.forEach((route) => {
+ if (!route.children?.length) return
- const parentName = String(route.name || route.path || '未知路由')
+ const parentName = String(route.name || route.path || '未知路由')
- route.children.forEach((child) => {
- const childPath = child.path || ''
+ route.children.forEach((child) => {
+ const childPath = child.path || ''
- // 跳过合法的绝对路径:外部链接和 iframe 路由
- if (this.isValidAbsolutePath(childPath)) return
+ // 跳过合法的绝对路径:外部链接和 iframe 路由
+ if (this.isValidAbsolutePath(childPath)) return
- // 检测非法的绝对路径
- if (childPath.startsWith('/')) {
- this.logPathError(child, childPath, parentName, level)
- }
- })
+ // 检测非法的绝对路径
+ if (childPath.startsWith('/')) {
+ this.logPathError(child, childPath, parentName, level)
+ }
+ })
- // 递归检查更深层级的子路由
- this.validateMenuPaths(route.children, level + 1)
- })
- }
+ // 递归检查更深层级的子路由
+ this.validateMenuPaths(route.children, level + 1)
+ })
+ }
- /**
- * 判断是否为合法的绝对路径
- */
- private isValidAbsolutePath(path: string): boolean {
- return (
- path.startsWith('http://') ||
- path.startsWith('https://') ||
- path.startsWith('/outside/iframe/')
- )
- }
+ /**
+ * 判断是否为合法的绝对路径
+ */
+ private isValidAbsolutePath(path: string): boolean {
+ return (
+ path.startsWith('http://') ||
+ path.startsWith('https://') ||
+ path.startsWith('/outside/iframe/')
+ )
+ }
- /**
- * 输出路径配置错误日志
- */
- private logPathError(
- route: AppRouteRecord,
- path: string,
- parentName: string,
- level: number
- ): void {
- const routeName = String(route.name || path || '未知路由')
- const menuTitle = route.meta?.title || routeName
- const suggestedPath = path.split('/').pop() || path.slice(1)
+ /**
+ * 输出路径配置错误日志
+ */
+ private logPathError(
+ route: AppRouteRecord,
+ path: string,
+ parentName: string,
+ level: number
+ ): void {
+ const routeName = String(route.name || path || '未知路由')
+ const menuTitle = route.meta?.title || routeName
+ const suggestedPath = path.split('/').pop() || path.slice(1)
- console.error(
- `[路由配置错误] 菜单 "${formatMenuTitle(menuTitle)}" (name: ${routeName}, path: ${path}) 配置错误\n` +
- ` 位置: ${parentName} > ${routeName}\n` +
- ` 问题: ${level + 1}级菜单的 path 不能以 / 开头\n` +
- ` 当前配置: path: '${path}'\n` +
- ` 应该改为: path: '${suggestedPath}'`
- )
- }
+ console.error(
+ `[路由配置错误] 菜单 "${formatMenuTitle(menuTitle)}" (name: ${routeName}, path: ${path}) 配置错误\n` +
+ ` 位置: ${parentName} > ${routeName}\n` +
+ ` 问题: ${level + 1}级菜单的 path 不能以 / 开头\n` +
+ ` 当前配置: path: '${path}'\n` +
+ ` 应该改为: path: '${suggestedPath}'`
+ )
+ }
- /**
- * 构建完整路径
- */
- private buildFullPath(path: string, parentPath: string): string {
- if (!path) return ''
+ /**
+ * 构建完整路径
+ */
+ private buildFullPath(path: string, parentPath: string): string {
+ if (!path) return ''
- // 外部链接直接返回
- if (path.startsWith('http://') || path.startsWith('https://')) {
- return path
- }
+ // 外部链接直接返回
+ if (path.startsWith('http://') || path.startsWith('https://')) {
+ return path
+ }
- // 如果已经是绝对路径,直接返回
- if (path.startsWith('/')) {
- return path
- }
+ // 如果已经是绝对路径,直接返回
+ if (path.startsWith('/')) {
+ return path
+ }
- // 拼接父路径和当前路径
- if (parentPath) {
- // 移除父路径末尾的斜杠,移除子路径开头的斜杠,然后拼接
- const cleanParent = parentPath.replace(/\/$/, '')
- const cleanChild = path.replace(/^\//, '')
- return `${cleanParent}/${cleanChild}`
- }
+ // 拼接父路径和当前路径
+ if (parentPath) {
+ // 移除父路径末尾的斜杠,移除子路径开头的斜杠,然后拼接
+ const cleanParent = parentPath.replace(/\/$/, '')
+ const cleanChild = path.replace(/^\//, '')
+ return `${cleanParent}/${cleanChild}`
+ }
- // 没有父路径,添加前导斜杠
- return `/${path}`
- }
+ // 没有父路径,添加前导斜杠
+ return `/${path}`
+ }
}
diff --git a/src/router/core/RoutePermissionValidator.ts b/src/router/core/RoutePermissionValidator.ts
index c33e663..63d3b06 100644
--- a/src/router/core/RoutePermissionValidator.ts
+++ b/src/router/core/RoutePermissionValidator.ts
@@ -26,94 +26,94 @@ import type { AppRouteRecord } from '@/types/router'
* 路由权限验证器
*/
export class RoutePermissionValidator {
- /**
- * 验证路径是否在用户菜单权限中
- * @param targetPath 目标路径
- * @param menuList 菜单列表
- * @returns 是否有权限访问
- */
- static hasPermission(targetPath: string, menuList: AppRouteRecord[]): boolean {
- // 根路径始终允许访问
- if (targetPath === '/') {
- return true
- }
+ /**
+ * 验证路径是否在用户菜单权限中
+ * @param targetPath 目标路径
+ * @param menuList 菜单列表
+ * @returns 是否有权限访问
+ */
+ static hasPermission(targetPath: string, menuList: AppRouteRecord[]): boolean {
+ // 根路径始终允许访问
+ if (targetPath === '/') {
+ return true
+ }
- // 构建路径集合
- const pathSet = this.buildMenuPathSet(menuList)
+ // 构建路径集合
+ const pathSet = this.buildMenuPathSet(menuList)
- // 检查路径是否在集合中(精确匹配或前缀匹配)
- return pathSet.has(targetPath) || this.checkPathPrefix(targetPath, pathSet)
- }
+ // 检查路径是否在集合中(精确匹配或前缀匹配)
+ return pathSet.has(targetPath) || this.checkPathPrefix(targetPath, pathSet)
+ }
- /**
- * 构建菜单路径集合(扁平化处理)
- * @param menuList 菜单列表
- * @param pathSet 路径集合
- * @returns 路径集合
- */
- static buildMenuPathSet(
- menuList: AppRouteRecord[],
- pathSet: Set = new Set()
- ): Set {
- if (!Array.isArray(menuList) || menuList.length === 0) {
- return pathSet
- }
+ /**
+ * 构建菜单路径集合(扁平化处理)
+ * @param menuList 菜单列表
+ * @param pathSet 路径集合
+ * @returns 路径集合
+ */
+ static buildMenuPathSet(
+ menuList: AppRouteRecord[],
+ pathSet: Set = new Set()
+ ): Set {
+ if (!Array.isArray(menuList) || menuList.length === 0) {
+ return pathSet
+ }
- for (const menuItem of menuList) {
- // 跳过隐藏的菜单项
- if (menuItem.meta?.isHide || !menuItem.path) {
- continue
- }
+ for (const menuItem of menuList) {
+ // 跳过隐藏的菜单项
+ if (menuItem.meta?.isHide || !menuItem.path) {
+ continue
+ }
- // 标准化路径并添加到集合
- const menuPath = menuItem.path.startsWith('/') ? menuItem.path : `/${menuItem.path}`
- pathSet.add(menuPath)
+ // 标准化路径并添加到集合
+ const menuPath = menuItem.path.startsWith('/') ? menuItem.path : `/${menuItem.path}`
+ pathSet.add(menuPath)
- // 递归处理子菜单
- if (menuItem.children?.length) {
- this.buildMenuPathSet(menuItem.children, pathSet)
- }
- }
+ // 递归处理子菜单
+ if (menuItem.children?.length) {
+ this.buildMenuPathSet(menuItem.children, pathSet)
+ }
+ }
- return pathSet
- }
+ return pathSet
+ }
- /**
- * 检查目标路径是否匹配集合中的某个路径前缀
- * 用于支持动态路由参数匹配,如 /user/123 匹配 /user
- * @param targetPath 目标路径
- * @param pathSet 路径集合
- * @returns 是否匹配
- */
- static checkPathPrefix(targetPath: string, pathSet: Set): boolean {
- // 遍历路径集合,检查是否有前缀匹配
- for (const menuPath of pathSet) {
- if (targetPath.startsWith(`${menuPath}/`)) {
- return true
- }
- }
- return false
- }
+ /**
+ * 检查目标路径是否匹配集合中的某个路径前缀
+ * 用于支持动态路由参数匹配,如 /user/123 匹配 /user
+ * @param targetPath 目标路径
+ * @param pathSet 路径集合
+ * @returns 是否匹配
+ */
+ static checkPathPrefix(targetPath: string, pathSet: Set): boolean {
+ // 遍历路径集合,检查是否有前缀匹配
+ for (const menuPath of pathSet) {
+ if (targetPath.startsWith(`${menuPath}/`)) {
+ return true
+ }
+ }
+ return false
+ }
- /**
- * 验证并返回有效的路径
- * 如果目标路径无权限,返回首页路径
- * @param targetPath 目标路径
- * @param menuList 菜单列表
- * @param homePath 首页路径
- * @returns 验证后的路径
- */
- static validatePath(
- targetPath: string,
- menuList: AppRouteRecord[],
- homePath: string = '/'
- ): { path: string; hasPermission: boolean } {
- const hasPermission = this.hasPermission(targetPath, menuList)
+ /**
+ * 验证并返回有效的路径
+ * 如果目标路径无权限,返回首页路径
+ * @param targetPath 目标路径
+ * @param menuList 菜单列表
+ * @param homePath 首页路径
+ * @returns 验证后的路径
+ */
+ static validatePath(
+ targetPath: string,
+ menuList: AppRouteRecord[],
+ homePath: string = '/'
+ ): { path: string; hasPermission: boolean } {
+ const hasPermission = this.hasPermission(targetPath, menuList)
- if (hasPermission) {
- return { path: targetPath, hasPermission: true }
- }
+ if (hasPermission) {
+ return { path: targetPath, hasPermission: true }
+ }
- return { path: homePath, hasPermission: false }
- }
+ return { path: homePath, hasPermission: false }
+ }
}
diff --git a/src/router/core/RouteRegistry.ts b/src/router/core/RouteRegistry.ts
index e1acb9e..3e4e49b 100644
--- a/src/router/core/RouteRegistry.ts
+++ b/src/router/core/RouteRegistry.ts
@@ -14,77 +14,77 @@ import { RouteValidator } from './RouteValidator'
import { RouteTransformer } from './RouteTransformer'
export class RouteRegistry {
- private router: Router
- private componentLoader: ComponentLoader
- private validator: RouteValidator
- private transformer: RouteTransformer
- private removeRouteFns: (() => void)[] = []
- private registered = false
+ private router: Router
+ private componentLoader: ComponentLoader
+ private validator: RouteValidator
+ private transformer: RouteTransformer
+ private removeRouteFns: (() => void)[] = []
+ private registered = false
- constructor(router: Router) {
- this.router = router
- this.componentLoader = new ComponentLoader()
- this.validator = new RouteValidator()
- this.transformer = new RouteTransformer(this.componentLoader)
- }
+ constructor(router: Router) {
+ this.router = router
+ this.componentLoader = new ComponentLoader()
+ this.validator = new RouteValidator()
+ this.transformer = new RouteTransformer(this.componentLoader)
+ }
- /**
- * 注册动态路由
- */
- register(menuList: AppRouteRecord[]): void {
- if (this.registered) {
- console.warn('[RouteRegistry] 路由已注册,跳过重复注册')
- return
- }
+ /**
+ * 注册动态路由
+ */
+ register(menuList: AppRouteRecord[]): void {
+ if (this.registered) {
+ console.warn('[RouteRegistry] 路由已注册,跳过重复注册')
+ return
+ }
- // 验证路由配置
- const validationResult = this.validator.validate(menuList)
- if (!validationResult.valid) {
- throw new Error(`路由配置验证失败: ${validationResult.errors.join(', ')}`)
- }
+ // 验证路由配置
+ const validationResult = this.validator.validate(menuList)
+ if (!validationResult.valid) {
+ throw new Error(`路由配置验证失败: ${validationResult.errors.join(', ')}`)
+ }
- // 转换并注册路由
- const removeRouteFns: (() => void)[] = []
+ // 转换并注册路由
+ const removeRouteFns: (() => void)[] = []
- menuList.forEach((route) => {
- if (route.name && !this.router.hasRoute(route.name)) {
- const routeConfig = this.transformer.transform(route)
- const removeRouteFn = this.router.addRoute(routeConfig as RouteRecordRaw)
- removeRouteFns.push(removeRouteFn)
- }
- })
+ menuList.forEach((route) => {
+ if (route.name && !this.router.hasRoute(route.name)) {
+ const routeConfig = this.transformer.transform(route)
+ const removeRouteFn = this.router.addRoute(routeConfig as RouteRecordRaw)
+ removeRouteFns.push(removeRouteFn)
+ }
+ })
- this.removeRouteFns = removeRouteFns
- this.registered = true
- }
+ this.removeRouteFns = removeRouteFns
+ this.registered = true
+ }
- /**
- * 移除所有动态路由
- */
- unregister(): void {
- this.removeRouteFns.forEach((fn) => fn())
- this.removeRouteFns = []
- this.registered = false
- }
+ /**
+ * 移除所有动态路由
+ */
+ unregister(): void {
+ this.removeRouteFns.forEach((fn) => fn())
+ this.removeRouteFns = []
+ this.registered = false
+ }
- /**
- * 检查是否已注册
- */
- isRegistered(): boolean {
- return this.registered
- }
+ /**
+ * 检查是否已注册
+ */
+ isRegistered(): boolean {
+ return this.registered
+ }
- /**
- * 获取移除函数列表(用于 store 管理)
- */
- getRemoveRouteFns(): (() => void)[] {
- return this.removeRouteFns
- }
+ /**
+ * 获取移除函数列表(用于 store 管理)
+ */
+ getRemoveRouteFns(): (() => void)[] {
+ return this.removeRouteFns
+ }
- /**
- * 标记为已注册(用于错误处理场景,避免重复请求)
- */
- markAsRegistered(): void {
- this.registered = true
- }
+ /**
+ * 标记为已注册(用于错误处理场景,避免重复请求)
+ */
+ markAsRegistered(): void {
+ this.registered = true
+ }
}
diff --git a/src/router/core/RouteTransformer.ts b/src/router/core/RouteTransformer.ts
index 0f6900c..83522f3 100644
--- a/src/router/core/RouteTransformer.ts
+++ b/src/router/core/RouteTransformer.ts
@@ -13,120 +13,120 @@ import { ComponentLoader } from './ComponentLoader'
import { IframeRouteManager } from './IframeRouteManager'
interface ConvertedRoute extends Omit {
- id?: number
- children?: ConvertedRoute[]
- component?: RouteRecordRaw['component'] | (() => Promise)
+ id?: number
+ children?: ConvertedRoute[]
+ component?: RouteRecordRaw['component'] | (() => Promise)
}
export class RouteTransformer {
- private componentLoader: ComponentLoader
- private iframeManager: IframeRouteManager
+ private componentLoader: ComponentLoader
+ private iframeManager: IframeRouteManager
- constructor(componentLoader: ComponentLoader) {
- this.componentLoader = componentLoader
- this.iframeManager = IframeRouteManager.getInstance()
- }
+ constructor(componentLoader: ComponentLoader) {
+ this.componentLoader = componentLoader
+ this.iframeManager = IframeRouteManager.getInstance()
+ }
- /**
- * 转换路由配置
- */
- transform(route: AppRouteRecord, depth = 0): ConvertedRoute {
- const { component, children, ...routeConfig } = route
+ /**
+ * 转换路由配置
+ */
+ transform(route: AppRouteRecord, depth = 0): ConvertedRoute {
+ const { component, children, ...routeConfig } = route
- // 基础路由配置
- const converted: ConvertedRoute = {
- ...routeConfig,
- component: undefined
- }
+ // 基础路由配置
+ const converted: ConvertedRoute = {
+ ...routeConfig,
+ component: undefined
+ }
- // 处理不同类型的路由
- if (route.meta.isIframe) {
- this.handleIframeRoute(converted, route, depth)
- } else if (this.isFirstLevelRoute(route, depth)) {
- this.handleFirstLevelRoute(converted, route, component as string)
- } else {
- this.handleNormalRoute(converted, component as string)
- }
+ // 处理不同类型的路由
+ if (route.meta.isIframe) {
+ this.handleIframeRoute(converted, route, depth)
+ } else if (this.isFirstLevelRoute(route, depth)) {
+ this.handleFirstLevelRoute(converted, route, component as string)
+ } else {
+ this.handleNormalRoute(converted, component as string)
+ }
- // 递归处理子路由
- if (children?.length) {
- converted.children = children.map((child) => this.transform(child, depth + 1))
- }
+ // 递归处理子路由
+ if (children?.length) {
+ converted.children = children.map((child) => this.transform(child, depth + 1))
+ }
- return converted
- }
+ return converted
+ }
- /**
- * 判断是否为一级路由(需要 Layout 包裹)
- */
- private isFirstLevelRoute(route: AppRouteRecord, depth: number): boolean {
- return depth === 0 && (!route.children || route.children.length === 0)
- }
+ /**
+ * 判断是否为一级路由(需要 Layout 包裹)
+ */
+ private isFirstLevelRoute(route: AppRouteRecord, depth: number): boolean {
+ return depth === 0 && (!route.children || route.children.length === 0)
+ }
- /**
- * 处理 iframe 类型路由
- */
- private handleIframeRoute(
- targetRoute: ConvertedRoute,
- sourceRoute: AppRouteRecord,
- depth: number
- ): void {
- if (depth === 0) {
- // 顶级 iframe:用 Layout 包裹
- targetRoute.component = this.componentLoader.loadLayout()
- targetRoute.path = this.extractFirstSegment(sourceRoute.path || '')
- targetRoute.name = ''
+ /**
+ * 处理 iframe 类型路由
+ */
+ private handleIframeRoute(
+ targetRoute: ConvertedRoute,
+ sourceRoute: AppRouteRecord,
+ depth: number
+ ): void {
+ if (depth === 0) {
+ // 顶级 iframe:用 Layout 包裹
+ targetRoute.component = this.componentLoader.loadLayout()
+ targetRoute.path = this.extractFirstSegment(sourceRoute.path || '')
+ targetRoute.name = ''
- targetRoute.children = [
- {
- ...sourceRoute,
- component: this.componentLoader.loadIframe()
- } as ConvertedRoute
- ]
- } else {
- // 非顶级(嵌套)iframe:直接使用 Iframe.vue
- targetRoute.component = this.componentLoader.loadIframe()
- }
+ targetRoute.children = [
+ {
+ ...sourceRoute,
+ component: this.componentLoader.loadIframe()
+ } as ConvertedRoute
+ ]
+ } else {
+ // 非顶级(嵌套)iframe:直接使用 Iframe.vue
+ targetRoute.component = this.componentLoader.loadIframe()
+ }
- // 记录 iframe 路由
- this.iframeManager.add(sourceRoute)
- }
+ // 记录 iframe 路由
+ this.iframeManager.add(sourceRoute)
+ }
- /**
- * 处理一级菜单路由
- */
- private handleFirstLevelRoute(
- converted: ConvertedRoute,
- route: AppRouteRecord,
- component: string | undefined
- ): void {
- converted.component = this.componentLoader.loadLayout()
- converted.path = this.extractFirstSegment(route.path || '')
- converted.name = ''
- route.meta.isFirstLevel = true
+ /**
+ * 处理一级菜单路由
+ */
+ private handleFirstLevelRoute(
+ converted: ConvertedRoute,
+ route: AppRouteRecord,
+ component: string | undefined
+ ): void {
+ converted.component = this.componentLoader.loadLayout()
+ converted.path = this.extractFirstSegment(route.path || '')
+ converted.name = ''
+ route.meta.isFirstLevel = true
- converted.children = [
- {
- ...route,
- component: component ? this.componentLoader.load(component) : undefined
- } as ConvertedRoute
- ]
- }
+ converted.children = [
+ {
+ ...route,
+ component: component ? this.componentLoader.load(component) : undefined
+ } as ConvertedRoute
+ ]
+ }
- /**
- * 处理普通路由
- */
- private handleNormalRoute(converted: ConvertedRoute, component: string | undefined): void {
- if (component) {
- converted.component = this.componentLoader.load(component)
- }
- }
+ /**
+ * 处理普通路由
+ */
+ private handleNormalRoute(converted: ConvertedRoute, component: string | undefined): void {
+ if (component) {
+ converted.component = this.componentLoader.load(component)
+ }
+ }
- /**
- * 提取路径的第一段
- */
- private extractFirstSegment(path: string): string {
- const segments = path.split('/').filter(Boolean)
- return segments.length > 0 ? `/${segments[0]}` : '/'
- }
+ /**
+ * 提取路径的第一段
+ */
+ private extractFirstSegment(path: string): string {
+ const segments = path.split('/').filter(Boolean)
+ return segments.length > 0 ? `/${segments[0]}` : '/'
+ }
}
diff --git a/src/router/core/RouteValidator.ts b/src/router/core/RouteValidator.ts
index f8e58fc..b4eaeda 100644
--- a/src/router/core/RouteValidator.ts
+++ b/src/router/core/RouteValidator.ts
@@ -11,177 +11,177 @@ import type { AppRouteRecord } from '@/types/router'
import { RoutesAlias } from '../routesAlias'
export interface ValidationResult {
- valid: boolean
- errors: string[]
- warnings: string[]
+ valid: boolean
+ errors: string[]
+ warnings: string[]
}
export class RouteValidator {
- // 用于记录已经提示过的路由,避免重复提示
- private warnedRoutes = new Set()
+ // 用于记录已经提示过的路由,避免重复提示
+ private warnedRoutes = new Set()
- /**
- * 验证路由配置
- */
- validate(routes: AppRouteRecord[]): ValidationResult {
- const errors: string[] = []
- const warnings: string[] = []
+ /**
+ * 验证路由配置
+ */
+ validate(routes: AppRouteRecord[]): ValidationResult {
+ const errors: string[] = []
+ const warnings: string[] = []
- // 检测重复路由
- this.checkDuplicates(routes, errors, warnings)
+ // 检测重复路由
+ this.checkDuplicates(routes, errors, warnings)
- // 检测组件配置
- this.checkComponents(routes, errors, warnings)
+ // 检测组件配置
+ this.checkComponents(routes, errors, warnings)
- // 检测嵌套菜单的 /index/index 配置
- this.checkNestedIndexComponent(routes)
+ // 检测嵌套菜单的 /index/index 配置
+ this.checkNestedIndexComponent(routes)
- return {
- valid: errors.length === 0,
- errors,
- warnings
- }
- }
+ return {
+ valid: errors.length === 0,
+ errors,
+ warnings
+ }
+ }
- /**
- * 检测重复路由
- */
- private checkDuplicates(
- routes: AppRouteRecord[],
- errors: string[],
- warnings: string[],
- parentPath = ''
- ): void {
- const routeNameMap = new Map()
- const componentPathMap = new Map()
+ /**
+ * 检测重复路由
+ */
+ private checkDuplicates(
+ routes: AppRouteRecord[],
+ errors: string[],
+ warnings: string[],
+ parentPath = ''
+ ): void {
+ const routeNameMap = new Map()
+ const componentPathMap = new Map()
- const checkRoutes = (routes: AppRouteRecord[], parentPath = '') => {
- routes.forEach((route) => {
- const currentPath = route.path || ''
- const fullPath = this.resolvePath(parentPath, currentPath)
+ const checkRoutes = (routes: AppRouteRecord[], parentPath = '') => {
+ routes.forEach((route) => {
+ const currentPath = route.path || ''
+ const fullPath = this.resolvePath(parentPath, currentPath)
- // 名称重复检测
- if (route.name) {
- const routeName = String(route.name)
- if (routeNameMap.has(routeName)) {
- warnings.push(`路由名称重复: "${routeName}" (${fullPath})`)
- } else {
- routeNameMap.set(routeName, fullPath)
- }
- }
+ // 名称重复检测
+ if (route.name) {
+ const routeName = String(route.name)
+ if (routeNameMap.has(routeName)) {
+ warnings.push(`路由名称重复: "${routeName}" (${fullPath})`)
+ } else {
+ routeNameMap.set(routeName, fullPath)
+ }
+ }
- // 组件路径重复检测
- if (route.component && typeof route.component === 'string') {
- const componentPath = route.component
- if (componentPath !== RoutesAlias.Layout) {
- const componentKey = `${parentPath}:${componentPath}`
- if (componentPathMap.has(componentKey)) {
- warnings.push(`组件路径重复: "${componentPath}" (${fullPath})`)
- } else {
- componentPathMap.set(componentKey, fullPath)
- }
- }
- }
+ // 组件路径重复检测
+ if (route.component && typeof route.component === 'string') {
+ const componentPath = route.component
+ if (componentPath !== RoutesAlias.Layout) {
+ const componentKey = `${parentPath}:${componentPath}`
+ if (componentPathMap.has(componentKey)) {
+ warnings.push(`组件路径重复: "${componentPath}" (${fullPath})`)
+ } else {
+ componentPathMap.set(componentKey, fullPath)
+ }
+ }
+ }
- // 递归处理子路由
- if (route.children?.length) {
- checkRoutes(route.children, fullPath)
- }
- })
- }
+ // 递归处理子路由
+ if (route.children?.length) {
+ checkRoutes(route.children, fullPath)
+ }
+ })
+ }
- checkRoutes(routes, parentPath)
- }
+ checkRoutes(routes, parentPath)
+ }
- /**
- * 检测组件配置
- */
- private checkComponents(
- routes: AppRouteRecord[],
- errors: string[],
- warnings: string[],
- parentPath = ''
- ): void {
- routes.forEach((route) => {
- const hasExternalLink = !!route.meta?.link?.trim()
- const hasChildren = Array.isArray(route.children) && route.children.length > 0
- const routePath = route.path || '[未定义路径]'
- const isIframe = route.meta?.isIframe
+ /**
+ * 检测组件配置
+ */
+ private checkComponents(
+ routes: AppRouteRecord[],
+ errors: string[],
+ warnings: string[],
+ parentPath = ''
+ ): void {
+ routes.forEach((route) => {
+ const hasExternalLink = !!route.meta?.link?.trim()
+ const hasChildren = Array.isArray(route.children) && route.children.length > 0
+ const routePath = route.path || '[未定义路径]'
+ const isIframe = route.meta?.isIframe
- // 如果配置了 component,则无需校验
- if (route.component) {
- // 递归检查子路由
- if (route.children?.length) {
- const fullPath = this.resolvePath(parentPath, route.path || '')
- this.checkComponents(route.children, errors, warnings, fullPath)
- }
- return
- }
+ // 如果配置了 component,则无需校验
+ if (route.component) {
+ // 递归检查子路由
+ if (route.children?.length) {
+ const fullPath = this.resolvePath(parentPath, route.path || '')
+ this.checkComponents(route.children, errors, warnings, fullPath)
+ }
+ return
+ }
- // 一级菜单:必须指定 Layout,除非是外链或 iframe
- if (parentPath === '' && !hasExternalLink && !isIframe) {
- errors.push(`一级菜单(${routePath}) 缺少 component,必须指向 ${RoutesAlias.Layout}`)
- return
- }
+ // 一级菜单:必须指定 Layout,除非是外链或 iframe
+ if (parentPath === '' && !hasExternalLink && !isIframe) {
+ errors.push(`一级菜单(${routePath}) 缺少 component,必须指向 ${RoutesAlias.Layout}`)
+ return
+ }
- // 非一级菜单:如果既不是外链、iframe,也没有子路由,则必须配置 component
- if (!hasExternalLink && !isIframe && !hasChildren) {
- errors.push(`路由(${routePath}) 缺少 component 配置`)
- }
+ // 非一级菜单:如果既不是外链、iframe,也没有子路由,则必须配置 component
+ if (!hasExternalLink && !isIframe && !hasChildren) {
+ errors.push(`路由(${routePath}) 缺少 component 配置`)
+ }
- // 递归检查子路由
- if (route.children?.length) {
- const fullPath = this.resolvePath(parentPath, route.path || '')
- this.checkComponents(route.children, errors, warnings, fullPath)
- }
- })
- }
+ // 递归检查子路由
+ if (route.children?.length) {
+ const fullPath = this.resolvePath(parentPath, route.path || '')
+ this.checkComponents(route.children, errors, warnings, fullPath)
+ }
+ })
+ }
- /**
- * 检测嵌套菜单的 Layout 组件配置
- * 只有一级菜单才能使用 Layout,二级及以下菜单不能使用
- */
- private checkNestedIndexComponent(routes: AppRouteRecord[], level = 1): void {
- routes.forEach((route) => {
- // 检查二级及以下菜单是否错误使用了 Layout
- if (level > 1 && route.component === RoutesAlias.Layout) {
- this.logLayoutError(route, level)
- }
+ /**
+ * 检测嵌套菜单的 Layout 组件配置
+ * 只有一级菜单才能使用 Layout,二级及以下菜单不能使用
+ */
+ private checkNestedIndexComponent(routes: AppRouteRecord[], level = 1): void {
+ routes.forEach((route) => {
+ // 检查二级及以下菜单是否错误使用了 Layout
+ if (level > 1 && route.component === RoutesAlias.Layout) {
+ this.logLayoutError(route, level)
+ }
- // 递归检查子路由
- if (route.children?.length) {
- this.checkNestedIndexComponent(route.children, level + 1)
- }
- })
- }
+ // 递归检查子路由
+ if (route.children?.length) {
+ this.checkNestedIndexComponent(route.children, level + 1)
+ }
+ })
+ }
- /**
- * 输出 Layout 组件配置错误日志
- */
- private logLayoutError(route: AppRouteRecord, level: number): void {
- const routeName = String(route.name || route.path || '未知路由')
- const routeKey = `${routeName}_${route.path}`
+ /**
+ * 输出 Layout 组件配置错误日志
+ */
+ private logLayoutError(route: AppRouteRecord, level: number): void {
+ const routeName = String(route.name || route.path || '未知路由')
+ const routeKey = `${routeName}_${route.path}`
- // 避免重复提示
- if (this.warnedRoutes.has(routeKey)) return
- this.warnedRoutes.add(routeKey)
+ // 避免重复提示
+ if (this.warnedRoutes.has(routeKey)) return
+ this.warnedRoutes.add(routeKey)
- const menuTitle = route.meta?.title || routeName
- const routePath = route.path || '/'
+ const menuTitle = route.meta?.title || routeName
+ const routePath = route.path || '/'
- console.error(
- `[路由配置错误] 菜单 "${menuTitle}" (name: ${routeName}, path: ${routePath}) 配置错误\n` +
- ` 问题: ${level}级菜单不能使用 ${RoutesAlias.Layout} 作为 component\n` +
- ` 说明: 只有一级菜单才能使用 ${RoutesAlias.Layout},二级及以下菜单应该指向具体的组件路径\n` +
- ` 当前配置: component: '${RoutesAlias.Layout}'\n` +
- ` 应该改为: component: '/your/component/path' 或留空 ''(如果是目录菜单)`
- )
- }
+ console.error(
+ `[路由配置错误] 菜单 "${menuTitle}" (name: ${routeName}, path: ${routePath}) 配置错误\n` +
+ ` 问题: ${level}级菜单不能使用 ${RoutesAlias.Layout} 作为 component\n` +
+ ` 说明: 只有一级菜单才能使用 ${RoutesAlias.Layout},二级及以下菜单应该指向具体的组件路径\n` +
+ ` 当前配置: component: '${RoutesAlias.Layout}'\n` +
+ ` 应该改为: component: '/your/component/path' 或留空 ''(如果是目录菜单)`
+ )
+ }
- /**
- * 路径解析
- */
- private resolvePath(parent: string, child: string): string {
- return [parent.replace(/\/$/, ''), child.replace(/^\//, '')].filter(Boolean).join('/')
- }
+ /**
+ * 路径解析
+ */
+ private resolvePath(parent: string, child: string): string {
+ return [parent.replace(/\/$/, ''), child.replace(/^\//, '')].filter(Boolean).join('/')
+ }
}
diff --git a/src/router/guards/afterEach.ts b/src/router/guards/afterEach.ts
index d60572d..ac3a232 100644
--- a/src/router/guards/afterEach.ts
+++ b/src/router/guards/afterEach.ts
@@ -8,27 +8,27 @@ import { getPendingLoading, resetPendingLoading } from './beforeEach'
/** 路由全局后置守卫 */
export function setupAfterEachGuard(router: Router) {
- const { scrollToTop } = useCommon()
+ const { scrollToTop } = useCommon()
- router.afterEach(() => {
- scrollToTop()
+ router.afterEach(() => {
+ scrollToTop()
- // 关闭进度条
- const settingStore = useSettingStore()
- if (settingStore.showNprogress) {
- NProgress.done()
- // 确保进度条完全移除,避免残影
- setTimeout(() => {
- NProgress.remove()
- }, 600)
- }
+ // 关闭进度条
+ const settingStore = useSettingStore()
+ if (settingStore.showNprogress) {
+ NProgress.done()
+ // 确保进度条完全移除,避免残影
+ setTimeout(() => {
+ NProgress.remove()
+ }, 600)
+ }
- // 关闭 loading 效果
- if (getPendingLoading()) {
- nextTick(() => {
- loadingService.hideLoading()
- resetPendingLoading()
- })
- }
- })
+ // 关闭 loading 效果
+ if (getPendingLoading()) {
+ nextTick(() => {
+ loadingService.hideLoading()
+ resetPendingLoading()
+ })
+ }
+ })
}
diff --git a/src/router/guards/beforeEach.ts b/src/router/guards/beforeEach.ts
index e94f633..58e1deb 100644
--- a/src/router/guards/beforeEach.ts
+++ b/src/router/guards/beforeEach.ts
@@ -73,128 +73,128 @@ let routeInitInProgress = false
* 获取 pendingLoading 状态
*/
export function getPendingLoading(): boolean {
- return pendingLoading
+ return pendingLoading
}
/**
* 重置 pendingLoading 状态
*/
export function resetPendingLoading(): void {
- pendingLoading = false
+ pendingLoading = false
}
/**
* 获取路由初始化失败状态
*/
export function getRouteInitFailed(): boolean {
- return routeInitFailed
+ return routeInitFailed
}
/**
* 重置路由初始化状态(用于重新登录场景)
*/
export function resetRouteInitState(): void {
- routeInitFailed = false
- routeInitInProgress = false
+ routeInitFailed = false
+ routeInitInProgress = false
}
/**
* 设置路由全局前置守卫
*/
export function setupBeforeEachGuard(router: Router): void {
- // 初始化路由注册器
- routeRegistry = new RouteRegistry(router)
+ // 初始化路由注册器
+ routeRegistry = new RouteRegistry(router)
- router.beforeEach(
- async (
- to: RouteLocationNormalized,
- from: RouteLocationNormalized,
- next: NavigationGuardNext
- ) => {
- try {
- await handleRouteGuard(to, from, next, router)
- } catch (error) {
- console.error('[RouteGuard] 路由守卫处理失败:', error)
- closeLoading()
- next({ name: 'Exception500' })
- }
- }
- )
+ router.beforeEach(
+ async (
+ to: RouteLocationNormalized,
+ from: RouteLocationNormalized,
+ next: NavigationGuardNext
+ ) => {
+ try {
+ await handleRouteGuard(to, from, next, router)
+ } catch (error) {
+ console.error('[RouteGuard] 路由守卫处理失败:', error)
+ closeLoading()
+ next({ name: 'Exception500' })
+ }
+ }
+ )
}
/**
* 关闭 loading 效果
*/
function closeLoading(): void {
- if (pendingLoading) {
- nextTick(() => {
- loadingService.hideLoading()
- pendingLoading = false
- })
- }
+ if (pendingLoading) {
+ nextTick(() => {
+ loadingService.hideLoading()
+ pendingLoading = false
+ })
+ }
}
/**
* 处理路由守卫逻辑
*/
async function handleRouteGuard(
- to: RouteLocationNormalized,
- from: RouteLocationNormalized,
- next: NavigationGuardNext,
- router: Router
+ to: RouteLocationNormalized,
+ from: RouteLocationNormalized,
+ next: NavigationGuardNext,
+ router: Router
): Promise {
- const settingStore = useSettingStore()
- const userStore = useUserStore()
+ const settingStore = useSettingStore()
+ const userStore = useUserStore()
- // 启动进度条
- if (settingStore.showNprogress) {
- NProgress.start()
- }
+ // 启动进度条
+ if (settingStore.showNprogress) {
+ NProgress.start()
+ }
- // 1. 检查登录状态
- if (!handleLoginStatus(to, userStore, next)) {
- return
- }
+ // 1. 检查登录状态
+ if (!handleLoginStatus(to, userStore, next)) {
+ return
+ }
- // 2. 检查路由初始化是否已失败(防止死循环)
- if (routeInitFailed) {
- // 已经失败过,直接放行到错误页面,不再重试
- if (to.matched.length > 0) {
- next()
- } else {
- // 未匹配到路由,跳转到 500 页面
- next({ name: 'Exception500', replace: true })
- }
- return
- }
+ // 2. 检查路由初始化是否已失败(防止死循环)
+ if (routeInitFailed) {
+ // 已经失败过,直接放行到错误页面,不再重试
+ if (to.matched.length > 0) {
+ next()
+ } else {
+ // 未匹配到路由,跳转到 500 页面
+ next({ name: 'Exception500', replace: true })
+ }
+ return
+ }
- // 3. 处理动态路由注册
- if (!routeRegistry?.isRegistered() && userStore.isLogin) {
- // 防止并发请求(快速连续导航场景)
- if (routeInitInProgress) {
- // 正在初始化中,等待完成后重新导航
- next(false)
- return
- }
- await handleDynamicRoutes(to, next, router)
- return
- }
+ // 3. 处理动态路由注册
+ if (!routeRegistry?.isRegistered() && userStore.isLogin) {
+ // 防止并发请求(快速连续导航场景)
+ if (routeInitInProgress) {
+ // 正在初始化中,等待完成后重新导航
+ next(false)
+ return
+ }
+ await handleDynamicRoutes(to, next, router)
+ return
+ }
- // 4. 处理根路径重定向
- if (handleRootPathRedirect(to, next)) {
- return
- }
+ // 4. 处理根路径重定向
+ if (handleRootPathRedirect(to, next)) {
+ return
+ }
- // 5. 处理已匹配的路由
- if (to.matched.length > 0) {
- setWorktab(to)
- setPageTitle(to)
- next()
- return
- }
+ // 5. 处理已匹配的路由
+ if (to.matched.length > 0) {
+ setWorktab(to)
+ setPageTitle(to)
+ next()
+ return
+ }
- // 6. 未匹配到路由,跳转到 404
- next({ name: 'Exception404' })
+ // 6. 未匹配到路由,跳转到 404
+ next({ name: 'Exception404' })
}
/**
@@ -202,176 +202,176 @@ async function handleRouteGuard(
* @returns true 表示可以继续,false 表示已处理跳转
*/
function handleLoginStatus(
- to: RouteLocationNormalized,
- userStore: ReturnType,
- next: NavigationGuardNext
+ to: RouteLocationNormalized,
+ userStore: ReturnType,
+ next: NavigationGuardNext
): boolean {
- // 已登录或访问登录页或静态路由,直接放行
- if (userStore.isLogin || to.path === RoutesAlias.Login || isStaticRoute(to.path)) {
- return true
- }
+ // 已登录或访问登录页或静态路由,直接放行
+ if (userStore.isLogin || to.path === RoutesAlias.Login || isStaticRoute(to.path)) {
+ return true
+ }
- // 未登录且访问需要权限的页面,跳转到登录页并携带 redirect 参数
- userStore.logOut()
- next({
- name: 'Login',
- query: { redirect: to.fullPath }
- })
- return false
+ // 未登录且访问需要权限的页面,跳转到登录页并携带 redirect 参数
+ userStore.logOut()
+ next({
+ name: 'Login',
+ query: { redirect: to.fullPath }
+ })
+ return false
}
/**
* 检查路由是否为静态路由
*/
function isStaticRoute(path: string): boolean {
- const checkRoute = (routes: any[], targetPath: string): boolean => {
- return routes.some((route) => {
- // 处理动态路由参数匹配
- const routePath = route.path
- const pattern = routePath.replace(/:[^/]+/g, '[^/]+').replace(/\*/g, '.*')
- const regex = new RegExp(`^${pattern}$`)
+ const checkRoute = (routes: any[], targetPath: string): boolean => {
+ return routes.some((route) => {
+ // 处理动态路由参数匹配
+ const routePath = route.path
+ const pattern = routePath.replace(/:[^/]+/g, '[^/]+').replace(/\*/g, '.*')
+ const regex = new RegExp(`^${pattern}$`)
- if (regex.test(targetPath)) {
- return true
- }
- if (route.children && route.children.length > 0) {
- return checkRoute(route.children, targetPath)
- }
- return false
- })
- }
+ if (regex.test(targetPath)) {
+ return true
+ }
+ if (route.children && route.children.length > 0) {
+ return checkRoute(route.children, targetPath)
+ }
+ return false
+ })
+ }
- return checkRoute(staticRoutes, path)
+ return checkRoute(staticRoutes, path)
}
/**
* 处理动态路由注册
*/
async function handleDynamicRoutes(
- to: RouteLocationNormalized,
- next: NavigationGuardNext,
- router: Router
+ to: RouteLocationNormalized,
+ next: NavigationGuardNext,
+ router: Router
): Promise {
- // 标记初始化进行中
- routeInitInProgress = true
+ // 标记初始化进行中
+ routeInitInProgress = true
- // 显示 loading
- pendingLoading = true
- loadingService.showLoading()
+ // 显示 loading
+ pendingLoading = true
+ loadingService.showLoading()
- try {
- // 1. 获取用户信息
- await fetchUserInfo()
+ try {
+ // 1. 获取用户信息
+ await fetchUserInfo()
- // 2. 获取菜单数据
- const menuList = await menuProcessor.getMenuList()
+ // 2. 获取菜单数据
+ const menuList = await menuProcessor.getMenuList()
- // 3. 验证菜单数据
- if (!menuProcessor.validateMenuList(menuList)) {
- throw new Error('获取菜单列表失败,请重新登录')
- }
+ // 3. 验证菜单数据
+ if (!menuProcessor.validateMenuList(menuList)) {
+ throw new Error('获取菜单列表失败,请重新登录')
+ }
- // 4. 注册动态路由
- routeRegistry?.register(menuList)
+ // 4. 注册动态路由
+ routeRegistry?.register(menuList)
- // 5. 保存菜单数据到 store
- const menuStore = useMenuStore()
- menuStore.setMenuList(menuList)
- menuStore.addRemoveRouteFns(routeRegistry?.getRemoveRouteFns() || [])
+ // 5. 保存菜单数据到 store
+ const menuStore = useMenuStore()
+ menuStore.setMenuList(menuList)
+ menuStore.addRemoveRouteFns(routeRegistry?.getRemoveRouteFns() || [])
- // 6. 保存 iframe 路由
- IframeRouteManager.getInstance().save()
+ // 6. 保存 iframe 路由
+ IframeRouteManager.getInstance().save()
- // 7. 验证工作标签页
- useWorktabStore().validateWorktabs(router)
+ // 7. 验证工作标签页
+ useWorktabStore().validateWorktabs(router)
- // 8. 验证目标路径权限
- const { homePath } = useCommon()
- const { path: validatedPath, hasPermission } = RoutePermissionValidator.validatePath(
- to.path,
- menuList,
- homePath.value || '/'
- )
+ // 8. 验证目标路径权限
+ const { homePath } = useCommon()
+ const { path: validatedPath, hasPermission } = RoutePermissionValidator.validatePath(
+ to.path,
+ menuList,
+ homePath.value || '/'
+ )
- // 初始化成功,重置进行中标记
- routeInitInProgress = false
+ // 初始化成功,重置进行中标记
+ routeInitInProgress = false
- // 9. 重新导航到目标路由
- if (!hasPermission) {
- // 无权限访问,跳转到首页
- closeLoading()
+ // 9. 重新导航到目标路由
+ if (!hasPermission) {
+ // 无权限访问,跳转到首页
+ closeLoading()
- // 输出警告信息
- console.warn(`[RouteGuard] 用户无权限访问路径: ${to.path},已跳转到首页`)
+ // 输出警告信息
+ console.warn(`[RouteGuard] 用户无权限访问路径: ${to.path},已跳转到首页`)
- // 直接跳转到首页
- next({
- path: validatedPath,
- replace: true
- })
- } else {
- // 有权限,正常导航
- next({
- path: to.path,
- query: to.query,
- hash: to.hash,
- replace: true
- })
- }
- } catch (error) {
- console.error('[RouteGuard] 动态路由注册失败:', error)
+ // 直接跳转到首页
+ next({
+ path: validatedPath,
+ replace: true
+ })
+ } else {
+ // 有权限,正常导航
+ next({
+ path: to.path,
+ query: to.query,
+ hash: to.hash,
+ replace: true
+ })
+ }
+ } catch (error) {
+ console.error('[RouteGuard] 动态路由注册失败:', error)
- // 关闭 loading
- closeLoading()
+ // 关闭 loading
+ closeLoading()
- // 401 错误:axios 拦截器已处理退出登录,取消当前导航
- if (isUnauthorizedError(error)) {
- // 重置状态,允许重新登录后再次初始化
- routeInitInProgress = false
- next(false)
- return
- }
+ // 401 错误:axios 拦截器已处理退出登录,取消当前导航
+ if (isUnauthorizedError(error)) {
+ // 重置状态,允许重新登录后再次初始化
+ routeInitInProgress = false
+ next(false)
+ return
+ }
- // 标记初始化失败,防止死循环
- routeInitFailed = true
- routeInitInProgress = false
+ // 标记初始化失败,防止死循环
+ routeInitFailed = true
+ routeInitInProgress = false
- // 输出详细错误信息,便于排查
- if (isHttpError(error)) {
- console.error(`[RouteGuard] 错误码: ${error.code}, 消息: ${error.message}`)
- }
+ // 输出详细错误信息,便于排查
+ if (isHttpError(error)) {
+ console.error(`[RouteGuard] 错误码: ${error.code}, 消息: ${error.message}`)
+ }
- // 跳转到 500 页面,使用 replace 避免产生历史记录
- next({ name: 'Exception500', replace: true })
- }
+ // 跳转到 500 页面,使用 replace 避免产生历史记录
+ next({ name: 'Exception500', replace: true })
+ }
}
/**
* 获取用户信息
*/
async function fetchUserInfo(): Promise {
- const userStore = useUserStore()
- const data = await fetchGetUserInfo()
- userStore.setUserInfo(data)
- // 检查并清理工作台标签页(如果是不同用户登录)
- userStore.checkAndClearWorktabs()
+ const userStore = useUserStore()
+ const data = await fetchGetUserInfo()
+ userStore.setUserInfo(data)
+ // 检查并清理工作台标签页(如果是不同用户登录)
+ userStore.checkAndClearWorktabs()
}
/**
* 重置路由相关状态
*/
export function resetRouterState(delay: number): void {
- setTimeout(() => {
- routeRegistry?.unregister()
- IframeRouteManager.getInstance().clear()
+ setTimeout(() => {
+ routeRegistry?.unregister()
+ IframeRouteManager.getInstance().clear()
- const menuStore = useMenuStore()
- menuStore.removeAllDynamicRoutes()
- menuStore.setMenuList([])
+ const menuStore = useMenuStore()
+ menuStore.removeAllDynamicRoutes()
+ menuStore.setMenuList([])
- // 重置路由初始化状态,允许重新登录后再次初始化
- resetRouteInitState()
- }, delay)
+ // 重置路由初始化状态,允许重新登录后再次初始化
+ resetRouteInitState()
+ }, delay)
}
/**
@@ -379,22 +379,22 @@ export function resetRouterState(delay: number): void {
* @returns true 表示已处理跳转,false 表示无需跳转
*/
function handleRootPathRedirect(to: RouteLocationNormalized, next: NavigationGuardNext): boolean {
- if (to.path !== '/') {
- return false
- }
+ if (to.path !== '/') {
+ return false
+ }
- const { homePath } = useCommon()
- if (homePath.value && homePath.value !== '/') {
- next({ path: homePath.value, replace: true })
- return true
- }
+ const { homePath } = useCommon()
+ if (homePath.value && homePath.value !== '/') {
+ next({ path: homePath.value, replace: true })
+ return true
+ }
- return false
+ return false
}
/**
* 判断是否为未授权错误(401)
*/
function isUnauthorizedError(error: unknown): boolean {
- return isHttpError(error) && error.code === ApiStatus.unauthorized
+ return isHttpError(error) && error.code === ApiStatus.unauthorized
}
diff --git a/src/router/index.ts b/src/router/index.ts
index 286ae58..bd9c5ee 100644
--- a/src/router/index.ts
+++ b/src/router/index.ts
@@ -7,16 +7,16 @@ import { setupAfterEachGuard } from './guards/afterEach'
// 创建路由实例
export const router = createRouter({
- history: createWebHashHistory(),
- routes: staticRoutes // 静态路由
+ history: createWebHashHistory(),
+ routes: staticRoutes // 静态路由
})
// 初始化路由
export function initRouter(app: App): void {
- configureNProgress() // 顶部进度条
- setupBeforeEachGuard(router) // 路由前置守卫
- setupAfterEachGuard(router) // 路由后置守卫
- app.use(router)
+ configureNProgress() // 顶部进度条
+ setupBeforeEachGuard(router) // 路由前置守卫
+ setupAfterEachGuard(router) // 路由后置守卫
+ app.use(router)
}
// 主页路径,默认使用菜单第一个有效路径,配置后使用此路径
diff --git a/src/router/modules/dashboard.ts b/src/router/modules/dashboard.ts
index 5f9c3e9..c7036db 100644
--- a/src/router/modules/dashboard.ts
+++ b/src/router/modules/dashboard.ts
@@ -1,24 +1,24 @@
import { AppRouteRecord } from '@/types/router'
export const dashboardRoutes: AppRouteRecord = {
- name: 'Dashboard',
- path: '/dashboard',
- component: '/index/index',
- meta: {
- title: 'menus.dashboard.title',
- icon: 'ri:pie-chart-line',
- roles: ['R_SUPER', 'R_ADMIN']
- },
- children: [
- {
- path: 'console',
- name: 'Console',
- component: '/dashboard/console',
- meta: {
- title: 'menus.dashboard.console',
- keepAlive: false,
- fixedTab: true
- }
- }
- ]
+ name: 'Dashboard',
+ path: '/dashboard',
+ component: '/index/index',
+ meta: {
+ title: 'menus.dashboard.title',
+ icon: 'ri:pie-chart-line',
+ roles: ['R_SUPER', 'R_ADMIN']
+ },
+ children: [
+ {
+ path: 'console',
+ name: 'Console',
+ component: '/dashboard/console',
+ meta: {
+ title: 'menus.dashboard.console',
+ keepAlive: false,
+ fixedTab: true
+ }
+ }
+ ]
}
diff --git a/src/router/modules/exception.ts b/src/router/modules/exception.ts
index 07c5604..8aeea59 100644
--- a/src/router/modules/exception.ts
+++ b/src/router/modules/exception.ts
@@ -1,46 +1,46 @@
import { AppRouteRecord } from '@/types/router'
export const exceptionRoutes: AppRouteRecord = {
- path: '/exception',
- name: 'Exception',
- component: '/index/index',
- meta: {
- title: 'menus.exception.title',
- icon: 'ri:error-warning-line'
- },
- children: [
- {
- path: '403',
- name: 'Exception403',
- component: '/exception/403',
- meta: {
- title: 'menus.exception.forbidden',
- keepAlive: true,
- isHideTab: true,
- isFullPage: true
- }
- },
- {
- path: '404',
- name: 'Exception404',
- component: '/exception/404',
- meta: {
- title: 'menus.exception.notFound',
- keepAlive: true,
- isHideTab: true,
- isFullPage: true
- }
- },
- {
- path: '500',
- name: 'Exception500',
- component: '/exception/500',
- meta: {
- title: 'menus.exception.serverError',
- keepAlive: true,
- isHideTab: true,
- isFullPage: true
- }
- }
- ]
+ path: '/exception',
+ name: 'Exception',
+ component: '/index/index',
+ meta: {
+ title: 'menus.exception.title',
+ icon: 'ri:error-warning-line'
+ },
+ children: [
+ {
+ path: '403',
+ name: 'Exception403',
+ component: '/exception/403',
+ meta: {
+ title: 'menus.exception.forbidden',
+ keepAlive: true,
+ isHideTab: true,
+ isFullPage: true
+ }
+ },
+ {
+ path: '404',
+ name: 'Exception404',
+ component: '/exception/404',
+ meta: {
+ title: 'menus.exception.notFound',
+ keepAlive: true,
+ isHideTab: true,
+ isFullPage: true
+ }
+ },
+ {
+ path: '500',
+ name: 'Exception500',
+ component: '/exception/500',
+ meta: {
+ title: 'menus.exception.serverError',
+ keepAlive: true,
+ isHideTab: true,
+ isFullPage: true
+ }
+ }
+ ]
}
diff --git a/src/router/modules/index.ts b/src/router/modules/index.ts
index deff162..f0bc8df 100644
--- a/src/router/modules/index.ts
+++ b/src/router/modules/index.ts
@@ -8,8 +8,8 @@ import { exceptionRoutes } from './exception'
* 导出所有模块化路由
*/
export const routeModules: AppRouteRecord[] = [
- dashboardRoutes,
- systemRoutes,
- resultRoutes,
- exceptionRoutes
+ dashboardRoutes,
+ systemRoutes,
+ resultRoutes,
+ exceptionRoutes
]
diff --git a/src/router/modules/result.ts b/src/router/modules/result.ts
index 575a2f7..30a328d 100644
--- a/src/router/modules/result.ts
+++ b/src/router/modules/result.ts
@@ -1,33 +1,33 @@
import { AppRouteRecord } from '@/types/router'
export const resultRoutes: AppRouteRecord = {
- path: '/result',
- name: 'Result',
- component: '/index/index',
- meta: {
- title: 'menus.result.title',
- icon: 'ri:checkbox-circle-line'
- },
- children: [
- {
- path: 'success',
- name: 'ResultSuccess',
- component: '/result/success',
- meta: {
- title: 'menus.result.success',
- icon: 'ri:checkbox-circle-line',
- keepAlive: true
- }
- },
- {
- path: 'fail',
- name: 'ResultFail',
- component: '/result/fail',
- meta: {
- title: 'menus.result.fail',
- icon: 'ri:close-circle-line',
- keepAlive: true
- }
- }
- ]
+ path: '/result',
+ name: 'Result',
+ component: '/index/index',
+ meta: {
+ title: 'menus.result.title',
+ icon: 'ri:checkbox-circle-line'
+ },
+ children: [
+ {
+ path: 'success',
+ name: 'ResultSuccess',
+ component: '/result/success',
+ meta: {
+ title: 'menus.result.success',
+ icon: 'ri:checkbox-circle-line',
+ keepAlive: true
+ }
+ },
+ {
+ path: 'fail',
+ name: 'ResultFail',
+ component: '/result/fail',
+ meta: {
+ title: 'menus.result.fail',
+ icon: 'ri:close-circle-line',
+ keepAlive: true
+ }
+ }
+ ]
}
diff --git a/src/router/modules/system.ts b/src/router/modules/system.ts
index 16df585..be432b9 100644
--- a/src/router/modules/system.ts
+++ b/src/router/modules/system.ts
@@ -1,60 +1,60 @@
import { AppRouteRecord } from '@/types/router'
export const systemRoutes: AppRouteRecord = {
- path: '/system',
- name: 'System',
- component: '/index/index',
- meta: {
- title: 'menus.system.title',
- icon: 'ri:user-3-line',
- roles: ['R_SUPER', 'R_ADMIN']
- },
- children: [
- {
- path: 'user',
- name: 'User',
- component: '/system/user',
- meta: {
- title: 'menus.system.user',
- keepAlive: true,
- roles: ['R_SUPER', 'R_ADMIN']
- }
- },
- {
- path: 'role',
- name: 'Role',
- component: '/system/role',
- meta: {
- title: 'menus.system.role',
- keepAlive: true,
- roles: ['R_SUPER']
- }
- },
- {
- path: 'user-center',
- name: 'UserCenter',
- component: '/system/user-center',
- meta: {
- title: 'menus.system.userCenter',
- isHide: true,
- keepAlive: true,
- isHideTab: true
- }
- },
- {
- path: 'menu',
- name: 'Menus',
- component: '/system/menu',
- meta: {
- title: 'menus.system.menu',
- keepAlive: true,
- roles: ['R_SUPER'],
- authList: [
- { title: '新增', authMark: 'add' },
- { title: '编辑', authMark: 'edit' },
- { title: '删除', authMark: 'delete' }
- ]
- }
- }
- ]
+ path: '/system',
+ name: 'System',
+ component: '/index/index',
+ meta: {
+ title: 'menus.system.title',
+ icon: 'ri:user-3-line',
+ roles: ['R_SUPER', 'R_ADMIN']
+ },
+ children: [
+ {
+ path: 'user',
+ name: 'User',
+ component: '/system/user',
+ meta: {
+ title: 'menus.system.user',
+ keepAlive: true,
+ roles: ['R_SUPER', 'R_ADMIN']
+ }
+ },
+ {
+ path: 'role',
+ name: 'Role',
+ component: '/system/role',
+ meta: {
+ title: 'menus.system.role',
+ keepAlive: true,
+ roles: ['R_SUPER']
+ }
+ },
+ {
+ path: 'user-center',
+ name: 'UserCenter',
+ component: '/system/user-center',
+ meta: {
+ title: 'menus.system.userCenter',
+ isHide: true,
+ keepAlive: true,
+ isHideTab: true
+ }
+ },
+ {
+ path: 'menu',
+ name: 'Menus',
+ component: '/system/menu',
+ meta: {
+ title: 'menus.system.menu',
+ keepAlive: true,
+ roles: ['R_SUPER'],
+ authList: [
+ { title: '新增', authMark: 'add' },
+ { title: '编辑', authMark: 'edit' },
+ { title: '删除', authMark: 'delete' }
+ ]
+ }
+ }
+ ]
}
diff --git a/src/router/routes/staticRoutes.ts b/src/router/routes/staticRoutes.ts
index 334d0c2..f683034 100644
--- a/src/router/routes/staticRoutes.ts
+++ b/src/router/routes/staticRoutes.ts
@@ -11,62 +11,62 @@ import { AppRouteRecordRaw } from '@/utils/router'
* 2、静态路由不管是否登录都可以访问
*/
export const staticRoutes: AppRouteRecordRaw[] = [
- // 不需要登录就能访问的路由示例
- // {
- // path: '/welcome',
- // name: 'WelcomeStatic',
- // component: () => import('@views/dashboard/console/index.vue'),
- // meta: { title: 'menus.dashboard.title' }
- // },
- {
- path: '/auth/login',
- name: 'Login',
- component: () => import('@views/auth/login/index.vue'),
- meta: { title: 'menus.login.title', isHideTab: true }
- },
- {
- path: '/auth/register',
- name: 'Register',
- component: () => import('@views/auth/register/index.vue'),
- meta: { title: 'menus.register.title', isHideTab: true }
- },
- {
- path: '/auth/forget-password',
- name: 'ForgetPassword',
- component: () => import('@views/auth/forget-password/index.vue'),
- meta: { title: 'menus.forgetPassword.title', isHideTab: true }
- },
- {
- path: '/403',
- name: 'Exception403',
- component: () => import('@views/exception/403/index.vue'),
- meta: { title: '403', isHideTab: true }
- },
- {
- path: '/:pathMatch(.*)*',
- name: 'Exception404',
- component: () => import('@views/exception/404/index.vue'),
- meta: { title: '404', isHideTab: true }
- },
- {
- path: '/500',
- name: 'Exception500',
- component: () => import('@views/exception/500/index.vue'),
- meta: { title: '500', isHideTab: true }
- },
- {
- path: '/outside',
- component: () => import('@views/index/index.vue'),
- name: 'Outside',
- meta: { title: 'menus.outside.title' },
- children: [
- // iframe 内嵌页面
- {
- path: '/outside/iframe/:path',
- name: 'Iframe',
- component: () => import('@/views/outside/Iframe.vue'),
- meta: { title: 'iframe' }
- }
- ]
- }
+ // 不需要登录就能访问的路由示例
+ // {
+ // path: '/welcome',
+ // name: 'WelcomeStatic',
+ // component: () => import('@views/dashboard/console/index.vue'),
+ // meta: { title: 'menus.dashboard.title' }
+ // },
+ {
+ path: '/auth/login',
+ name: 'Login',
+ component: () => import('@views/auth/login/index.vue'),
+ meta: { title: 'menus.login.title', isHideTab: true }
+ },
+ {
+ path: '/auth/register',
+ name: 'Register',
+ component: () => import('@views/auth/register/index.vue'),
+ meta: { title: 'menus.register.title', isHideTab: true }
+ },
+ {
+ path: '/auth/forget-password',
+ name: 'ForgetPassword',
+ component: () => import('@views/auth/forget-password/index.vue'),
+ meta: { title: 'menus.forgetPassword.title', isHideTab: true }
+ },
+ {
+ path: '/403',
+ name: 'Exception403',
+ component: () => import('@views/exception/403/index.vue'),
+ meta: { title: '403', isHideTab: true }
+ },
+ {
+ path: '/:pathMatch(.*)*',
+ name: 'Exception404',
+ component: () => import('@views/exception/404/index.vue'),
+ meta: { title: '404', isHideTab: true }
+ },
+ {
+ path: '/500',
+ name: 'Exception500',
+ component: () => import('@views/exception/500/index.vue'),
+ meta: { title: '500', isHideTab: true }
+ },
+ {
+ path: '/outside',
+ component: () => import('@views/index/index.vue'),
+ name: 'Outside',
+ meta: { title: 'menus.outside.title' },
+ children: [
+ // iframe 内嵌页面
+ {
+ path: '/outside/iframe/:path',
+ name: 'Iframe',
+ component: () => import('@/views/outside/Iframe.vue'),
+ meta: { title: 'iframe' }
+ }
+ ]
+ }
]
diff --git a/src/router/routesAlias.ts b/src/router/routesAlias.ts
index 2af1c68..a14bb7c 100644
--- a/src/router/routesAlias.ts
+++ b/src/router/routesAlias.ts
@@ -3,6 +3,6 @@
# 存放系统级公共路由路径,如布局容器、登录页等
*/
export enum RoutesAlias {
- Layout = '/index/index', // 布局容器
- Login = '/auth/login' // 登录页
+ Layout = '/index/index', // 布局容器
+ Login = '/auth/login' // 登录页
}
diff --git a/src/store/index.ts b/src/store/index.ts
index b485999..bbd5fa5 100644
--- a/src/store/index.ts
+++ b/src/store/index.ts
@@ -34,19 +34,19 @@ const storageKeyManager = new StorageKeyManager()
// 配置持久化插件
store.use(
- createPersistedState({
- key: (storeId: string) => storageKeyManager.getStorageKey(storeId),
- storage: localStorage,
- serializer: {
- serialize: JSON.stringify,
- deserialize: JSON.parse
- }
- })
+ createPersistedState({
+ key: (storeId: string) => storageKeyManager.getStorageKey(storeId),
+ storage: localStorage,
+ serializer: {
+ serialize: JSON.stringify,
+ deserialize: JSON.parse
+ }
+ })
)
/**
* 初始化 Store
*/
export function initStore(app: App): void {
- app.use(store)
+ app.use(store)
}
diff --git a/src/store/modules/menu.ts b/src/store/modules/menu.ts
index 85d13da..dbbc0b7 100644
--- a/src/store/modules/menu.ts
+++ b/src/store/modules/menu.ts
@@ -39,71 +39,71 @@ import { HOME_PAGE_PATH } from '@/router'
* 管理应用的菜单列表、首页路径、菜单宽度和动态路由移除函数
*/
export const useMenuStore = defineStore('menuStore', () => {
- /** 首页路径 */
- const homePath = ref(HOME_PAGE_PATH)
- /** 菜单列表 */
- const menuList = ref([])
- /** 菜单宽度 */
- const menuWidth = ref('')
- /** 存储路由移除函数的数组 */
- const removeRouteFns = ref<(() => void)[]>([])
+ /** 首页路径 */
+ const homePath = ref(HOME_PAGE_PATH)
+ /** 菜单列表 */
+ const menuList = ref([])
+ /** 菜单宽度 */
+ const menuWidth = ref('')
+ /** 存储路由移除函数的数组 */
+ const removeRouteFns = ref<(() => void)[]>([])
- /**
- * 设置菜单列表
- * @param list 菜单路由记录数组
- */
- const setMenuList = (list: AppRouteRecord[]) => {
- menuList.value = list
- setHomePath(HOME_PAGE_PATH || getFirstMenuPath(list))
- }
+ /**
+ * 设置菜单列表
+ * @param list 菜单路由记录数组
+ */
+ const setMenuList = (list: AppRouteRecord[]) => {
+ menuList.value = list
+ setHomePath(HOME_PAGE_PATH || getFirstMenuPath(list))
+ }
- /**
- * 获取首页路径
- * @returns 首页路径字符串
- */
- const getHomePath = () => homePath.value
+ /**
+ * 获取首页路径
+ * @returns 首页路径字符串
+ */
+ const getHomePath = () => homePath.value
- /**
- * 设置主页路径
- * @param path 主页路径
- */
- const setHomePath = (path: string) => {
- homePath.value = path
- }
+ /**
+ * 设置主页路径
+ * @param path 主页路径
+ */
+ const setHomePath = (path: string) => {
+ homePath.value = path
+ }
- /**
- * 添加路由移除函数
- * @param fns 要添加的路由移除函数数组
- */
- const addRemoveRouteFns = (fns: (() => void)[]) => {
- removeRouteFns.value.push(...fns)
- }
+ /**
+ * 添加路由移除函数
+ * @param fns 要添加的路由移除函数数组
+ */
+ const addRemoveRouteFns = (fns: (() => void)[]) => {
+ removeRouteFns.value.push(...fns)
+ }
- /**
- * 移除所有动态路由
- * 执行所有存储的路由移除函数并清空数组
- */
- const removeAllDynamicRoutes = () => {
- removeRouteFns.value.forEach((fn) => fn())
- removeRouteFns.value = []
- }
+ /**
+ * 移除所有动态路由
+ * 执行所有存储的路由移除函数并清空数组
+ */
+ const removeAllDynamicRoutes = () => {
+ removeRouteFns.value.forEach((fn) => fn())
+ removeRouteFns.value = []
+ }
- /**
- * 清空路由移除函数数组
- */
- const clearRemoveRouteFns = () => {
- removeRouteFns.value = []
- }
+ /**
+ * 清空路由移除函数数组
+ */
+ const clearRemoveRouteFns = () => {
+ removeRouteFns.value = []
+ }
- return {
- menuList,
- menuWidth,
- removeRouteFns,
- setMenuList,
- getHomePath,
- setHomePath,
- addRemoveRouteFns,
- removeAllDynamicRoutes,
- clearRemoveRouteFns
- }
+ return {
+ menuList,
+ menuWidth,
+ removeRouteFns,
+ setMenuList,
+ getHomePath,
+ setHomePath,
+ addRemoveRouteFns,
+ removeAllDynamicRoutes,
+ clearRemoveRouteFns
+ }
})
diff --git a/src/store/modules/setting.ts b/src/store/modules/setting.ts
index 2878259..bdb97b2 100644
--- a/src/store/modules/setting.ts
+++ b/src/store/modules/setting.ts
@@ -45,406 +45,408 @@ import { SETTING_DEFAULT_CONFIG } from '@/config/setting'
* 管理应用的菜单、主题、界面显示等各项设置
*/
export const useSettingStore = defineStore(
- 'settingStore',
- () => {
- // 菜单相关设置
- /** 菜单类型 */
- const menuType = ref(SETTING_DEFAULT_CONFIG.menuType)
- /** 菜单展开宽度 */
- const menuOpenWidth = ref(SETTING_DEFAULT_CONFIG.menuOpenWidth)
- /** 菜单是否展开 */
- const menuOpen = ref(SETTING_DEFAULT_CONFIG.menuOpen)
- /** 双菜单是否显示文本 */
- const dualMenuShowText = ref(SETTING_DEFAULT_CONFIG.dualMenuShowText)
+ 'settingStore',
+ () => {
+ // 菜单相关设置
+ /** 菜单类型 */
+ const menuType = ref(SETTING_DEFAULT_CONFIG.menuType)
+ /** 菜单展开宽度 */
+ const menuOpenWidth = ref(SETTING_DEFAULT_CONFIG.menuOpenWidth)
+ /** 菜单是否展开 */
+ const menuOpen = ref(SETTING_DEFAULT_CONFIG.menuOpen)
+ /** 双菜单是否显示文本 */
+ const dualMenuShowText = ref(SETTING_DEFAULT_CONFIG.dualMenuShowText)
- // 主题相关设置
- /** 系统主题类型 */
- const systemThemeType = ref(SETTING_DEFAULT_CONFIG.systemThemeType)
- /** 系统主题模式 */
- const systemThemeMode = ref(SETTING_DEFAULT_CONFIG.systemThemeMode)
- /** 菜单主题类型 */
- const menuThemeType = ref(SETTING_DEFAULT_CONFIG.menuThemeType)
- /** 系统主题颜色 */
- const systemThemeColor = ref(SETTING_DEFAULT_CONFIG.systemThemeColor)
+ // 主题相关设置
+ /** 系统主题类型 */
+ const systemThemeType = ref(SETTING_DEFAULT_CONFIG.systemThemeType)
+ /** 系统主题模式 */
+ const systemThemeMode = ref(SETTING_DEFAULT_CONFIG.systemThemeMode)
+ /** 菜单主题类型 */
+ const menuThemeType = ref(SETTING_DEFAULT_CONFIG.menuThemeType)
+ /** 系统主题颜色 */
+ const systemThemeColor = ref(SETTING_DEFAULT_CONFIG.systemThemeColor)
- // 界面显示设置
- /** 是否显示菜单按钮 */
- const showMenuButton = ref(SETTING_DEFAULT_CONFIG.showMenuButton)
- /** 是否显示快速入口 */
- const showFastEnter = ref(SETTING_DEFAULT_CONFIG.showFastEnter)
- /** 是否显示刷新按钮 */
- const showRefreshButton = ref(SETTING_DEFAULT_CONFIG.showRefreshButton)
- /** 是否显示面包屑 */
- const showCrumbs = ref(SETTING_DEFAULT_CONFIG.showCrumbs)
- /** 是否显示工作台标签 */
- const showWorkTab = ref(SETTING_DEFAULT_CONFIG.showWorkTab)
- /** 是否显示语言切换 */
- const showLanguage = ref(SETTING_DEFAULT_CONFIG.showLanguage)
- /** 是否显示进度条 */
- const showNprogress = ref(SETTING_DEFAULT_CONFIG.showNprogress)
- /** 是否显示设置引导 */
- const showSettingGuide = ref(SETTING_DEFAULT_CONFIG.showSettingGuide)
- /** 是否显示节日文本 */
- const showFestivalText = ref(SETTING_DEFAULT_CONFIG.showFestivalText)
- /** 是否显示水印 */
- const watermarkVisible = ref(SETTING_DEFAULT_CONFIG.watermarkVisible)
+ // 界面显示设置
+ /** 是否显示菜单按钮 */
+ const showMenuButton = ref(SETTING_DEFAULT_CONFIG.showMenuButton)
+ /** 是否显示快速入口 */
+ const showFastEnter = ref(SETTING_DEFAULT_CONFIG.showFastEnter)
+ /** 是否显示刷新按钮 */
+ const showRefreshButton = ref(SETTING_DEFAULT_CONFIG.showRefreshButton)
+ /** 是否显示面包屑 */
+ const showCrumbs = ref(SETTING_DEFAULT_CONFIG.showCrumbs)
+ /** 是否显示工作台标签 */
+ const showWorkTab = ref(SETTING_DEFAULT_CONFIG.showWorkTab)
+ /** 是否显示语言切换 */
+ const showLanguage = ref(SETTING_DEFAULT_CONFIG.showLanguage)
+ /** 是否显示进度条 */
+ const showNprogress = ref(SETTING_DEFAULT_CONFIG.showNprogress)
+ /** 是否显示设置引导 */
+ const showSettingGuide = ref(SETTING_DEFAULT_CONFIG.showSettingGuide)
+ /** 是否显示节日文本 */
+ const showFestivalText = ref(SETTING_DEFAULT_CONFIG.showFestivalText)
+ /** 是否显示水印 */
+ const watermarkVisible = ref(SETTING_DEFAULT_CONFIG.watermarkVisible)
- // 功能设置
- /** 是否自动关闭 */
- const autoClose = ref(SETTING_DEFAULT_CONFIG.autoClose)
- /** 是否唯一展开 */
- const uniqueOpened = ref(SETTING_DEFAULT_CONFIG.uniqueOpened)
- /** 是否色弱模式 */
- const colorWeak = ref(SETTING_DEFAULT_CONFIG.colorWeak)
- /** 是否刷新 */
- const refresh = ref(SETTING_DEFAULT_CONFIG.refresh)
- /** 是否加载节日烟花 */
- const holidayFireworksLoaded = ref(SETTING_DEFAULT_CONFIG.holidayFireworksLoaded)
+ // 功能设置
+ /** 是否自动关闭 */
+ const autoClose = ref(SETTING_DEFAULT_CONFIG.autoClose)
+ /** 是否唯一展开 */
+ const uniqueOpened = ref(SETTING_DEFAULT_CONFIG.uniqueOpened)
+ /** 是否色弱模式 */
+ const colorWeak = ref(SETTING_DEFAULT_CONFIG.colorWeak)
+ /** 是否刷新 */
+ const refresh = ref(SETTING_DEFAULT_CONFIG.refresh)
+ /** 是否加载节日烟花 */
+ const holidayFireworksLoaded = ref(SETTING_DEFAULT_CONFIG.holidayFireworksLoaded)
- // 样式设置
- /** 边框模式 */
- const boxBorderMode = ref(SETTING_DEFAULT_CONFIG.boxBorderMode)
- /** 页面过渡效果 */
- const pageTransition = ref(SETTING_DEFAULT_CONFIG.pageTransition)
- /** 标签页样式 */
- const tabStyle = ref(SETTING_DEFAULT_CONFIG.tabStyle)
- /** 自定义圆角 */
- const customRadius = ref(SETTING_DEFAULT_CONFIG.customRadius)
- /** 容器宽度 */
- const containerWidth = ref(SETTING_DEFAULT_CONFIG.containerWidth)
+ // 样式设置
+ /** 边框模式 */
+ const boxBorderMode = ref(SETTING_DEFAULT_CONFIG.boxBorderMode)
+ /** 页面过渡效果 */
+ const pageTransition = ref(SETTING_DEFAULT_CONFIG.pageTransition)
+ /** 标签页样式 */
+ const tabStyle = ref(SETTING_DEFAULT_CONFIG.tabStyle)
+ /** 自定义圆角 */
+ const customRadius = ref(SETTING_DEFAULT_CONFIG.customRadius)
+ /** 容器宽度 */
+ const containerWidth = ref(SETTING_DEFAULT_CONFIG.containerWidth)
- // 节日相关
- /** 节日日期 */
- const festivalDate = ref('')
+ // 节日相关
+ /** 节日日期 */
+ const festivalDate = ref('')
- /**
- * 获取菜单主题
- * 根据当前主题类型和暗色模式返回对应的主题配置
- */
- const getMenuTheme = computed((): MenuThemeType => {
- const list = AppConfig.themeList.filter((item) => item.theme === menuThemeType.value)
- if (isDark.value) {
- return AppConfig.darkMenuStyles[0]
- } else {
- return list[0]
- }
- })
+ /**
+ * 获取菜单主题
+ * 根据当前主题类型和暗色模式返回对应的主题配置
+ */
+ const getMenuTheme = computed((): MenuThemeType => {
+ const list = AppConfig.themeList.filter((item) => item.theme === menuThemeType.value)
+ if (isDark.value) {
+ return AppConfig.darkMenuStyles[0]
+ } else {
+ return list[0]
+ }
+ })
- /**
- * 判断是否为暗色模式
- */
- const isDark = computed((): boolean => {
- return systemThemeType.value === SystemThemeEnum.DARK
- })
+ /**
+ * 判断是否为暗色模式
+ */
+ const isDark = computed((): boolean => {
+ return systemThemeType.value === SystemThemeEnum.DARK
+ })
- /**
- * 获取菜单展开宽度
- */
- const getMenuOpenWidth = computed((): string => {
- return menuOpenWidth.value + 'px' || SETTING_DEFAULT_CONFIG.menuOpenWidth + 'px'
- })
+ /**
+ * 获取菜单展开宽度
+ */
+ const getMenuOpenWidth = computed((): string => {
+ return menuOpenWidth.value + 'px' || SETTING_DEFAULT_CONFIG.menuOpenWidth + 'px'
+ })
- /**
- * 获取自定义圆角
- */
- const getCustomRadius = computed((): string => {
- return customRadius.value + 'rem' || SETTING_DEFAULT_CONFIG.customRadius + 'rem'
- })
+ /**
+ * 获取自定义圆角
+ */
+ const getCustomRadius = computed((): string => {
+ return customRadius.value + 'rem' || SETTING_DEFAULT_CONFIG.customRadius + 'rem'
+ })
- /**
- * 是否显示烟花
- * 根据当前日期和节日日期判断是否显示烟花效果
- */
- const isShowFireworks = computed((): boolean => {
- return festivalDate.value === useCeremony().currentFestivalData.value?.date ? false : true
- })
+ /**
+ * 是否显示烟花
+ * 根据当前日期和节日日期判断是否显示烟花效果
+ */
+ const isShowFireworks = computed((): boolean => {
+ return festivalDate.value === useCeremony().currentFestivalData.value?.date
+ ? false
+ : true
+ })
- /**
- * 切换菜单布局
- * @param type 菜单类型
- */
- const switchMenuLayouts = (type: MenuTypeEnum) => {
- menuType.value = type
- }
+ /**
+ * 切换菜单布局
+ * @param type 菜单类型
+ */
+ const switchMenuLayouts = (type: MenuTypeEnum) => {
+ menuType.value = type
+ }
- /**
- * 设置菜单展开宽度
- * @param width 宽度值
- */
- const setMenuOpenWidth = (width: number) => {
- menuOpenWidth.value = width
- }
+ /**
+ * 设置菜单展开宽度
+ * @param width 宽度值
+ */
+ const setMenuOpenWidth = (width: number) => {
+ menuOpenWidth.value = width
+ }
- /**
- * 设置全局主题
- * @param theme 主题类型
- * @param themeMode 主题模式
- */
- const setGlopTheme = (theme: SystemThemeEnum, themeMode: SystemThemeEnum) => {
- systemThemeType.value = theme
- systemThemeMode.value = themeMode
- localStorage.setItem(StorageConfig.THEME_KEY, theme)
- }
+ /**
+ * 设置全局主题
+ * @param theme 主题类型
+ * @param themeMode 主题模式
+ */
+ const setGlopTheme = (theme: SystemThemeEnum, themeMode: SystemThemeEnum) => {
+ systemThemeType.value = theme
+ systemThemeMode.value = themeMode
+ localStorage.setItem(StorageConfig.THEME_KEY, theme)
+ }
- /**
- * 切换菜单样式
- * @param theme 菜单主题
- */
- const switchMenuStyles = (theme: MenuThemeEnum) => {
- menuThemeType.value = theme
- }
+ /**
+ * 切换菜单样式
+ * @param theme 菜单主题
+ */
+ const switchMenuStyles = (theme: MenuThemeEnum) => {
+ menuThemeType.value = theme
+ }
- /**
- * 设置Element Plus主题颜色
- * @param theme 主题颜色
- */
- const setElementTheme = (theme: string) => {
- systemThemeColor.value = theme
- setElementThemeColor(theme)
- }
+ /**
+ * 设置Element Plus主题颜色
+ * @param theme 主题颜色
+ */
+ const setElementTheme = (theme: string) => {
+ systemThemeColor.value = theme
+ setElementThemeColor(theme)
+ }
- /**
- * 切换边框模式
- */
- const setBorderMode = () => {
- boxBorderMode.value = !boxBorderMode.value
- }
+ /**
+ * 切换边框模式
+ */
+ const setBorderMode = () => {
+ boxBorderMode.value = !boxBorderMode.value
+ }
- /**
- * 设置容器宽度
- * @param width 容器宽度枚举值
- */
- const setContainerWidth = (width: ContainerWidthEnum) => {
- containerWidth.value = width
- }
+ /**
+ * 设置容器宽度
+ * @param width 容器宽度枚举值
+ */
+ const setContainerWidth = (width: ContainerWidthEnum) => {
+ containerWidth.value = width
+ }
- /**
- * 切换唯一展开模式
- */
- const setUniqueOpened = () => {
- uniqueOpened.value = !uniqueOpened.value
- }
+ /**
+ * 切换唯一展开模式
+ */
+ const setUniqueOpened = () => {
+ uniqueOpened.value = !uniqueOpened.value
+ }
- /**
- * 切换菜单按钮显示
- */
- const setButton = () => {
- showMenuButton.value = !showMenuButton.value
- }
+ /**
+ * 切换菜单按钮显示
+ */
+ const setButton = () => {
+ showMenuButton.value = !showMenuButton.value
+ }
- /**
- * 切换快速入口显示
- */
- const setFastEnter = () => {
- showFastEnter.value = !showFastEnter.value
- }
+ /**
+ * 切换快速入口显示
+ */
+ const setFastEnter = () => {
+ showFastEnter.value = !showFastEnter.value
+ }
- /**
- * 切换自动关闭
- */
- const setAutoClose = () => {
- autoClose.value = !autoClose.value
- }
+ /**
+ * 切换自动关闭
+ */
+ const setAutoClose = () => {
+ autoClose.value = !autoClose.value
+ }
- /**
- * 切换刷新按钮显示
- */
- const setShowRefreshButton = () => {
- showRefreshButton.value = !showRefreshButton.value
- }
+ /**
+ * 切换刷新按钮显示
+ */
+ const setShowRefreshButton = () => {
+ showRefreshButton.value = !showRefreshButton.value
+ }
- /**
- * 切换面包屑显示
- */
- const setCrumbs = () => {
- showCrumbs.value = !showCrumbs.value
- }
+ /**
+ * 切换面包屑显示
+ */
+ const setCrumbs = () => {
+ showCrumbs.value = !showCrumbs.value
+ }
- /**
- * 设置工作台标签显示
- * @param show 是否显示
- */
- const setWorkTab = (show: boolean) => {
- showWorkTab.value = show
- }
+ /**
+ * 设置工作台标签显示
+ * @param show 是否显示
+ */
+ const setWorkTab = (show: boolean) => {
+ showWorkTab.value = show
+ }
- /**
- * 切换语言切换显示
- */
- const setLanguage = () => {
- showLanguage.value = !showLanguage.value
- }
+ /**
+ * 切换语言切换显示
+ */
+ const setLanguage = () => {
+ showLanguage.value = !showLanguage.value
+ }
- /**
- * 切换进度条显示
- */
- const setNprogress = () => {
- showNprogress.value = !showNprogress.value
- }
+ /**
+ * 切换进度条显示
+ */
+ const setNprogress = () => {
+ showNprogress.value = !showNprogress.value
+ }
- /**
- * 切换色弱模式
- */
- const setColorWeak = () => {
- colorWeak.value = !colorWeak.value
- }
+ /**
+ * 切换色弱模式
+ */
+ const setColorWeak = () => {
+ colorWeak.value = !colorWeak.value
+ }
- /**
- * 隐藏设置引导
- */
- const hideSettingGuide = () => {
- showSettingGuide.value = false
- }
+ /**
+ * 隐藏设置引导
+ */
+ const hideSettingGuide = () => {
+ showSettingGuide.value = false
+ }
- /**
- * 显示设置引导
- */
- const openSettingGuide = () => {
- showSettingGuide.value = true
- }
+ /**
+ * 显示设置引导
+ */
+ const openSettingGuide = () => {
+ showSettingGuide.value = true
+ }
- /**
- * 设置页面过渡效果
- * @param transition 过渡效果名称
- */
- const setPageTransition = (transition: string) => {
- pageTransition.value = transition
- }
+ /**
+ * 设置页面过渡效果
+ * @param transition 过渡效果名称
+ */
+ const setPageTransition = (transition: string) => {
+ pageTransition.value = transition
+ }
- /**
- * 设置标签页样式
- * @param style 样式名称
- */
- const setTabStyle = (style: string) => {
- tabStyle.value = style
- }
+ /**
+ * 设置标签页样式
+ * @param style 样式名称
+ */
+ const setTabStyle = (style: string) => {
+ tabStyle.value = style
+ }
- /**
- * 设置菜单展开状态
- * @param open 是否展开
- */
- const setMenuOpen = (open: boolean) => {
- menuOpen.value = open
- }
+ /**
+ * 设置菜单展开状态
+ * @param open 是否展开
+ */
+ const setMenuOpen = (open: boolean) => {
+ menuOpen.value = open
+ }
- /**
- * 刷新页面
- */
- const reload = () => {
- refresh.value = !refresh.value
- }
+ /**
+ * 刷新页面
+ */
+ const reload = () => {
+ refresh.value = !refresh.value
+ }
- /**
- * 设置水印显示
- * @param visible 是否显示
- */
- const setWatermarkVisible = (visible: boolean) => {
- watermarkVisible.value = visible
- }
+ /**
+ * 设置水印显示
+ * @param visible 是否显示
+ */
+ const setWatermarkVisible = (visible: boolean) => {
+ watermarkVisible.value = visible
+ }
- /**
- * 设置自定义圆角
- * @param radius 圆角值
- */
- const setCustomRadius = (radius: string) => {
- customRadius.value = radius
- document.documentElement.style.setProperty('--custom-radius', `${radius}rem`)
- }
+ /**
+ * 设置自定义圆角
+ * @param radius 圆角值
+ */
+ const setCustomRadius = (radius: string) => {
+ customRadius.value = radius
+ document.documentElement.style.setProperty('--custom-radius', `${radius}rem`)
+ }
- /**
- * 设置节日烟花加载状态
- * @param isLoad 是否已加载
- */
- const setholidayFireworksLoaded = (isLoad: boolean) => {
- holidayFireworksLoaded.value = isLoad
- }
+ /**
+ * 设置节日烟花加载状态
+ * @param isLoad 是否已加载
+ */
+ const setholidayFireworksLoaded = (isLoad: boolean) => {
+ holidayFireworksLoaded.value = isLoad
+ }
- /**
- * 设置节日文本显示
- * @param show 是否显示
- */
- const setShowFestivalText = (show: boolean) => {
- showFestivalText.value = show
- }
+ /**
+ * 设置节日文本显示
+ * @param show 是否显示
+ */
+ const setShowFestivalText = (show: boolean) => {
+ showFestivalText.value = show
+ }
- const setFestivalDate = (date: string) => {
- festivalDate.value = date
- }
+ const setFestivalDate = (date: string) => {
+ festivalDate.value = date
+ }
- const setDualMenuShowText = (show: boolean) => {
- dualMenuShowText.value = show
- }
+ const setDualMenuShowText = (show: boolean) => {
+ dualMenuShowText.value = show
+ }
- return {
- menuType,
- menuOpenWidth,
- systemThemeType,
- systemThemeMode,
- menuThemeType,
- systemThemeColor,
- boxBorderMode,
- uniqueOpened,
- showMenuButton,
- showFastEnter,
- showRefreshButton,
- showCrumbs,
- autoClose,
- showWorkTab,
- showLanguage,
- showNprogress,
- colorWeak,
- showSettingGuide,
- pageTransition,
- tabStyle,
- menuOpen,
- refresh,
- watermarkVisible,
- customRadius,
- holidayFireworksLoaded,
- showFestivalText,
- festivalDate,
- dualMenuShowText,
- containerWidth,
- getMenuTheme,
- isDark,
- getMenuOpenWidth,
- getCustomRadius,
- isShowFireworks,
- switchMenuLayouts,
- setMenuOpenWidth,
- setGlopTheme,
- switchMenuStyles,
- setElementTheme,
- setBorderMode,
- setContainerWidth,
- setUniqueOpened,
- setButton,
- setFastEnter,
- setAutoClose,
- setShowRefreshButton,
- setCrumbs,
- setWorkTab,
- setLanguage,
- setNprogress,
- setColorWeak,
- hideSettingGuide,
- openSettingGuide,
- setPageTransition,
- setTabStyle,
- setMenuOpen,
- reload,
- setWatermarkVisible,
- setCustomRadius,
- setholidayFireworksLoaded,
- setShowFestivalText,
- setFestivalDate,
- setDualMenuShowText
- }
- },
- {
- persist: {
- key: 'setting',
- storage: localStorage
- }
- }
+ return {
+ menuType,
+ menuOpenWidth,
+ systemThemeType,
+ systemThemeMode,
+ menuThemeType,
+ systemThemeColor,
+ boxBorderMode,
+ uniqueOpened,
+ showMenuButton,
+ showFastEnter,
+ showRefreshButton,
+ showCrumbs,
+ autoClose,
+ showWorkTab,
+ showLanguage,
+ showNprogress,
+ colorWeak,
+ showSettingGuide,
+ pageTransition,
+ tabStyle,
+ menuOpen,
+ refresh,
+ watermarkVisible,
+ customRadius,
+ holidayFireworksLoaded,
+ showFestivalText,
+ festivalDate,
+ dualMenuShowText,
+ containerWidth,
+ getMenuTheme,
+ isDark,
+ getMenuOpenWidth,
+ getCustomRadius,
+ isShowFireworks,
+ switchMenuLayouts,
+ setMenuOpenWidth,
+ setGlopTheme,
+ switchMenuStyles,
+ setElementTheme,
+ setBorderMode,
+ setContainerWidth,
+ setUniqueOpened,
+ setButton,
+ setFastEnter,
+ setAutoClose,
+ setShowRefreshButton,
+ setCrumbs,
+ setWorkTab,
+ setLanguage,
+ setNprogress,
+ setColorWeak,
+ hideSettingGuide,
+ openSettingGuide,
+ setPageTransition,
+ setTabStyle,
+ setMenuOpen,
+ reload,
+ setWatermarkVisible,
+ setCustomRadius,
+ setholidayFireworksLoaded,
+ setShowFestivalText,
+ setFestivalDate,
+ setDualMenuShowText
+ }
+ },
+ {
+ persist: {
+ key: 'setting',
+ storage: localStorage
+ }
+ }
)
diff --git a/src/store/modules/table.ts b/src/store/modules/table.ts
index 094c310..5d9d958 100644
--- a/src/store/modules/table.ts
+++ b/src/store/modules/table.ts
@@ -31,67 +31,67 @@ import { TableSizeEnum } from '@/enums/formEnum'
// 表格
export const useTableStore = defineStore(
- 'tableStore',
- () => {
- // 表格大小
- const tableSize = ref(TableSizeEnum.DEFAULT)
- // 斑马纹
- const isZebra = ref(false)
- // 边框
- const isBorder = ref(false)
- // 表头背景
- const isHeaderBackground = ref(false)
+ 'tableStore',
+ () => {
+ // 表格大小
+ const tableSize = ref(TableSizeEnum.DEFAULT)
+ // 斑马纹
+ const isZebra = ref(false)
+ // 边框
+ const isBorder = ref(false)
+ // 表头背景
+ const isHeaderBackground = ref(false)
- // 是否全屏
- const isFullScreen = ref(false)
+ // 是否全屏
+ const isFullScreen = ref(false)
- /**
- * 设置表格大小
- * @param size 表格大小枚举值
- */
- const setTableSize = (size: TableSizeEnum) => (tableSize.value = size)
+ /**
+ * 设置表格大小
+ * @param size 表格大小枚举值
+ */
+ const setTableSize = (size: TableSizeEnum) => (tableSize.value = size)
- /**
- * 设置斑马纹显示状态
- * @param value 是否显示斑马纹
- */
- const setIsZebra = (value: boolean) => (isZebra.value = value)
+ /**
+ * 设置斑马纹显示状态
+ * @param value 是否显示斑马纹
+ */
+ const setIsZebra = (value: boolean) => (isZebra.value = value)
- /**
- * 设置表格边框显示状态
- * @param value 是否显示边框
- */
- const setIsBorder = (value: boolean) => (isBorder.value = value)
+ /**
+ * 设置表格边框显示状态
+ * @param value 是否显示边框
+ */
+ const setIsBorder = (value: boolean) => (isBorder.value = value)
- /**
- * 设置表头背景显示状态
- * @param value 是否显示表头背景
- */
- const setIsHeaderBackground = (value: boolean) => (isHeaderBackground.value = value)
+ /**
+ * 设置表头背景显示状态
+ * @param value 是否显示表头背景
+ */
+ const setIsHeaderBackground = (value: boolean) => (isHeaderBackground.value = value)
- /**
- * 设置是否全屏
- * @param value 是否全屏
- */
- const setIsFullScreen = (value: boolean) => (isFullScreen.value = value)
+ /**
+ * 设置是否全屏
+ * @param value 是否全屏
+ */
+ const setIsFullScreen = (value: boolean) => (isFullScreen.value = value)
- return {
- tableSize,
- isZebra,
- isBorder,
- isHeaderBackground,
- setTableSize,
- setIsZebra,
- setIsBorder,
- setIsHeaderBackground,
- isFullScreen,
- setIsFullScreen
- }
- },
- {
- persist: {
- key: 'table',
- storage: localStorage
- }
- }
+ return {
+ tableSize,
+ isZebra,
+ isBorder,
+ isHeaderBackground,
+ setTableSize,
+ setIsZebra,
+ setIsBorder,
+ setIsHeaderBackground,
+ isFullScreen,
+ setIsFullScreen
+ }
+ },
+ {
+ persist: {
+ key: 'table',
+ storage: localStorage
+ }
+ }
)
diff --git a/src/store/modules/user.ts b/src/store/modules/user.ts
index 08f7684..a0b804a 100644
--- a/src/store/modules/user.ts
+++ b/src/store/modules/user.ts
@@ -48,188 +48,188 @@ import { StorageConfig } from '@/utils/storage/storage-config'
* 管理用户登录状态、个人信息、语言设置、搜索历史、锁屏状态等
*/
export const useUserStore = defineStore(
- 'userStore',
- () => {
- // 语言设置
- const language = ref(LanguageEnum.ZH)
- // 登录状态
- const isLogin = ref(false)
- // 锁屏状态
- const isLock = ref(false)
- // 锁屏密码
- const lockPassword = ref('')
- // 用户信息
- const info = ref>({})
- // 搜索历史记录
- const searchHistory = ref([])
- // 访问令牌
- const accessToken = ref('')
- // 刷新令牌
- const refreshToken = ref('')
+ 'userStore',
+ () => {
+ // 语言设置
+ const language = ref(LanguageEnum.ZH)
+ // 登录状态
+ const isLogin = ref(false)
+ // 锁屏状态
+ const isLock = ref(false)
+ // 锁屏密码
+ const lockPassword = ref('')
+ // 用户信息
+ const info = ref>({})
+ // 搜索历史记录
+ const searchHistory = ref([])
+ // 访问令牌
+ const accessToken = ref('')
+ // 刷新令牌
+ const refreshToken = ref('')
- // 计算属性:获取用户信息
- const getUserInfo = computed(() => info.value)
- // 计算属性:获取设置状态
- const getSettingState = computed(() => useSettingStore().$state)
- // 计算属性:获取工作台状态
- const getWorktabState = computed(() => useWorktabStore().$state)
+ // 计算属性:获取用户信息
+ const getUserInfo = computed(() => info.value)
+ // 计算属性:获取设置状态
+ const getSettingState = computed(() => useSettingStore().$state)
+ // 计算属性:获取工作台状态
+ const getWorktabState = computed(() => useWorktabStore().$state)
- /**
- * 设置用户信息
- * @param newInfo 新的用户信息
- */
- const setUserInfo = (newInfo: Api.Auth.UserInfo) => {
- info.value = newInfo
- }
+ /**
+ * 设置用户信息
+ * @param newInfo 新的用户信息
+ */
+ const setUserInfo = (newInfo: Api.Auth.UserInfo) => {
+ info.value = newInfo
+ }
- /**
- * 设置登录状态
- * @param status 登录状态
- */
- const setLoginStatus = (status: boolean) => {
- isLogin.value = status
- }
+ /**
+ * 设置登录状态
+ * @param status 登录状态
+ */
+ const setLoginStatus = (status: boolean) => {
+ isLogin.value = status
+ }
- /**
- * 设置语言
- * @param lang 语言枚举值
- */
- const setLanguage = (lang: LanguageEnum) => {
- setPageTitle(router.currentRoute.value)
- language.value = lang
- }
+ /**
+ * 设置语言
+ * @param lang 语言枚举值
+ */
+ const setLanguage = (lang: LanguageEnum) => {
+ setPageTitle(router.currentRoute.value)
+ language.value = lang
+ }
- /**
- * 设置搜索历史
- * @param list 搜索历史列表
- */
- const setSearchHistory = (list: AppRouteRecord[]) => {
- searchHistory.value = list
- }
+ /**
+ * 设置搜索历史
+ * @param list 搜索历史列表
+ */
+ const setSearchHistory = (list: AppRouteRecord[]) => {
+ searchHistory.value = list
+ }
- /**
- * 设置锁屏状态
- * @param status 锁屏状态
- */
- const setLockStatus = (status: boolean) => {
- isLock.value = status
- }
+ /**
+ * 设置锁屏状态
+ * @param status 锁屏状态
+ */
+ const setLockStatus = (status: boolean) => {
+ isLock.value = status
+ }
- /**
- * 设置锁屏密码
- * @param password 锁屏密码
- */
- const setLockPassword = (password: string) => {
- lockPassword.value = password
- }
+ /**
+ * 设置锁屏密码
+ * @param password 锁屏密码
+ */
+ const setLockPassword = (password: string) => {
+ lockPassword.value = password
+ }
- /**
- * 设置令牌
- * @param newAccessToken 访问令牌
- * @param newRefreshToken 刷新令牌(可选)
- */
- const setToken = (newAccessToken: string, newRefreshToken?: string) => {
- accessToken.value = newAccessToken
- if (newRefreshToken) {
- refreshToken.value = newRefreshToken
- }
- }
+ /**
+ * 设置令牌
+ * @param newAccessToken 访问令牌
+ * @param newRefreshToken 刷新令牌(可选)
+ */
+ const setToken = (newAccessToken: string, newRefreshToken?: string) => {
+ accessToken.value = newAccessToken
+ if (newRefreshToken) {
+ refreshToken.value = newRefreshToken
+ }
+ }
- /**
- * 退出登录
- * 清空所有用户相关状态并跳转到登录页
- * 如果是同一账号重新登录,保留工作台标签页
- */
- const logOut = () => {
- // 保存当前用户 ID,用于下次登录时判断是否为同一用户
- const currentUserId = info.value.userId
- if (currentUserId) {
- localStorage.setItem(StorageConfig.LAST_USER_ID_KEY, String(currentUserId))
- }
+ /**
+ * 退出登录
+ * 清空所有用户相关状态并跳转到登录页
+ * 如果是同一账号重新登录,保留工作台标签页
+ */
+ const logOut = () => {
+ // 保存当前用户 ID,用于下次登录时判断是否为同一用户
+ const currentUserId = info.value.userId
+ if (currentUserId) {
+ localStorage.setItem(StorageConfig.LAST_USER_ID_KEY, String(currentUserId))
+ }
- // 清空用户信息
- info.value = {}
- // 重置登录状态
- isLogin.value = false
- // 重置锁屏状态
- isLock.value = false
- // 清空锁屏密码
- lockPassword.value = ''
- // 清空访问令牌
- accessToken.value = ''
- // 清空刷新令牌
- refreshToken.value = ''
- // 注意:不清空工作台标签页,等下次登录时根据用户判断
- // 移除iframe路由缓存
- sessionStorage.removeItem('iframeRoutes')
- // 清空主页路径
- useMenuStore().setHomePath('')
- // 重置路由状态
- resetRouterState(500)
- // 跳转到登录页,携带当前路由作为 redirect 参数
- const currentRoute = router.currentRoute.value
- const redirect = currentRoute.path !== '/login' ? currentRoute.fullPath : undefined
- router.push({
- name: 'Login',
- query: redirect ? { redirect } : undefined
- })
- }
+ // 清空用户信息
+ info.value = {}
+ // 重置登录状态
+ isLogin.value = false
+ // 重置锁屏状态
+ isLock.value = false
+ // 清空锁屏密码
+ lockPassword.value = ''
+ // 清空访问令牌
+ accessToken.value = ''
+ // 清空刷新令牌
+ refreshToken.value = ''
+ // 注意:不清空工作台标签页,等下次登录时根据用户判断
+ // 移除iframe路由缓存
+ sessionStorage.removeItem('iframeRoutes')
+ // 清空主页路径
+ useMenuStore().setHomePath('')
+ // 重置路由状态
+ resetRouterState(500)
+ // 跳转到登录页,携带当前路由作为 redirect 参数
+ const currentRoute = router.currentRoute.value
+ const redirect = currentRoute.path !== '/login' ? currentRoute.fullPath : undefined
+ router.push({
+ name: 'Login',
+ query: redirect ? { redirect } : undefined
+ })
+ }
- /**
- * 检查并清理工作台标签页
- * 如果不是同一用户登录,清空工作台标签页
- * 应在登录成功后调用
- */
- const checkAndClearWorktabs = () => {
- const lastUserId = localStorage.getItem(StorageConfig.LAST_USER_ID_KEY)
- const currentUserId = info.value.userId
+ /**
+ * 检查并清理工作台标签页
+ * 如果不是同一用户登录,清空工作台标签页
+ * 应在登录成功后调用
+ */
+ const checkAndClearWorktabs = () => {
+ const lastUserId = localStorage.getItem(StorageConfig.LAST_USER_ID_KEY)
+ const currentUserId = info.value.userId
- // 无法获取当前用户 ID,跳过检查
- if (!currentUserId) return
+ // 无法获取当前用户 ID,跳过检查
+ if (!currentUserId) return
- // 首次登录或缓存已清除,保留现有标签页
- if (!lastUserId) {
- return
- }
+ // 首次登录或缓存已清除,保留现有标签页
+ if (!lastUserId) {
+ return
+ }
- // 不同用户登录,清空工作台标签页
- if (String(currentUserId) !== lastUserId) {
- const worktabStore = useWorktabStore()
- worktabStore.opened = []
- worktabStore.keepAliveExclude = []
- }
+ // 不同用户登录,清空工作台标签页
+ if (String(currentUserId) !== lastUserId) {
+ const worktabStore = useWorktabStore()
+ worktabStore.opened = []
+ worktabStore.keepAliveExclude = []
+ }
- // 清除临时存储
- localStorage.removeItem(StorageConfig.LAST_USER_ID_KEY)
- }
+ // 清除临时存储
+ localStorage.removeItem(StorageConfig.LAST_USER_ID_KEY)
+ }
- return {
- language,
- isLogin,
- isLock,
- lockPassword,
- info,
- searchHistory,
- accessToken,
- refreshToken,
- getUserInfo,
- getSettingState,
- getWorktabState,
- setUserInfo,
- setLoginStatus,
- setLanguage,
- setSearchHistory,
- setLockStatus,
- setLockPassword,
- setToken,
- logOut,
- checkAndClearWorktabs
- }
- },
- {
- persist: {
- key: 'user',
- storage: localStorage
- }
- }
+ return {
+ language,
+ isLogin,
+ isLock,
+ lockPassword,
+ info,
+ searchHistory,
+ accessToken,
+ refreshToken,
+ getUserInfo,
+ getSettingState,
+ getWorktabState,
+ setUserInfo,
+ setLoginStatus,
+ setLanguage,
+ setSearchHistory,
+ setLockStatus,
+ setLockPassword,
+ setToken,
+ logOut,
+ checkAndClearWorktabs
+ }
+ },
+ {
+ persist: {
+ key: 'user',
+ storage: localStorage
+ }
+ }
)
diff --git a/src/store/modules/worktab.ts b/src/store/modules/worktab.ts
index caa0d90..8c74858 100644
--- a/src/store/modules/worktab.ts
+++ b/src/store/modules/worktab.ts
@@ -45,524 +45,528 @@ import { WorkTab } from '@/types'
import { useCommon } from '@/hooks/core/useCommon'
interface WorktabState {
- current: Partial
- opened: WorkTab[]
- keepAliveExclude: string[]
+ current: Partial
+ opened: WorkTab[]
+ keepAliveExclude: string[]
}
/**
* 工作台标签页管理 Store
*/
export const useWorktabStore = defineStore(
- 'worktabStore',
- () => {
- // 状态定义
- const current = ref