This commit is contained in:
萌狼蓝天
2025-09-07 21:38:41 +08:00
9 changed files with 259 additions and 306 deletions

13
.vscode/settings.json vendored
View File

@@ -63,19 +63,8 @@
"**/dist/**": true,
"**/yarn.lock": true
},
"i18n-ally.keystyle": "nested",
"i18n-ally.sortKeys": true,
"i18n-ally.namespace": false,
"i18n-ally.pathMatcher": "{namespaces}/{locale}.{ext}",
"i18n-ally.enabledParsers": ["ts"],
"i18n-ally.sourceLanguage": "en",
"i18n-ally.displayLanguage": "zh-CN",
"i18n-ally.enabledFrameworks": [
"vue",
"react"
],
"i18n-ally.localesPaths": [
"src/lang"
"src/lang/package"
],
"scss.lint.unknownAtRules": "ignore"
}

View File

@@ -1,11 +1,16 @@
// https://eslint.org/docs/latest/use/configure/configuration-files-new
// 基础ESLint配置
import eslint from "@eslint/js";
import pluginVue from "eslint-plugin-vue";
import * as typescriptEslint from "typescript-eslint";
import vueParser from "vue-eslint-parser";
import globals from "globals";
// TypeScript支持
import * as typescriptEslint from "typescript-eslint";
// Vue支持
import pluginVue from "eslint-plugin-vue";
import vueParser from "vue-eslint-parser";
// 代码风格与格式化
import configPrettier from "eslint-config-prettier";
import prettierPlugin from "eslint-plugin-prettier";
// 解析自动导入配置
import fs from "node:fs";
@@ -132,6 +137,7 @@ export default [
sourceType: "module",
parser: typescriptEslint.parser,
extraFileExtensions: [".vue"],
tsconfigRootDir: __dirname,
},
},
rules: {
@@ -174,8 +180,10 @@ export default [
languageOptions: {
parser: typescriptEslint.parser,
parserOptions: {
project: true,
tsconfigRootDir: import.meta.dirname,
ecmaVersion: "latest",
sourceType: "module",
project: "./tsconfig.json",
tsconfigRootDir: __dirname,
},
},
rules: {
@@ -212,5 +220,15 @@ export default [
},
// Prettier 集成(必须放在最后)
configPrettier,
{
plugins: {
prettier: prettierPlugin, // 将 Prettier 的输出作为 ESLint 的问题来报告
},
rules: {
...configPrettier.rules,
"prettier/prettier": ["error", {}, { usePrettierrc: true }],
"arrow-body-style": "off",
"prefer-arrow-callback": "off",
},
},
];

View File

@@ -2,18 +2,14 @@ import type { App } from "vue";
import { createI18n } from "vue-i18n";
import { useAppStoreHook } from "@/store/modules/app-store";
// 本地语言包
import enLocale from "./package/en";
import zhCnLocale from "./package/zh-cn";
import enLocale from "./package/en.json";
import zhCnLocale from "./package/zh-cn.json";
const appStore = useAppStoreHook();
const messages = {
"zh-cn": {
...zhCnLocale,
},
en: {
...enLocale,
},
"zh-cn": zhCnLocale,
en: enLocale,
};
const i18n = createI18n({

91
src/lang/package/en.json Normal file
View File

@@ -0,0 +1,91 @@
{
"route": {
"dashboard": "Dashboard",
"document": "Document"
},
"login": {
"themeToggle": "Theme Switch",
"languageToggle": "Language Switch",
"dark": "Dark",
"light": "Light",
"username": "Username",
"password": "Password",
"login": "Login",
"captchaCode": "Verify Code",
"capsLock": "Caps Lock is On",
"rememberMe": "Remember Me",
"forgetPassword": "Forget Password?",
"message": {
"username": {
"required": "Please enter Username"
},
"password": {
"required": "Please enter Password",
"min": "The password can not be less than 6 digits",
"confirm": "Please confirm the password again",
"inconformity": "The two password entries are inconsistent"
},
"captchaCode": {
"required": "Please enter Verify Code"
}
},
"otherLoginMethods": "Other",
"resetPassword": "Reset password",
"thinkOfPasswd": "Remember your password?",
"register": "Register account",
"agree": "I have read and agree to the",
"userAgreement": "User Agreement",
"haveAccount": "Already have an account?",
"noAccount": "Don't have an account?",
"quickFill": "Quick fill",
"reg": "Register"
},
"navbar": {
"dashboard": "Dashboard",
"logout": "Logout",
"document": "Document",
"gitee": "Gitee",
"profile": "User Profile"
},
"sizeSelect": {
"tooltip": "Layout Size",
"default": "Default",
"large": "Large",
"small": "Small",
"message": {
"success": "Switch Layout Size Successful!"
}
},
"langSelect": {
"message": {
"success": "Switch Language Successful!"
}
},
"settings": {
"project": "Project Settings",
"theme": "Theme",
"interface": "Interface",
"navigation": "Navigation",
"themeColor": "Theme Color",
"showTagsView": "Show Tags View",
"showAppLogo": "Show App Logo",
"sidebarColorScheme": "Sidebar Color Scheme",
"showWatermark": "Show Watermark",
"classicBlue": "Classic Blue",
"minimalWhite": "Minimal White",
"copyConfig": "Copy Config",
"resetConfig": "Reset Default",
"copySuccess": "Configuration copied to clipboard",
"resetSuccess": "Reset to default configuration",
"copyDescription": "Copy config will generate current settings code, reset will restore all settings to default",
"confirmReset": "Are you sure to reset all settings to default? This operation cannot be undone.",
"applyToFile": "Apply to File",
"onlyCopy": "Only Copy",
"leftLayout": "Left Mode",
"topLayout": "Top Mode",
"mixLayout": "Mix Mode",
"configManagement": "Config Management",
"copyConfigDescription": "Generate current settings code and copy to clipboard, then overwrite src/settings.ts file",
"resetConfigDescription": "Restore all settings to system default values"
}
}

View File

@@ -1,96 +0,0 @@
export default {
// 菜单国际化
route: {
dashboard: "Dashboard",
document: "Document",
},
// 登录页面国际化
login: {
themeToggle: "Theme Switch",
languageToggle: "Language Switch",
dark: "Dark",
light: "Light",
username: "Username",
password: "Password",
login: "Login",
captchaCode: "Verify Code",
capsLock: "Caps Lock is On",
rememberMe: "Remember Me",
forgetPassword: "Forget Password?",
message: {
username: {
required: "Please enter Username",
},
password: {
required: "Please enter Password",
min: "The password can not be less than 6 digits",
confirm: "Please confirm the password again",
inconformity: "The two password entries are inconsistent",
},
captchaCode: {
required: "Please enter Verify Code",
},
},
otherLoginMethods: "Other",
resetPassword: "Reset password",
thinkOfPasswd: "Remember your password?",
register: "Register account",
agree: "I have read and agree to the",
userAgreement: "User Agreement",
haveAccount: "Already have an account?",
noAccount: "Don't have an account?",
quickFill: "Quick fill",
reg: "Register",
},
// 导航栏国际化
navbar: {
dashboard: "Dashboard",
logout: "Logout",
document: "Document",
gitee: "Gitee",
profile: "User Profile",
},
sizeSelect: {
tooltip: "Layout Size",
default: "Default",
large: "Large",
small: "Small",
message: {
success: "Switch Layout Size Successful!",
},
},
langSelect: {
message: {
success: "Switch Language Successful!",
},
},
settings: {
project: "Project Settings",
theme: "Theme",
interface: "Interface",
navigation: "Navigation",
themeColor: "Theme Color",
showTagsView: "Show Tags View",
showAppLogo: "Show App Logo",
sidebarColorScheme: "Sidebar Color Scheme",
showWatermark: "Show Watermark",
classicBlue: "Classic Blue",
minimalWhite: "Minimal White",
copyConfig: "Copy Config",
resetConfig: "Reset Default",
copySuccess: "Configuration copied to clipboard",
resetSuccess: "Reset to default configuration",
copyDescription:
"Copy config will generate current settings code, reset will restore all settings to default",
confirmReset: "Are you sure to reset all settings to default? This operation cannot be undone.",
applyToFile: "Apply to File",
onlyCopy: "Only Copy",
leftLayout: "Left Mode",
topLayout: "Top Mode",
mixLayout: "Mix Mode",
configManagement: "Config Management",
copyConfigDescription:
"Generate current settings code and copy to clipboard, then overwrite src/settings.ts file",
resetConfigDescription: "Restore all settings to system default values",
},
};

View File

@@ -0,0 +1,94 @@
{
"route": {
"dashboard": "首页",
"document": "项目文档"
},
"login": {
"themeToggle": "主题切换",
"languageToggle": "语言切换",
"dark": "暗黑",
"light": "明亮",
"username": "用户名",
"password": "密码",
"login": "登 录",
"captchaCode": "验证码",
"capsLock": "大写锁定已打开",
"rememberMe": "记住我",
"forgetPassword": "忘记密码?",
"message": {
"username": {
"required": "请输入用户名"
},
"password": {
"required": "请输入密码",
"min": "密码不能少于6位",
"confirm": "请再次确认密码",
"inconformity": "两次密码输入不一致"
},
"captchaCode": {
"required": "请输入验证码"
}
},
"otherLoginMethods": "其他",
"resetPassword": "重置密码",
"thinkOfPasswd": "想起密码?",
"register": "注册账号",
"agree": "我已同意并阅读",
"userAgreement": "用户协议",
"haveAccount": "已有账号?",
"noAccount": "您没有账号?",
"quickFill": "快速填写",
"reg": "注 册"
},
"navbar": {
"dashboard": "首页",
"logout": "退出登录",
"document": "项目文档",
"gitee": "项目地址",
"profile": "个人中心"
},
"sizeSelect": {
"tooltip": "布局大小",
"default": "默认",
"large": "大型",
"small": "小型",
"message": {
"success": "切换布局大小成功!"
}
},
"langSelect": {
"message": {
"success": "切换语言成功!"
}
},
"settings": {
"project": "项目配置",
"theme": "主题设置",
"interface": "界面设置",
"navigation": "导航设置",
"themeColor": "主题颜色",
"themeColorTip": "主题颜色",
"darkMode": "暗黑模式",
"layoutSetting": "布局设置",
"sidebarColorScheme": "侧边栏配色",
"showTagsView": "显示页签",
"showAppLogo": "显示Logo",
"showWatermark": "显示水印",
"classicBlue": "经典蓝",
"minimalWhite": "极简白",
"copyConfig": "复制配置",
"resetConfig": "重置默认",
"copySuccess": "配置已复制到剪贴板",
"resetSuccess": "已重置为默认配置",
"copyDescription": "复制配置将生成当前设置的代码,重置将恢复所有设置为默认值",
"confirmReset": "确定要重置所有设置为默认值吗?此操作不可恢复。",
"applyToFile": "应用到文件",
"onlyCopy": "仅复制",
"leftLayout": "左侧模式",
"topLayout": "顶部模式",
"mixLayout": "混合模式",
"configManagement": "配置管理",
"copyConfigDescription": "生成当前设置的代码并复制到剪贴板,然后覆盖 src/settings.ts 文件",
"resetConfigDescription": "恢复所有设置为系统默认值"
}
}

View File

@@ -1,97 +0,0 @@
export default {
// 菜单国际化
route: {
dashboard: "首页",
document: "项目文档",
},
// 登录页面国际化
login: {
themeToggle: "主题切换",
languageToggle: "语言切换",
dark: "暗黑",
light: "明亮",
username: "用户名",
password: "密码",
login: "登 录",
captchaCode: "验证码",
capsLock: "大写锁定已打开",
rememberMe: "记住我",
forgetPassword: "忘记密码?",
message: {
username: {
required: "请输入用户名",
},
password: {
required: "请输入密码",
min: "密码不能少于6位",
confirm: "请再次确认密码",
inconformity: "两次密码输入不一致",
},
captchaCode: {
required: "请输入验证码",
},
},
otherLoginMethods: "其他",
resetPassword: "重置密码",
thinkOfPasswd: "想起密码?",
register: "注册账号",
agree: "我已同意并阅读",
userAgreement: "用户协议",
haveAccount: "已有账号?",
noAccount: "您没有账号?",
quickFill: "快速填写",
reg: "注 册",
},
// 导航栏国际化
navbar: {
dashboard: "首页",
logout: "退出登录",
document: "项目文档",
gitee: "项目地址",
profile: "个人中心",
},
sizeSelect: {
tooltip: "布局大小",
default: "默认",
large: "大型",
small: "小型",
message: {
success: "切换布局大小成功!",
},
},
langSelect: {
message: {
success: "切换语言成功!",
},
},
settings: {
project: "项目配置",
theme: "主题设置",
interface: "界面设置",
navigation: "导航设置",
themeColor: "主题颜色",
themeColorTip: "主题颜色",
darkMode: "暗黑模式",
layoutSetting: "布局设置",
sidebarColorScheme: "侧边栏配色",
showTagsView: "显示页签",
showAppLogo: "显示Logo",
showWatermark: "显示水印",
classicBlue: "经典蓝",
minimalWhite: "极简白",
copyConfig: "复制配置",
resetConfig: "重置默认",
copySuccess: "配置已复制到剪贴板",
resetSuccess: "已重置为默认配置",
copyDescription: "复制配置将生成当前设置的代码,重置将恢复所有设置为默认值",
confirmReset: "确定要重置所有设置为默认值吗?此操作不可恢复。",
applyToFile: "应用到文件",
onlyCopy: "仅复制",
leftLayout: "左侧模式",
topLayout: "顶部模式",
mixLayout: "混合模式",
configManagement: "配置管理",
copyConfigDescription: "生成当前设置的代码并复制到剪贴板,然后覆盖 src/settings.ts 文件",
resetConfigDescription: "恢复所有设置为系统默认值",
},
};

View File

@@ -107,40 +107,35 @@
</div>
<!-- 操作按钮区域 - 固定到底部 -->
<div class="action-footer">
<div class="action-divider"></div>
<div class="action-card">
<div class="action-buttons">
<el-tooltip
content="复制配置将生成当前设置的代码,覆盖 src/settings.ts 下的 defaultSettings 变量"
placement="top"
<template #footer>
<div class="action-buttons">
<el-tooltip
content="复制配置将生成当前设置的代码,覆盖 src/settings.ts 下的 defaultSettings 变量"
placement="top"
>
<el-button
type="primary"
size="default"
:icon="copyIcon"
:loading="copyLoading"
@click="handleCopySettings"
>
<el-button
type="primary"
size="default"
:icon="copyIcon"
:loading="copyLoading"
class="action-btn"
@click="handleCopySettings"
>
{{ copyLoading ? "复制中..." : t("settings.copyConfig") }}
</el-button>
</el-tooltip>
<el-tooltip content="重置将恢复所有设置为默认值" placement="top">
<el-button
type="warning"
size="default"
:icon="resetIcon"
:loading="resetLoading"
class="action-btn"
@click="handleResetSettings"
>
{{ resetLoading ? "重置中..." : t("settings.resetConfig") }}
</el-button>
</el-tooltip>
</div>
{{ copyLoading ? "复制中..." : t("settings.copyConfig") }}
</el-button>
</el-tooltip>
<el-tooltip content="重置将恢复所有设置为默认值" placement="top">
<el-button
type="warning"
size="default"
:icon="resetIcon"
:loading="resetLoading"
@click="handleResetSettings"
>
{{ resetLoading ? "重置中..." : t("settings.resetConfig") }}
</el-button>
</el-tooltip>
</div>
</div>
</template>
</el-drawer>
</template>
@@ -326,47 +321,22 @@ const handleCloseDrawer = () => {
.settings-content {
height: calc(100vh - 120px); /* 减去头部和底部按钮的高度 */
padding: 20px;
padding-bottom: 20px;
overflow-y: auto;
}
/* 底部操作区域样式 */
.action-footer {
position: absolute;
right: 0;
bottom: 0;
left: 0;
z-index: 10;
padding: 0;
background: var(--el-bg-color);
border-top: 1px solid var(--el-border-color-light);
.action-buttons {
display: flex;
.action-divider {
display: none; /* 移除重复的分割线 */
}
& > .el-button {
flex: 1;
font-size: 14px;
border-radius: 8px;
transition: all 0.3s ease;
.action-card {
padding: 16px 20px;
margin: 0;
background: var(--el-fill-color-extra-light);
border: none;
border-radius: 0;
.action-buttons {
display: flex;
gap: 12px;
.action-btn {
flex: 1;
font-size: 14px;
border-radius: 8px;
transition: all 0.3s ease;
&:hover {
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
transform: translateY(-2px);
}
}
&:hover {
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
transform: translateY(-2px);
}
}
}

View File

@@ -107,31 +107,19 @@ const parseDynamicRoutes = (rawRoutes: RouteVO[]): RouteRecordRaw[] => {
};
/**
* 去除中间层的路由 `component` 属性
* 路由处理函数
* - 去除中间层路由 `component: Layout` 的 `component` 属性
* @param routes 路由数组
* @param isTopLevel 是否是顶层路由
*/
const processRoutes = (routes: RouteVO[], isTopLevel: boolean = true): RouteVO[] => {
return routes.map((route) => {
// 创建新对象
const newRoute: RouteVO = {
path: route.path,
name: route.name,
children: route.children,
meta: { ...route.meta },
return routes.map(({ component, children, ...args }) => {
return {
...args,
component: isTopLevel || component !== "Layout" ? component : undefined,
// 递归处理children标记为非顶层
children: children && children.length > 0 ? processRoutes(children, false) : [],
};
// 如果是顶层或者component不是"Layout"保留component属性
if (isTopLevel || route.component !== "Layout") {
newRoute.component = route.component;
}
// 递归处理children标记为非顶层
if (route.children && route.children.length > 0) {
newRoute.children = processRoutes(route.children, false);
}
return newRoute;
});
};