feat(projects): new i18n function $t & login page and setting drawer config i18n

This commit is contained in:
Soybean 2023-07-23 20:19:47 +08:00
parent 458e387b68
commit 854d0bcf20
49 changed files with 1176 additions and 543 deletions

29
.vscode/settings.json vendored
View File

@ -1,11 +1,32 @@
{ {
"cSpell.ignorePaths": [
"package.json",
"package-lock.json",
"yarn.lock",
"pnpm-lock.yaml",
"node_modules",
"vscode-extension",
".git/objects",
".vscode",
".vscode-insiders",
"CHANGELOG.md",
"dist",
"public",
"styles"
],
"cSpell.words": [ "cSpell.words": [
"AMAP", "AMAP",
"antv", "antv",
"bmapgl",
"colord", "colord",
"echarts", "echarts",
"gitee",
"gridicons",
"iconify", "iconify",
"jsapi",
"naiveui",
"Sider", "Sider",
"tauri",
"unocss", "unocss",
"unplugin", "unplugin",
"vditor", "vditor",
@ -29,7 +50,13 @@
"*.svg": "html" "*.svg": "html"
}, },
"files.eol": "\n", "files.eol": "\n",
"i18n-ally.localesPaths": ["src/locales", "src/locales/lang"], "i18n-ally.displayLanguage": "zh-CN",
"i18n-ally.enabledParsers": ["ts"],
"i18n-ally.enabledFrameworks": ["vue"],
"i18n-ally.editor.preferEditor": true,
"i18n-ally.keystyle": "nested",
"i18n-ally.localesPaths": ["src/locales/lang"],
"material-icon-theme.activeIconPack": "vue",
"[html][css][less][scss][sass][markdown][yaml][yml][jsonc]": { "[html][css][less][scss][sass][markdown][yaml][yml][jsonc]": {
"editor.defaultFormatter": "esbenp.prettier-vscode", "editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true "editor.formatOnSave": true

View File

@ -13,7 +13,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
title: '分析页', title: '分析页',
requiresAuth: true, requiresAuth: true,
icon: 'icon-park-outline:analysis', icon: 'icon-park-outline:analysis',
i18nTitle: 'message.routes.dashboard.analysis' i18nTitle: 'routes.dashboard.analysis'
} }
}, },
{ {
@ -24,7 +24,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
title: '工作台', title: '工作台',
requiresAuth: true, requiresAuth: true,
icon: 'icon-park-outline:workbench', icon: 'icon-park-outline:workbench',
i18nTitle: 'message.routes.dashboard.workbench' i18nTitle: 'routes.dashboard.workbench'
} }
} }
], ],
@ -32,7 +32,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
title: '仪表盘', title: '仪表盘',
icon: 'mdi:monitor-dashboard', icon: 'mdi:monitor-dashboard',
order: 1, order: 1,
i18nTitle: 'message.routes.dashboard._value' i18nTitle: 'routes.dashboard._value'
} }
}, },
{ {
@ -46,7 +46,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self', component: 'self',
meta: { meta: {
title: 'vue文档', title: 'vue文档',
i18nTitle: 'message.routes.document.vue', i18nTitle: 'routes.document.vue',
requiresAuth: true, requiresAuth: true,
icon: 'logos:vue' icon: 'logos:vue'
} }
@ -57,7 +57,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self', component: 'self',
meta: { meta: {
title: 'vite文档', title: 'vite文档',
i18nTitle: 'message.routes.document.vite', i18nTitle: 'routes.document.vite',
requiresAuth: true, requiresAuth: true,
icon: 'logos:vitejs' icon: 'logos:vitejs'
} }
@ -68,7 +68,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self', component: 'self',
meta: { meta: {
title: 'naive文档', title: 'naive文档',
i18nTitle: 'message.routes.document.naive', i18nTitle: 'routes.document.naive',
requiresAuth: true, requiresAuth: true,
icon: 'logos:naiveui' icon: 'logos:naiveui'
} }
@ -79,7 +79,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self', component: 'self',
meta: { meta: {
title: '项目文档', title: '项目文档',
i18nTitle: 'message.routes.document.project', i18nTitle: 'routes.document.project',
requiresAuth: true, requiresAuth: true,
localIcon: 'logo' localIcon: 'logo'
} }
@ -89,7 +89,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
path: '/document/project-link', path: '/document/project-link',
meta: { meta: {
title: '项目文档(外链)', title: '项目文档(外链)',
i18nTitle: 'message.routes.document.project-link', i18nTitle: 'routes.document.project-link',
requiresAuth: true, requiresAuth: true,
localIcon: 'logo', localIcon: 'logo',
href: 'https://docs.soybean.pro/' href: 'https://docs.soybean.pro/'
@ -98,7 +98,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
], ],
meta: { meta: {
title: '文档', title: '文档',
i18nTitle: 'message.routes.document._value', i18nTitle: 'routes.document._value',
icon: 'mdi:file-document-multiple-outline', icon: 'mdi:file-document-multiple-outline',
order: 2 order: 2
} }
@ -114,7 +114,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self', component: 'self',
meta: { meta: {
title: '按钮', title: '按钮',
i18nTitle: 'message.routes.component.button', i18nTitle: 'routes.component.button',
requiresAuth: true, requiresAuth: true,
icon: 'mdi:button-cursor' icon: 'mdi:button-cursor'
} }
@ -125,7 +125,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self', component: 'self',
meta: { meta: {
title: '卡片', title: '卡片',
i18nTitle: 'message.routes.component.card', i18nTitle: 'routes.component.card',
requiresAuth: true, requiresAuth: true,
icon: 'mdi:card-outline' icon: 'mdi:card-outline'
} }
@ -136,7 +136,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self', component: 'self',
meta: { meta: {
title: '表格', title: '表格',
i18nTitle: 'message.routes.component.table', i18nTitle: 'routes.component.table',
requiresAuth: true, requiresAuth: true,
icon: 'mdi:table-large' icon: 'mdi:table-large'
} }
@ -144,7 +144,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
], ],
meta: { meta: {
title: '组件示例', title: '组件示例',
i18nTitle: 'message.routes.component._value', i18nTitle: 'routes.component._value',
icon: 'cib:app-store', icon: 'cib:app-store',
order: 3 order: 3
} }
@ -165,7 +165,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self', component: 'self',
meta: { meta: {
title: 'ECharts', title: 'ECharts',
i18nTitle: 'message.routes.plugin.charts.echarts', i18nTitle: 'routes.plugin.charts.echarts',
requiresAuth: true, requiresAuth: true,
icon: 'simple-icons:apacheecharts' icon: 'simple-icons:apacheecharts'
} }
@ -176,7 +176,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self', component: 'self',
meta: { meta: {
title: 'AntV', title: 'AntV',
i18nTitle: 'message.routes.plugin.charts.antv', i18nTitle: 'routes.plugin.charts.antv',
requiresAuth: true, requiresAuth: true,
icon: 'simple-icons:antdesign' icon: 'simple-icons:antdesign'
} }
@ -184,7 +184,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
], ],
meta: { meta: {
title: '图表', title: '图表',
i18nTitle: 'message.routes.plugin.charts._value', i18nTitle: 'routes.plugin.charts._value',
icon: 'mdi:chart-areaspline' icon: 'mdi:chart-areaspline'
} }
}, },
@ -194,7 +194,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self', component: 'self',
meta: { meta: {
title: '地图', title: '地图',
i18nTitle: 'message.routes.plugin.map', i18nTitle: 'routes.plugin.map',
requiresAuth: true, requiresAuth: true,
icon: 'mdi:map' icon: 'mdi:map'
} }
@ -205,7 +205,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self', component: 'self',
meta: { meta: {
title: '视频', title: '视频',
i18nTitle: 'message.routes.plugin.video', i18nTitle: 'routes.plugin.video',
requiresAuth: true, requiresAuth: true,
icon: 'mdi:video' icon: 'mdi:video'
} }
@ -221,7 +221,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self', component: 'self',
meta: { meta: {
title: '富文本编辑器', title: '富文本编辑器',
i18nTitle: 'message.routes.plugin.editor.quill', i18nTitle: 'routes.plugin.editor.quill',
requiresAuth: true, requiresAuth: true,
icon: 'mdi:file-document-edit-outline' icon: 'mdi:file-document-edit-outline'
} }
@ -232,7 +232,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self', component: 'self',
meta: { meta: {
title: 'markdown编辑器', title: 'markdown编辑器',
i18nTitle: 'message.routes.plugin.editor.markdown', i18nTitle: 'routes.plugin.editor.markdown',
requiresAuth: true, requiresAuth: true,
icon: 'ri:markdown-line' icon: 'ri:markdown-line'
} }
@ -240,7 +240,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
], ],
meta: { meta: {
title: '编辑器', title: '编辑器',
i18nTitle: 'message.routes.plugin.editor._value', i18nTitle: 'routes.plugin.editor._value',
icon: 'icon-park-outline:editor' icon: 'icon-park-outline:editor'
} }
}, },
@ -250,7 +250,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self', component: 'self',
meta: { meta: {
title: 'Swiper插件', title: 'Swiper插件',
i18nTitle: 'message.routes.plugin.swiper', i18nTitle: 'routes.plugin.swiper',
requiresAuth: true, requiresAuth: true,
icon: 'simple-icons:swiper' icon: 'simple-icons:swiper'
} }
@ -261,7 +261,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self', component: 'self',
meta: { meta: {
title: '剪贴板', title: '剪贴板',
i18nTitle: 'message.routes.plugin.copy', i18nTitle: 'routes.plugin.copy',
requiresAuth: true, requiresAuth: true,
icon: 'mdi:clipboard-outline' icon: 'mdi:clipboard-outline'
} }
@ -272,7 +272,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self', component: 'self',
meta: { meta: {
title: '图标', title: '图标',
i18nTitle: 'message.routes.plugin.icon', i18nTitle: 'routes.plugin.icon',
requiresAuth: true, requiresAuth: true,
localIcon: 'custom-icon' localIcon: 'custom-icon'
} }
@ -283,7 +283,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self', component: 'self',
meta: { meta: {
title: '打印', title: '打印',
i18nTitle: 'message.routes.plugin.print', i18nTitle: 'routes.plugin.print',
requiresAuth: true, requiresAuth: true,
icon: 'mdi:printer' icon: 'mdi:printer'
} }
@ -291,7 +291,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
], ],
meta: { meta: {
title: '插件示例', title: '插件示例',
i18nTitle: 'message.routes.plugin._value', i18nTitle: 'routes.plugin._value',
icon: 'clarity:plugin-line', icon: 'clarity:plugin-line',
order: 4 order: 4
} }
@ -307,7 +307,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self', component: 'self',
meta: { meta: {
title: '权限切换', title: '权限切换',
i18nTitle: 'message.routes.auth-demo.permission', i18nTitle: 'routes.auth-demo.permission',
requiresAuth: true, requiresAuth: true,
icon: 'ic:round-construction' icon: 'ic:round-construction'
} }
@ -318,7 +318,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self', component: 'self',
meta: { meta: {
title: '超级管理员可见', title: '超级管理员可见',
i18nTitle: 'message.routes.auth-demo.super', i18nTitle: 'routes.auth-demo.super',
requiresAuth: true, requiresAuth: true,
icon: 'ic:round-supervisor-account' icon: 'ic:round-supervisor-account'
} }
@ -326,7 +326,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
], ],
meta: { meta: {
title: '权限示例', title: '权限示例',
i18nTitle: 'message.routes.auth-demo._value', i18nTitle: 'routes.auth-demo._value',
icon: 'ic:baseline-security', icon: 'ic:baseline-security',
order: 5 order: 5
} }
@ -342,7 +342,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self', component: 'self',
meta: { meta: {
title: 'Tab', title: 'Tab',
i18nTitle: 'message.routes.function.tab', i18nTitle: 'routes.function.tab',
requiresAuth: true, requiresAuth: true,
icon: 'ic:round-tab' icon: 'ic:round-tab'
} }
@ -375,7 +375,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
], ],
meta: { meta: {
title: '功能', title: '功能',
i18nTitle: 'message.routes.function._value', i18nTitle: 'routes.function._value',
icon: 'icon-park-outline:all-application', icon: 'icon-park-outline:all-application',
order: 6 order: 6
} }
@ -391,7 +391,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self', component: 'self',
meta: { meta: {
title: '异常页403', title: '异常页403',
i18nTitle: 'message.routes.exception.403', i18nTitle: 'routes.exception.403',
requiresAuth: true, requiresAuth: true,
icon: 'ic:baseline-block' icon: 'ic:baseline-block'
} }
@ -402,7 +402,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self', component: 'self',
meta: { meta: {
title: '异常页404', title: '异常页404',
i18nTitle: 'message.routes.exception.404', i18nTitle: 'routes.exception.404',
requiresAuth: true, requiresAuth: true,
icon: 'ic:baseline-web-asset-off' icon: 'ic:baseline-web-asset-off'
} }
@ -413,14 +413,14 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self', component: 'self',
meta: { meta: {
title: '异常页500', title: '异常页500',
i18nTitle: 'message.routes.exception.500', i18nTitle: 'routes.exception.500',
requiresAuth: true, requiresAuth: true,
icon: 'ic:baseline-wifi-off' icon: 'ic:baseline-wifi-off'
} }
} }
], ],
meta: { meta: {
i18nTitle: 'message.routes.exception._value', i18nTitle: 'routes.exception._value',
title: '异常页', title: '异常页',
icon: 'ant-design:exception-outlined', icon: 'ant-design:exception-outlined',
order: 7 order: 7
@ -442,7 +442,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self', component: 'self',
meta: { meta: {
title: '二级菜单', title: '二级菜单',
i18nTitle: 'message.routes.multi-menu.first.second', i18nTitle: 'routes.multi-menu.first.second',
requiresAuth: true, requiresAuth: true,
icon: 'mdi:menu' icon: 'mdi:menu'
} }
@ -458,7 +458,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self', component: 'self',
meta: { meta: {
title: '三级菜单', title: '三级菜单',
i18nTitle: 'message.routes.multi-menu.first.second-new.third', i18nTitle: 'routes.multi-menu.first.second-new.third',
requiresAuth: true, requiresAuth: true,
icon: 'mdi:menu' icon: 'mdi:menu'
} }
@ -466,21 +466,21 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
], ],
meta: { meta: {
title: '二级菜单(有子菜单)', title: '二级菜单(有子菜单)',
i18nTitle: 'message.routes.multi-menu.first.second-new._value', i18nTitle: 'routes.multi-menu.first.second-new._value',
icon: 'mdi:menu' icon: 'mdi:menu'
} }
} }
], ],
meta: { meta: {
title: '一级菜单', title: '一级菜单',
i18nTitle: 'message.routes.multi-menu.first._value', i18nTitle: 'routes.multi-menu.first._value',
icon: 'mdi:menu' icon: 'mdi:menu'
} }
} }
], ],
meta: { meta: {
title: '多级菜单', title: '多级菜单',
i18nTitle: 'message.routes.multi-menu._value', i18nTitle: 'routes.multi-menu._value',
icon: 'carbon:menu', icon: 'carbon:menu',
order: 8 order: 8
} }
@ -496,7 +496,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self', component: 'self',
meta: { meta: {
title: '权限管理', title: '权限管理',
i18nTitle: 'message.routes.management.auth', i18nTitle: 'routes.management.auth',
requiresAuth: true, requiresAuth: true,
icon: 'ic:baseline-security' icon: 'ic:baseline-security'
} }
@ -507,7 +507,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self', component: 'self',
meta: { meta: {
title: '角色管理', title: '角色管理',
i18nTitle: 'message.routes.management.role', i18nTitle: 'routes.management.role',
requiresAuth: true, requiresAuth: true,
icon: 'carbon:user-role' icon: 'carbon:user-role'
} }
@ -518,7 +518,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self', component: 'self',
meta: { meta: {
title: '用户管理', title: '用户管理',
i18nTitle: 'message.routes.management.user', i18nTitle: 'routes.management.user',
requiresAuth: true, requiresAuth: true,
icon: 'ic:round-manage-accounts' icon: 'ic:round-manage-accounts'
} }
@ -529,7 +529,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self', component: 'self',
meta: { meta: {
title: '路由管理', title: '路由管理',
i18nTitle: 'message.routes.management.route', i18nTitle: 'routes.management.route',
requiresAuth: true, requiresAuth: true,
icon: 'material-symbols:route' icon: 'material-symbols:route'
} }
@ -537,7 +537,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
], ],
meta: { meta: {
title: '系统管理', title: '系统管理',
i18nTitle: 'message.routes.management._value', i18nTitle: 'routes.management._value',
icon: 'carbon:cloud-service-management', icon: 'carbon:cloud-service-management',
order: 9 order: 9
} }
@ -548,7 +548,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self', component: 'self',
meta: { meta: {
title: '关于', title: '关于',
i18nTitle: 'message.routes.about', i18nTitle: 'routes.about',
requiresAuth: true, requiresAuth: true,
keepAlive: true, keepAlive: true,
singleLayout: 'basic', singleLayout: 'basic',
@ -571,7 +571,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
title: '分析页', title: '分析页',
requiresAuth: true, requiresAuth: true,
icon: 'icon-park-outline:analysis', icon: 'icon-park-outline:analysis',
i18nTitle: 'message.routes.dashboard.analysis' i18nTitle: 'routes.dashboard.analysis'
} }
}, },
{ {
@ -582,7 +582,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
title: '工作台', title: '工作台',
requiresAuth: true, requiresAuth: true,
icon: 'icon-park-outline:workbench', icon: 'icon-park-outline:workbench',
i18nTitle: 'message.routes.dashboard.workbench' i18nTitle: 'routes.dashboard.workbench'
} }
} }
], ],
@ -590,7 +590,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
title: '仪表盘', title: '仪表盘',
icon: 'mdi:monitor-dashboard', icon: 'mdi:monitor-dashboard',
order: 1, order: 1,
i18nTitle: 'message.routes.dashboard._value' i18nTitle: 'routes.dashboard._value'
} }
}, },
{ {
@ -604,7 +604,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self', component: 'self',
meta: { meta: {
title: 'vue文档', title: 'vue文档',
i18nTitle: 'message.routes.document.vue', i18nTitle: 'routes.document.vue',
requiresAuth: true, requiresAuth: true,
icon: 'logos:vue' icon: 'logos:vue'
} }
@ -615,7 +615,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self', component: 'self',
meta: { meta: {
title: 'vite文档', title: 'vite文档',
i18nTitle: 'message.routes.document.vite', i18nTitle: 'routes.document.vite',
requiresAuth: true, requiresAuth: true,
icon: 'logos:vitejs' icon: 'logos:vitejs'
} }
@ -626,7 +626,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self', component: 'self',
meta: { meta: {
title: 'naive文档', title: 'naive文档',
i18nTitle: 'message.routes.document.naive', i18nTitle: 'routes.document.naive',
requiresAuth: true, requiresAuth: true,
icon: 'logos:naiveui' icon: 'logos:naiveui'
} }
@ -637,7 +637,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self', component: 'self',
meta: { meta: {
title: '项目文档', title: '项目文档',
i18nTitle: 'message.routes.document.project', i18nTitle: 'routes.document.project',
requiresAuth: true, requiresAuth: true,
localIcon: 'logo' localIcon: 'logo'
} }
@ -647,7 +647,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
path: '/document/project-link', path: '/document/project-link',
meta: { meta: {
title: '项目文档(外链)', title: '项目文档(外链)',
i18nTitle: 'message.routes.document.project-link', i18nTitle: 'routes.document.project-link',
requiresAuth: true, requiresAuth: true,
localIcon: 'logo', localIcon: 'logo',
href: 'https://docs.soybean.pro/' href: 'https://docs.soybean.pro/'
@ -656,7 +656,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
], ],
meta: { meta: {
title: '文档', title: '文档',
i18nTitle: 'message.routes.document._value', i18nTitle: 'routes.document._value',
icon: 'mdi:file-document-multiple-outline', icon: 'mdi:file-document-multiple-outline',
order: 2 order: 2
} }
@ -672,7 +672,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self', component: 'self',
meta: { meta: {
title: '按钮', title: '按钮',
i18nTitle: 'message.routes.component.button', i18nTitle: 'routes.component.button',
requiresAuth: true, requiresAuth: true,
icon: 'mdi:button-cursor' icon: 'mdi:button-cursor'
} }
@ -683,7 +683,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self', component: 'self',
meta: { meta: {
title: '卡片', title: '卡片',
i18nTitle: 'message.routes.component.card', i18nTitle: 'routes.component.card',
requiresAuth: true, requiresAuth: true,
icon: 'mdi:card-outline' icon: 'mdi:card-outline'
} }
@ -694,7 +694,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self', component: 'self',
meta: { meta: {
title: '表格', title: '表格',
i18nTitle: 'message.routes.component.table', i18nTitle: 'routes.component.table',
requiresAuth: true, requiresAuth: true,
icon: 'mdi:table-large' icon: 'mdi:table-large'
} }
@ -702,7 +702,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
], ],
meta: { meta: {
title: '组件示例', title: '组件示例',
i18nTitle: 'message.routes.component._value', i18nTitle: 'routes.component._value',
icon: 'cib:app-store', icon: 'cib:app-store',
order: 3 order: 3
} }
@ -723,7 +723,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self', component: 'self',
meta: { meta: {
title: 'ECharts', title: 'ECharts',
i18nTitle: 'message.routes.plugin.charts.echarts', i18nTitle: 'routes.plugin.charts.echarts',
requiresAuth: true, requiresAuth: true,
icon: 'simple-icons:apacheecharts' icon: 'simple-icons:apacheecharts'
} }
@ -734,7 +734,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self', component: 'self',
meta: { meta: {
title: 'AntV', title: 'AntV',
i18nTitle: 'message.routes.plugin.charts.antv', i18nTitle: 'routes.plugin.charts.antv',
requiresAuth: true, requiresAuth: true,
icon: 'simple-icons:antdesign' icon: 'simple-icons:antdesign'
} }
@ -742,7 +742,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
], ],
meta: { meta: {
title: '图表', title: '图表',
i18nTitle: 'message.routes.plugin.charts._value', i18nTitle: 'routes.plugin.charts._value',
icon: 'mdi:chart-areaspline' icon: 'mdi:chart-areaspline'
} }
}, },
@ -752,7 +752,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self', component: 'self',
meta: { meta: {
title: '地图', title: '地图',
i18nTitle: 'message.routes.plugin.map', i18nTitle: 'routes.plugin.map',
requiresAuth: true, requiresAuth: true,
icon: 'mdi:map' icon: 'mdi:map'
} }
@ -763,7 +763,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self', component: 'self',
meta: { meta: {
title: '视频', title: '视频',
i18nTitle: 'message.routes.plugin.video', i18nTitle: 'routes.plugin.video',
requiresAuth: true, requiresAuth: true,
icon: 'mdi:video' icon: 'mdi:video'
} }
@ -779,7 +779,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self', component: 'self',
meta: { meta: {
title: '富文本编辑器', title: '富文本编辑器',
i18nTitle: 'message.routes.plugin.editor.quill', i18nTitle: 'routes.plugin.editor.quill',
requiresAuth: true, requiresAuth: true,
icon: 'mdi:file-document-edit-outline' icon: 'mdi:file-document-edit-outline'
} }
@ -790,7 +790,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self', component: 'self',
meta: { meta: {
title: 'markdown编辑器', title: 'markdown编辑器',
i18nTitle: 'message.routes.plugin.editor.markdown', i18nTitle: 'routes.plugin.editor.markdown',
requiresAuth: true, requiresAuth: true,
icon: 'ri:markdown-line' icon: 'ri:markdown-line'
} }
@ -798,7 +798,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
], ],
meta: { meta: {
title: '编辑器', title: '编辑器',
i18nTitle: 'message.routes.plugin.editor._value', i18nTitle: 'routes.plugin.editor._value',
icon: 'icon-park-outline:editor' icon: 'icon-park-outline:editor'
} }
}, },
@ -808,7 +808,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self', component: 'self',
meta: { meta: {
title: 'Swiper插件', title: 'Swiper插件',
i18nTitle: 'message.routes.plugin.swiper', i18nTitle: 'routes.plugin.swiper',
requiresAuth: true, requiresAuth: true,
icon: 'simple-icons:swiper' icon: 'simple-icons:swiper'
} }
@ -819,7 +819,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self', component: 'self',
meta: { meta: {
title: '剪贴板', title: '剪贴板',
i18nTitle: 'message.routes.plugin.copy', i18nTitle: 'routes.plugin.copy',
requiresAuth: true, requiresAuth: true,
icon: 'mdi:clipboard-outline' icon: 'mdi:clipboard-outline'
} }
@ -830,7 +830,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self', component: 'self',
meta: { meta: {
title: '图标', title: '图标',
i18nTitle: 'message.routes.plugin.icon', i18nTitle: 'routes.plugin.icon',
requiresAuth: true, requiresAuth: true,
localIcon: 'custom-icon' localIcon: 'custom-icon'
} }
@ -841,7 +841,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self', component: 'self',
meta: { meta: {
title: '打印', title: '打印',
i18nTitle: 'message.routes.plugin.print', i18nTitle: 'routes.plugin.print',
requiresAuth: true, requiresAuth: true,
icon: 'mdi:printer' icon: 'mdi:printer'
} }
@ -849,7 +849,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
], ],
meta: { meta: {
title: '插件示例', title: '插件示例',
i18nTitle: 'message.routes.plugin._value', i18nTitle: 'routes.plugin._value',
icon: 'clarity:plugin-line', icon: 'clarity:plugin-line',
order: 4 order: 4
} }
@ -865,7 +865,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self', component: 'self',
meta: { meta: {
title: '权限切换', title: '权限切换',
i18nTitle: 'message.routes.auth-demo.permission', i18nTitle: 'routes.auth-demo.permission',
requiresAuth: true, requiresAuth: true,
icon: 'ic:round-construction' icon: 'ic:round-construction'
} }
@ -876,7 +876,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self', component: 'self',
meta: { meta: {
title: '超级管理员可见', title: '超级管理员可见',
i18nTitle: 'message.routes.auth-demo.super', i18nTitle: 'routes.auth-demo.super',
requiresAuth: true, requiresAuth: true,
icon: 'ic:round-supervisor-account' icon: 'ic:round-supervisor-account'
} }
@ -884,7 +884,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
], ],
meta: { meta: {
title: '权限示例', title: '权限示例',
i18nTitle: 'message.routes.auth-demo._value', i18nTitle: 'routes.auth-demo._value',
icon: 'ic:baseline-security', icon: 'ic:baseline-security',
order: 5 order: 5
} }
@ -900,7 +900,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self', component: 'self',
meta: { meta: {
title: 'Tab', title: 'Tab',
i18nTitle: 'message.routes.function.tab', i18nTitle: 'routes.function.tab',
requiresAuth: true, requiresAuth: true,
icon: 'ic:round-tab' icon: 'ic:round-tab'
} }
@ -933,7 +933,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
], ],
meta: { meta: {
title: '功能', title: '功能',
i18nTitle: 'message.routes.function._value', i18nTitle: 'routes.function._value',
icon: 'icon-park-outline:all-application', icon: 'icon-park-outline:all-application',
order: 6 order: 6
} }
@ -949,7 +949,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self', component: 'self',
meta: { meta: {
title: '异常页403', title: '异常页403',
i18nTitle: 'message.routes.exception.403', i18nTitle: 'routes.exception.403',
requiresAuth: true, requiresAuth: true,
icon: 'ic:baseline-block' icon: 'ic:baseline-block'
} }
@ -960,7 +960,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self', component: 'self',
meta: { meta: {
title: '异常页404', title: '异常页404',
i18nTitle: 'message.routes.exception.404', i18nTitle: 'routes.exception.404',
requiresAuth: true, requiresAuth: true,
icon: 'ic:baseline-web-asset-off' icon: 'ic:baseline-web-asset-off'
} }
@ -971,14 +971,14 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self', component: 'self',
meta: { meta: {
title: '异常页500', title: '异常页500',
i18nTitle: 'message.routes.exception.500', i18nTitle: 'routes.exception.500',
requiresAuth: true, requiresAuth: true,
icon: 'ic:baseline-wifi-off' icon: 'ic:baseline-wifi-off'
} }
} }
], ],
meta: { meta: {
i18nTitle: 'message.routes.exception._value', i18nTitle: 'routes.exception._value',
title: '异常页', title: '异常页',
icon: 'ant-design:exception-outlined', icon: 'ant-design:exception-outlined',
order: 7 order: 7
@ -1000,7 +1000,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self', component: 'self',
meta: { meta: {
title: '二级菜单', title: '二级菜单',
i18nTitle: 'message.routes.multi-menu.first.second', i18nTitle: 'routes.multi-menu.first.second',
requiresAuth: true, requiresAuth: true,
icon: 'mdi:menu' icon: 'mdi:menu'
} }
@ -1016,7 +1016,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self', component: 'self',
meta: { meta: {
title: '三级菜单', title: '三级菜单',
i18nTitle: 'message.routes.multi-menu.first.second-new.third', i18nTitle: 'routes.multi-menu.first.second-new.third',
requiresAuth: true, requiresAuth: true,
icon: 'mdi:menu' icon: 'mdi:menu'
} }
@ -1024,21 +1024,21 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
], ],
meta: { meta: {
title: '二级菜单(有子菜单)', title: '二级菜单(有子菜单)',
i18nTitle: 'message.routes.multi-menu.first.second-new._value', i18nTitle: 'routes.multi-menu.first.second-new._value',
icon: 'mdi:menu' icon: 'mdi:menu'
} }
} }
], ],
meta: { meta: {
title: '一级菜单', title: '一级菜单',
i18nTitle: 'message.routes.multi-menu.first._value', i18nTitle: 'routes.multi-menu.first._value',
icon: 'mdi:menu' icon: 'mdi:menu'
} }
} }
], ],
meta: { meta: {
title: '多级菜单', title: '多级菜单',
i18nTitle: 'message.routes.multi-menu._value', i18nTitle: 'routes.multi-menu._value',
icon: 'carbon:menu', icon: 'carbon:menu',
order: 8 order: 8
} }
@ -1054,7 +1054,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self', component: 'self',
meta: { meta: {
title: '权限管理', title: '权限管理',
i18nTitle: 'message.routes.management.auth', i18nTitle: 'routes.management.auth',
requiresAuth: true, requiresAuth: true,
icon: 'ic:baseline-security' icon: 'ic:baseline-security'
} }
@ -1065,7 +1065,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self', component: 'self',
meta: { meta: {
title: '角色管理', title: '角色管理',
i18nTitle: 'message.routes.management.role', i18nTitle: 'routes.management.role',
requiresAuth: true, requiresAuth: true,
icon: 'carbon:user-role' icon: 'carbon:user-role'
} }
@ -1076,7 +1076,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self', component: 'self',
meta: { meta: {
title: '用户管理', title: '用户管理',
i18nTitle: 'message.routes.management.user', i18nTitle: 'routes.management.user',
requiresAuth: true, requiresAuth: true,
icon: 'ic:round-manage-accounts' icon: 'ic:round-manage-accounts'
} }
@ -1087,7 +1087,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self', component: 'self',
meta: { meta: {
title: '路由管理', title: '路由管理',
i18nTitle: 'message.routes.management.route', i18nTitle: 'routes.management.route',
requiresAuth: true, requiresAuth: true,
icon: 'material-symbols:route' icon: 'material-symbols:route'
} }
@ -1095,7 +1095,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
], ],
meta: { meta: {
title: '系统管理', title: '系统管理',
i18nTitle: 'message.routes.management._value', i18nTitle: 'routes.management._value',
icon: 'carbon:cloud-service-management', icon: 'carbon:cloud-service-management',
order: 9 order: 9
} }
@ -1106,7 +1106,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self', component: 'self',
meta: { meta: {
title: '关于', title: '关于',
i18nTitle: 'message.routes.about', i18nTitle: 'routes.about',
requiresAuth: true, requiresAuth: true,
keepAlive: true, keepAlive: true,
singleLayout: 'basic', singleLayout: 'basic',
@ -1129,7 +1129,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
title: '分析页', title: '分析页',
requiresAuth: true, requiresAuth: true,
icon: 'icon-park-outline:analysis', icon: 'icon-park-outline:analysis',
i18nTitle: 'message.routes.dashboard.analysis' i18nTitle: 'routes.dashboard.analysis'
} }
}, },
{ {
@ -1140,7 +1140,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
title: '工作台', title: '工作台',
requiresAuth: true, requiresAuth: true,
icon: 'icon-park-outline:workbench', icon: 'icon-park-outline:workbench',
i18nTitle: 'message.routes.dashboard.workbench' i18nTitle: 'routes.dashboard.workbench'
} }
} }
], ],
@ -1148,7 +1148,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
title: '仪表盘', title: '仪表盘',
icon: 'mdi:monitor-dashboard', icon: 'mdi:monitor-dashboard',
order: 1, order: 1,
i18nTitle: 'message.routes.dashboard._value' i18nTitle: 'routes.dashboard._value'
} }
}, },
{ {
@ -1162,7 +1162,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self', component: 'self',
meta: { meta: {
title: '权限切换', title: '权限切换',
i18nTitle: 'message.routes.auth-demo.permission', i18nTitle: 'routes.auth-demo.permission',
requiresAuth: true, requiresAuth: true,
icon: 'ic:round-construction' icon: 'ic:round-construction'
} }
@ -1173,7 +1173,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self', component: 'self',
meta: { meta: {
title: '超级管理员可见', title: '超级管理员可见',
i18nTitle: 'message.routes.auth-demo.super', i18nTitle: 'routes.auth-demo.super',
requiresAuth: true, requiresAuth: true,
icon: 'ic:round-supervisor-account' icon: 'ic:round-supervisor-account'
} }
@ -1181,7 +1181,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
], ],
meta: { meta: {
title: '权限示例', title: '权限示例',
i18nTitle: 'message.routes.auth-demo._value', i18nTitle: 'routes.auth-demo._value',
icon: 'ic:baseline-security', icon: 'ic:baseline-security',
order: 5 order: 5
} }
@ -1202,7 +1202,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self', component: 'self',
meta: { meta: {
title: '二级菜单', title: '二级菜单',
i18nTitle: 'message.routes.multi-menu.first.second', i18nTitle: 'routes.multi-menu.first.second',
requiresAuth: true, requiresAuth: true,
icon: 'mdi:menu' icon: 'mdi:menu'
} }
@ -1218,7 +1218,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self', component: 'self',
meta: { meta: {
title: '三级菜单', title: '三级菜单',
i18nTitle: 'message.routes.multi-menu.first.second-new.third', i18nTitle: 'routes.multi-menu.first.second-new.third',
requiresAuth: true, requiresAuth: true,
icon: 'mdi:menu' icon: 'mdi:menu'
} }
@ -1226,21 +1226,21 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
], ],
meta: { meta: {
title: '二级菜单(有子菜单)', title: '二级菜单(有子菜单)',
i18nTitle: 'message.routes.multi-menu.first.second-new._value', i18nTitle: 'routes.multi-menu.first.second-new._value',
icon: 'mdi:menu' icon: 'mdi:menu'
} }
} }
], ],
meta: { meta: {
title: '一级菜单', title: '一级菜单',
i18nTitle: 'message.routes.multi-menu.first._value', i18nTitle: 'routes.multi-menu.first._value',
icon: 'mdi:menu' icon: 'mdi:menu'
} }
} }
], ],
meta: { meta: {
title: '多级菜单', title: '多级菜单',
i18nTitle: 'message.routes.multi-menu._value', i18nTitle: 'routes.multi-menu._value',
icon: 'carbon:menu', icon: 'carbon:menu',
order: 8 order: 8
} }
@ -1251,7 +1251,7 @@ export const routeModel: Record<Auth.RoleType, AuthRoute.Route[]> = {
component: 'self', component: 'self',
meta: { meta: {
title: '关于', title: '关于',
i18nTitle: 'message.routes.about', i18nTitle: 'routes.about',
requiresAuth: true, requiresAuth: true,
keepAlive: true, keepAlive: true,
singleLayout: 'basic', singleLayout: 'basic',

View File

@ -11,17 +11,15 @@
></div> ></div>
</div> </div>
</div> </div>
<h2 class="text-28px font-500 text-#646464">{{ title }}</h2> <h2 class="text-28px font-500 text-#646464">{{ $t('system.title') }}</h2>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { useAppInfo } from '@/composables';
import { sessionStg, getRgbOfColor } from '@/utils'; import { sessionStg, getRgbOfColor } from '@/utils';
import { $t } from '@/locales';
import themeSettings from '@/settings/theme.json'; import themeSettings from '@/settings/theme.json';
const { title } = useAppInfo();
const lodingClasses = [ const lodingClasses = [
'left-0 top-0', 'left-0 top-0',
'left-0 bottom-0 animate-delay-500', 'left-0 bottom-0 animate-delay-500',

View File

@ -2,26 +2,6 @@ import UAParser from 'ua-parser-js';
import { useAuthStore } from '@/store'; import { useAuthStore } from '@/store';
import { isArray, isString } from '@/utils'; import { isArray, isString } from '@/utils';
interface AppInfo {
/** 项目名称 */
name: string;
/** 项目标题 */
title: string;
/** 项目描述 */
desc: string;
}
/** 项目信息 */
export function useAppInfo(): AppInfo {
const { VITE_APP_NAME: name, VITE_APP_TITLE: title, VITE_APP_DESC: desc } = import.meta.env;
return {
name,
title,
desc
};
}
/** 获取设备信息 */ /** 获取设备信息 */
export function useDeviceInfo() { export function useDeviceInfo() {
const parser = new UAParser(); const parser = new UAParser();

View File

@ -1,17 +1,18 @@
import { $t } from '@/locales';
import { transformObjectToOption } from './_shared'; import { transformObjectToOption } from './_shared';
export const loginModuleLabels: Record<UnionKey.LoginModule, string> = { export const loginModuleLabels: Record<UnionKey.LoginModule, string> = {
'pwd-login': '账密登录', 'pwd-login': $t('page.login.pwdLogin.title'),
'code-login': '手机验证码登录', 'code-login': $t('page.login.codeLogin.title'),
register: '注册', register: $t('page.login.register.title'),
'reset-pwd': '重置密码', 'reset-pwd': $t('page.login.resetPwd.title'),
'bind-wechat': '微信绑定' 'bind-wechat': $t('page.login.bindWeChat.title')
}; };
export const userRoleLabels: Record<Auth.RoleType, string> = { export const userRoleLabels: Record<Auth.RoleType, string> = {
super: '超级管理员', super: $t('page.login.pwdLogin.superAdmin'),
admin: '管理员', admin: $t('page.login.pwdLogin.admin'),
user: '普通用户' user: $t('page.login.pwdLogin.user')
}; };
export const userRoleOptions = transformObjectToOption(userRoleLabels); export const userRoleOptions = transformObjectToOption(userRoleLabels);

View File

@ -35,7 +35,7 @@ import { routePath } from '@/router';
import { useRouteStore, useThemeStore } from '@/store'; import { useRouteStore, useThemeStore } from '@/store';
import { useRouterPush } from '@/composables'; import { useRouterPush } from '@/composables';
import { getBreadcrumbByRouteKey } from '@/utils'; import { getBreadcrumbByRouteKey } from '@/utils';
import { t } from '@/locales'; import { $t } from '@/locales';
defineOptions({ name: 'GlobalBreadcrumb' }); defineOptions({ name: 'GlobalBreadcrumb' });
@ -48,8 +48,8 @@ const breadcrumbs = computed(() =>
getBreadcrumbByRouteKey(route.name as string, routeStore.menus as App.GlobalMenuOption[], routePath('root')).map( getBreadcrumbByRouteKey(route.name as string, routeStore.menus as App.GlobalMenuOption[], routePath('root')).map(
item => ({ item => ({
...item, ...item,
label: item.i18nTitle ? t(item.i18nTitle) : item.label, label: item.i18nTitle ? $t(item.i18nTitle) : item.label,
options: item.options?.map(oItem => ({ ...oItem, label: oItem.i18nTitle ? t(oItem.i18nTitle) : oItem.label })) options: item.options?.map(oItem => ({ ...oItem, label: oItem.i18nTitle ? $t(oItem.i18nTitle) : oItem.label }))
}) })
) )
); );

View File

@ -15,7 +15,7 @@ import { localStg } from '@/utils';
const theme = useThemeStore(); const theme = useThemeStore();
const { locale } = useI18n(); const { locale } = useI18n();
const language = ref<I18nType.langType>(localStg.get('lang') || 'zh-CN'); const language = ref<I18nType.LangType>(localStg.get('lang') || 'zh-CN');
const options = [ const options = [
{ {
label: '中文', label: '中文',
@ -31,9 +31,9 @@ const options = [
} }
]; ];
const handleSelect = (key: string) => { const handleSelect = (key: string) => {
language.value = key as I18nType.langType; language.value = key as I18nType.LangType;
locale.value = key; locale.value = key;
localStg.set('lang', key as I18nType.langType); localStg.set('lang', key as I18nType.LangType);
}; };
</script> </script>
<style scoped></style> <style scoped></style>

View File

@ -2,14 +2,14 @@
<router-link :to="routeHomePath" class="flex-center w-full nowrap-hidden"> <router-link :to="routeHomePath" class="flex-center w-full nowrap-hidden">
<system-logo class="text-32px text-primary" /> <system-logo class="text-32px text-primary" />
<h2 v-show="showTitle" class="pl-8px text-16px font-bold text-primary transition duration-300 ease-in-out"> <h2 v-show="showTitle" class="pl-8px text-16px font-bold text-primary transition duration-300 ease-in-out">
{{ t('message.system.title') }} {{ $t('system.title') }}
</h2> </h2>
</router-link> </router-link>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { routePath } from '@/router'; import { routePath } from '@/router';
import { t } from '@/locales'; import { $t } from '@/locales';
defineOptions({ name: 'GlobalLogo' }); defineOptions({ name: 'GlobalLogo' });

View File

@ -9,7 +9,7 @@
:style="{ width: showDrawer ? theme.sider.mixChildMenuWidth + 'px' : '0px' }" :style="{ width: showDrawer ? theme.sider.mixChildMenuWidth + 'px' : '0px' }"
> >
<header class="header-height flex-y-center justify-between" :style="{ height: theme.header.height + 'px' }"> <header class="header-height flex-y-center justify-between" :style="{ height: theme.header.height + 'px' }">
<h2 class="text-primary pl-8px text-16px font-bold">{{ title }}</h2> <h2 class="text-primary pl-8px text-16px font-bold">{{ $t('system.title') }}</h2>
<div class="px-8px text-16px text-gray-600 cursor-pointer" @click="app.toggleMixSiderFixed"> <div class="px-8px text-16px text-gray-600 cursor-pointer" @click="app.toggleMixSiderFixed">
<icon-mdi-pin-off v-if="app.mixSiderFixed" /> <icon-mdi-pin-off v-if="app.mixSiderFixed" />
<icon-mdi-pin v-else /> <icon-mdi-pin v-else />
@ -35,8 +35,9 @@ import { computed, ref, watch } from 'vue';
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
import type { MenuOption } from 'naive-ui'; import type { MenuOption } from 'naive-ui';
import { useAppStore, useThemeStore } from '@/store'; import { useAppStore, useThemeStore } from '@/store';
import { useAppInfo, useRouterPush } from '@/composables'; import { useRouterPush } from '@/composables';
import { getActiveKeyPathsOfMenus } from '@/utils'; import { getActiveKeyPathsOfMenus } from '@/utils';
import { $t } from '@/locales';
defineOptions({ name: 'MixMenuDrawer' }); defineOptions({ name: 'MixMenuDrawer' });
@ -53,7 +54,6 @@ const route = useRoute();
const app = useAppStore(); const app = useAppStore();
const theme = useThemeStore(); const theme = useThemeStore();
const { routerPush } = useRouterPush(); const { routerPush } = useRouterPush();
const { title } = useAppInfo();
const showDrawer = computed(() => (props.visible && props.menus.length) || app.mixSiderFixed); const showDrawer = computed(() => (props.visible && props.menus.length) || app.mixSiderFixed);

View File

@ -28,7 +28,7 @@ import { useRouterPush } from '@/composables';
import { useBoolean } from '@/hooks'; import { useBoolean } from '@/hooks';
import { translateMenuLabel } from '@/utils'; import { translateMenuLabel } from '@/utils';
import { GlobalLogo } from '@/layouts/common'; import { GlobalLogo } from '@/layouts/common';
import { t } from '@/locales'; import { $t } from '@/locales';
import { MixMenuCollapse, MixMenuDetail, MixMenuDrawer } from './components'; import { MixMenuCollapse, MixMenuDetail, MixMenuDrawer } from './components';
defineOptions({ name: 'VerticalMixSider' }); defineOptions({ name: 'VerticalMixSider' });
@ -53,7 +53,7 @@ const firstDegreeMenus = computed(() =>
return { return {
routeName, routeName,
label: i18nTitle ? t(i18nTitle) : label, label: i18nTitle ? $t(i18nTitle) : label,
icon, icon,
hasChildren hasChildren
}; };

View File

@ -19,7 +19,7 @@
class="inline-block align-text-bottom text-16px" class="inline-block align-text-bottom text-16px"
/> />
</template> </template>
{{ item.meta.i18nTitle ? t(item.meta.i18nTitle) : item.meta.title }} {{ item.meta.i18nTitle ? $t(item.meta.i18nTitle) : item.meta.title }}
</PageTab> </PageTab>
</div> </div>
<context-menu <context-menu
@ -36,7 +36,7 @@
import { computed, nextTick, reactive, ref, watch } from 'vue'; import { computed, nextTick, reactive, ref, watch } from 'vue';
import { PageTab } from '@soybeanjs/vue-materials'; import { PageTab } from '@soybeanjs/vue-materials';
import { useTabStore, useThemeStore } from '@/store'; import { useTabStore, useThemeStore } from '@/store';
import { t } from '@/locales'; import { $t } from '@/locales';
import { ContextMenu } from './components'; import { ContextMenu } from './components';
defineOptions({ name: 'TabDetail' }); defineOptions({ name: 'TabDetail' });

View File

@ -1,7 +1,7 @@
<template> <template>
<n-divider title-placement="center">主题模式</n-divider> <n-divider title-placement="center">{{ $t('layout.settingDrawer.themeModeTitle') }}</n-divider>
<n-space vertical size="large"> <n-space vertical size="large">
<setting-menu label="深色主题"> <setting-menu :label="$t('layout.settingDrawer.darkMode')">
<n-switch :value="theme.darkMode" @update:value="theme.setDarkMode"> <n-switch :value="theme.darkMode" @update:value="theme.setDarkMode">
<template #checked> <template #checked>
<icon-mdi-white-balance-sunny class="text-14px text-white" /> <icon-mdi-white-balance-sunny class="text-14px text-white" />
@ -11,7 +11,7 @@
</template> </template>
</n-switch> </n-switch>
</setting-menu> </setting-menu>
<setting-menu label="跟随系统"> <setting-menu :label="$t('layout.settingDrawer.followSystemTheme')">
<n-switch :value="theme.followSystemTheme" @update:value="theme.setFollowSystemTheme"> <n-switch :value="theme.followSystemTheme" @update:value="theme.setFollowSystemTheme">
<template #checked> <template #checked>
<icon-ic-baseline-do-not-disturb class="text-14px text-white" /> <icon-ic-baseline-do-not-disturb class="text-14px text-white" />
@ -21,7 +21,7 @@
</template> </template>
</n-switch> </n-switch>
</setting-menu> </setting-menu>
<setting-menu label="自定义暗黑主题动画过渡"> <setting-menu :label="$t('layout.settingDrawer.isCustomizeDarkModeTransition')">
<n-switch :value="theme.isCustomizeDarkModeTransition" @update:value="theme.setIsCustomizeDarkModeTransition"> <n-switch :value="theme.isCustomizeDarkModeTransition" @update:value="theme.setIsCustomizeDarkModeTransition">
<template #checked> <template #checked>
<icon-ic-baseline-do-not-disturb class="text-14px text-white" /> <icon-ic-baseline-do-not-disturb class="text-14px text-white" />
@ -31,13 +31,13 @@
</template> </template>
</n-switch> </n-switch>
</setting-menu> </setting-menu>
<setting-menu label="侧边栏深色"> <setting-menu :label="$t('layout.settingDrawer.sider.inverted')">
<n-switch :value="theme.sider.inverted" @update:value="theme.setSiderInverted" /> <n-switch :value="theme.sider.inverted" @update:value="theme.setSiderInverted" />
</setting-menu> </setting-menu>
<setting-menu label="头部深色"> <setting-menu :label="$t('layout.settingDrawer.header.inverted')">
<n-switch :value="theme.header.inverted" @update:value="theme.setHeaderInverted" /> <n-switch :value="theme.header.inverted" @update:value="theme.setHeaderInverted" />
</setting-menu> </setting-menu>
<setting-menu label="底部深色"> <setting-menu :label="$t('layout.settingDrawer.footer.inverted')">
<n-switch :value="theme.footer.inverted" @update:value="theme.setFooterInverted" /> <n-switch :value="theme.footer.inverted" @update:value="theme.setFooterInverted" />
</setting-menu> </setting-menu>
</n-space> </n-space>
@ -45,6 +45,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import { useThemeStore } from '@/store'; import { useThemeStore } from '@/store';
import { $t } from '@/locales';
import SettingMenu from '../setting-menu/index.vue'; import SettingMenu from '../setting-menu/index.vue';
defineOptions({ name: 'DarkMode' }); defineOptions({ name: 'DarkMode' });

View File

@ -1,5 +1,5 @@
<template> <template>
<n-divider title-placement="center">布局模式</n-divider> <n-divider title-placement="center">{{ $t('layout.settingDrawer.layoutModelTitle') }}</n-divider>
<n-space justify="space-around" :wrap="true" :size="24" class="px-12px"> <n-space justify="space-around" :wrap="true" :size="24" class="px-12px">
<layout-card <layout-card
v-for="item in theme.layout.modeList" v-for="item in theme.layout.modeList"
@ -43,6 +43,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { useThemeStore } from '@/store'; import { useThemeStore } from '@/store';
import { $t } from '@/locales';
import { LayoutCard } from './components'; import { LayoutCard } from './components';
defineOptions({ name: 'LayoutMode' }); defineOptions({ name: 'LayoutMode' });

View File

@ -1,7 +1,7 @@
<template> <template>
<n-divider title-placement="center">界面功能</n-divider> <n-divider title-placement="center">{{ $t('layout.settingDrawer.pageFunctionsTitle') }}</n-divider>
<n-space vertical size="large"> <n-space vertical size="large">
<setting-menu label="滚动模式"> <setting-menu :label="$t('layout.settingDrawer.scrollMode')">
<n-select <n-select
class="w-120px" class="w-120px"
size="small" size="small"
@ -10,10 +10,10 @@
@update:value="theme.setScrollMode" @update:value="theme.setScrollMode"
/> />
</setting-menu> </setting-menu>
<setting-menu label="固定头部和多页签"> <setting-menu :label="$t('layout.settingDrawer.fixedHeaderAndTab')">
<n-switch :value="theme.fixedHeaderAndTab" @update:value="theme.setIsFixedHeaderAndTab" /> <n-switch :value="theme.fixedHeaderAndTab" @update:value="theme.setIsFixedHeaderAndTab" />
</setting-menu> </setting-menu>
<setting-menu label="顶部菜单位置"> <setting-menu :label="$t('layout.settingDrawer.menu.horizontalPosition')">
<n-select <n-select
class="w-120px" class="w-120px"
size="small" size="small"
@ -22,7 +22,7 @@
@update:value="theme.setHorizontalMenuPosition" @update:value="theme.setHorizontalMenuPosition"
/> />
</setting-menu> </setting-menu>
<setting-menu label="头部高度"> <setting-menu :label="$t('layout.settingDrawer.header.height')">
<n-input-number <n-input-number
class="w-120px" class="w-120px"
size="small" size="small"
@ -31,7 +31,7 @@
@update:value="theme.setHeaderHeight" @update:value="theme.setHeaderHeight"
/> />
</setting-menu> </setting-menu>
<setting-menu label="多页签高度"> <setting-menu :label="$t('layout.settingDrawer.tab.height')">
<n-input-number <n-input-number
class="w-120px" class="w-120px"
size="small" size="small"
@ -40,10 +40,10 @@
@update:value="theme.setTabHeight" @update:value="theme.setTabHeight"
/> />
</setting-menu> </setting-menu>
<setting-menu label="多页签缓存"> <setting-menu :label="$t('layout.settingDrawer.tab.isCache')">
<n-switch :value="theme.tab.isCache" @update:value="theme.setTabIsCache" /> <n-switch :value="theme.tab.isCache" @update:value="theme.setTabIsCache" />
</setting-menu> </setting-menu>
<setting-menu label="侧边栏展开宽度"> <setting-menu :label="$t('layout.settingDrawer.sider.width')">
<n-input-number <n-input-number
class="w-120px" class="w-120px"
size="small" size="small"
@ -52,7 +52,7 @@
@update:value="theme.setSiderWidth" @update:value="theme.setSiderWidth"
/> />
</setting-menu> </setting-menu>
<setting-menu label="左侧混合侧边栏展开宽度"> <setting-menu :label="$t('layout.settingDrawer.sider.mixWidth')">
<n-input-number <n-input-number
class="w-120px" class="w-120px"
size="small" size="small"
@ -61,13 +61,13 @@
@update:value="theme.setMixSiderWidth" @update:value="theme.setMixSiderWidth"
/> />
</setting-menu> </setting-menu>
<setting-menu label="显示底部"> <setting-menu :label="$t('layout.settingDrawer.footer.visible')">
<n-switch :value="theme.footer.visible" @update:value="theme.setFooterVisible" /> <n-switch :value="theme.footer.visible" @update:value="theme.setFooterVisible" />
</setting-menu> </setting-menu>
<setting-menu label="固定底部"> <setting-menu :label="$t('layout.settingDrawer.footer.fixed')">
<n-switch :value="theme.footer.fixed" @update:value="theme.setFooterIsFixed" /> <n-switch :value="theme.footer.fixed" @update:value="theme.setFooterIsFixed" />
</setting-menu> </setting-menu>
<setting-menu label="底部居右"> <setting-menu :label="$t('layout.settingDrawer.footer.right')">
<n-switch :value="theme.footer.right" @update:value="theme.setFooterIsRight" /> <n-switch :value="theme.footer.right" @update:value="theme.setFooterIsRight" />
</setting-menu> </setting-menu>
</n-space> </n-space>
@ -75,6 +75,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import { useThemeStore } from '@/store'; import { useThemeStore } from '@/store';
import { $t } from '@/locales';
import SettingMenu from '../setting-menu/index.vue'; import SettingMenu from '../setting-menu/index.vue';
defineOptions({ name: 'PageFunc' }); defineOptions({ name: 'PageFunc' });

View File

@ -1,16 +1,16 @@
<template> <template>
<n-divider title-placement="center">界面显示</n-divider> <n-divider title-placement="center">{{ $t('layout.settingDrawer.pageViewTitle') }}</n-divider>
<n-space vertical size="large"> <n-space vertical size="large">
<setting-menu label="面包屑"> <setting-menu :label="$t('layout.settingDrawer.header.crumb.visible')">
<n-switch :value="theme.header.crumb.visible" @update:value="theme.setHeaderCrumbVisible" /> <n-switch :value="theme.header.crumb.visible" @update:value="theme.setHeaderCrumbVisible" />
</setting-menu> </setting-menu>
<setting-menu label="面包屑图标"> <setting-menu :label="$t('layout.settingDrawer.header.crumb.icon')">
<n-switch :value="theme.header.crumb.showIcon" @update:value="theme.setHeaderCrumbIconVisible" /> <n-switch :value="theme.header.crumb.showIcon" @update:value="theme.setHeaderCrumbIconVisible" />
</setting-menu> </setting-menu>
<setting-menu label="多页签"> <setting-menu :label="$t('layout.settingDrawer.tab.visible')">
<n-switch :value="theme.tab.visible" @update:value="theme.setTabVisible" /> <n-switch :value="theme.tab.visible" @update:value="theme.setTabVisible" />
</setting-menu> </setting-menu>
<setting-menu label="多页签风格"> <setting-menu :label="$t('layout.settingDrawer.tab.modeList.mode')">
<n-select <n-select
class="w-120px" class="w-120px"
size="small" size="small"
@ -19,10 +19,10 @@
@update:value="theme.setTabMode" @update:value="theme.setTabMode"
/> />
</setting-menu> </setting-menu>
<setting-menu label="页面切换动画"> <setting-menu :label="$t('layout.settingDrawer.page.animate')">
<n-switch :value="theme.page.animate" @update:value="theme.setPageIsAnimate" /> <n-switch :value="theme.page.animate" @update:value="theme.setPageIsAnimate" />
</setting-menu> </setting-menu>
<setting-menu label="页面切换动画类型"> <setting-menu :label="$t('layout.settingDrawer.page.animateMode')">
<n-select <n-select
class="w-120px" class="w-120px"
size="small" size="small"
@ -36,6 +36,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import { useThemeStore } from '@/store'; import { useThemeStore } from '@/store';
import { $t } from '@/locales';
import SettingMenu from '../setting-menu/index.vue'; import SettingMenu from '../setting-menu/index.vue';
defineOptions({ name: 'PageView' }); defineOptions({ name: 'PageView' });

View File

@ -1,5 +1,5 @@
<template> <template>
<n-divider title-placement="center">系统主题</n-divider> <n-divider title-placement="center">{{ $t('layout.settingDrawer.systemThemeTitle') }}</n-divider>
<n-grid :cols="8" :x-gap="8" :y-gap="12"> <n-grid :cols="8" :x-gap="8" :y-gap="12">
<n-grid-item v-for="color in theme.themeColorList" :key="color" class="flex-x-center"> <n-grid-item v-for="color in theme.themeColorList" :key="color" class="flex-x-center">
<color-checkbox :color="color" :checked="color === theme.themeColor" @click="theme.setThemeColor(color)" /> <color-checkbox :color="color" :checked="color === theme.themeColor" @click="theme.setThemeColor(color)" />
@ -7,7 +7,9 @@
</n-grid> </n-grid>
<n-space :vertical="true" class="pt-12px"> <n-space :vertical="true" class="pt-12px">
<n-color-picker :value="theme.themeColor" :show-alpha="false" @update-value="theme.setThemeColor" /> <n-color-picker :value="theme.themeColor" :show-alpha="false" @update-value="theme.setThemeColor" />
<n-button :block="true" :type="otherColorBtnType" @click="openModal">更多颜色</n-button> <n-button :block="true" :type="otherColorBtnType" @click="openModal">
{{ $t('layout.settingDrawer.systemTheme.moreColors') }}
</n-button>
</n-space> </n-space>
<color-modal :visible="visible" @close="closeModal" /> <color-modal :visible="visible" @close="closeModal" />
</template> </template>
@ -17,6 +19,7 @@ import { computed } from 'vue';
import { isInTraditionColors } from '@/settings'; import { isInTraditionColors } from '@/settings';
import { useThemeStore } from '@/store'; import { useThemeStore } from '@/store';
import { useBoolean } from '@/hooks'; import { useBoolean } from '@/hooks';
import { $t } from '@/locales';
import { ColorCheckbox, ColorModal } from './components'; import { ColorCheckbox, ColorModal } from './components';
defineOptions({ name: 'ThemeColorSelect' }); defineOptions({ name: 'ThemeColorSelect' });

View File

@ -1,11 +1,13 @@
<template> <template>
<n-divider title-placement="center">主题配置</n-divider> <n-divider title-placement="center">{{ $t('layout.settingDrawer.themeConfiguration.title') }}</n-divider>
<textarea id="themeConfigCopyTarget" v-model="dataClipboardText" class="absolute opacity-0" /> <textarea id="themeConfigCopyTarget" v-model="dataClipboardText" class="absolute opacity-0" />
<n-space vertical> <n-space vertical>
<div ref="copyRef" data-clipboard-target="#themeConfigCopyTarget"> <div ref="copyRef" data-clipboard-target="#themeConfigCopyTarget">
<n-button type="primary" :block="true">拷贝当前配置</n-button> <n-button type="primary" :block="true">{{ $t('layout.settingDrawer.themeConfiguration.copy') }}</n-button>
</div> </div>
<n-button type="warning" :block="true" @click="handleResetConfig">重置当前配置</n-button> <n-button type="warning" :block="true" @click="handleResetConfig">
{{ $t('layout.settingDrawer.themeConfiguration.reset') }}
</n-button>
</n-space> </n-space>
</template> </template>
@ -13,6 +15,7 @@
import { onMounted, onUnmounted, ref, watch } from 'vue'; import { onMounted, onUnmounted, ref, watch } from 'vue';
import Clipboard from 'clipboard'; import Clipboard from 'clipboard';
import { useThemeStore } from '@/store'; import { useThemeStore } from '@/store';
import { $t } from '@/locales';
defineOptions({ name: 'ThemeConfig' }); defineOptions({ name: 'ThemeConfig' });
@ -28,7 +31,7 @@ function getClipboardText() {
function handleResetConfig() { function handleResetConfig() {
theme.resetThemeStore(); theme.resetThemeStore();
window.$message?.success('已重置配置,请重新拷贝!'); window.$message?.success($t('layout.settingDrawer.themeConfiguration.resetSuccess'));
} }
function clipboardEventListener() { function clipboardEventListener() {
@ -36,9 +39,9 @@ function clipboardEventListener() {
const copy = new Clipboard(copyRef.value); const copy = new Clipboard(copyRef.value);
copy.on('success', () => { copy.on('success', () => {
window.$dialog?.success({ window.$dialog?.success({
title: '操作成功', title: $t('layout.settingDrawer.themeConfiguration.operateSuccess'),
content: '复制成功,请替换 src/settings/theme.json的内容', content: $t('layout.settingDrawer.themeConfiguration.copySuccess'),
positiveText: '确定' positiveText: $t('layout.settingDrawer.themeConfiguration.confirmCopy')
}); });
}); });
} }

View File

@ -1,6 +1,6 @@
<template> <template>
<n-drawer :show="app.settingDrawerVisible" display-directive="show" :width="330" @mask-click="app.closeSettingDrawer"> <n-drawer :show="app.settingDrawerVisible" display-directive="show" :width="330" @mask-click="app.closeSettingDrawer">
<n-drawer-content title="主题配置" :native-scrollbar="false"> <n-drawer-content :title="$t('layout.settingDrawer.title')" :native-scrollbar="false">
<dark-mode /> <dark-mode />
<layout-mode /> <layout-mode />
<theme-color-select /> <theme-color-select />
@ -14,6 +14,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { useAppStore } from '@/store'; import { useAppStore } from '@/store';
import { $t } from '@/locales';
import { DarkMode, DrawerButton, LayoutMode, PageFunc, PageView, ThemeColorSelect, ThemeConfig } from './components'; import { DarkMode, DrawerButton, LayoutMode, PageFunc, PageView, ThemeColorSelect, ThemeConfig } from './components';
defineOptions({ name: 'SettingDrawer' }); defineOptions({ name: 'SettingDrawer' });

View File

@ -1,8 +1,8 @@
import type { App } from 'vue'; import type { App } from 'vue';
import { createI18n } from 'vue-i18n'; import { createI18n } from 'vue-i18n';
import { localStg } from '@/utils'; import type { TranslateOptions } from 'vue-i18n';
import messages from './lang'; import { localStg } from '@/utils/storage';
import type { LocaleKey } from './lang'; import messages from './locale';
const i18n = createI18n({ const i18n = createI18n({
locale: localStg.get('lang') || 'zh-CN', locale: localStg.get('lang') || 'zh-CN',
@ -15,10 +15,20 @@ export function setupI18n(app: App) {
app.use(i18n); app.use(i18n);
} }
export function t(key: string) { interface T {
return i18n.global.t(key); (key: I18nType.I18nKey): string;
(key: I18nType.I18nKey, plural: number, options?: TranslateOptions<I18nType.LangType>): string;
(key: I18nType.I18nKey, defaultMsg: string, options?: TranslateOptions<I18nType.I18nKey>): string;
(key: I18nType.I18nKey, list: unknown[], options?: TranslateOptions<I18nType.I18nKey>): string;
(key: I18nType.I18nKey, list: unknown[], plural: number): string;
(key: I18nType.I18nKey, list: unknown[], defaultMsg: string): string;
(key: I18nType.I18nKey, named: Record<string, unknown>, options?: TranslateOptions<I18nType.LangType>): string;
(key: I18nType.I18nKey, named: Record<string, unknown>, plural: number): string;
(key: I18nType.I18nKey, named: Record<string, unknown>, defaultMsg: string): string;
} }
export function setLocale(locale: LocaleKey) { export const $t = i18n.global.t as T;
export function setLocale(locale: I18nType.LangType) {
i18n.global.locale.value = locale; i18n.global.locale.value = locale;
} }

View File

@ -1,83 +1,217 @@
import type { LocaleMessages } from 'vue-i18n'; const locale: I18nType.Schema = {
system: {
const locale: LocaleMessages<I18nType.Schema> = { title: 'SoybeanAdmin'
message: { },
system: { common: {
title: 'SoybeanAdmin' add: 'Add',
addSuccess: 'Add Success',
edit: 'Edit',
editSuccess: 'Edit Success',
delete: 'Delete',
deleteSuccess: 'Delete Success',
batchDelete: 'Batch Delete',
confirm: 'Confirm',
cancel: 'Cancel',
pleaseCheckValue: 'Please check the value is valid',
action: 'Action'
},
routes: {
dashboard: {
_value: 'Dashboard',
analysis: 'Analysis',
workbench: 'Workbench'
}, },
routes: { document: {
dashboard: { _value: 'Document',
_value: 'Dashboard', vue: 'Vue Document',
analysis: 'Analysis', vite: 'Vite Document',
workbench: 'Workbench' naive: 'NaiveUI Document',
project: 'Project Document',
'project-link': 'Project Document(href)'
},
component: {
_value: 'Component',
button: 'Button',
card: 'Card',
table: 'Table'
},
plugin: {
_value: 'Plugin',
charts: {
_value: 'Chart',
echarts: 'ECharts',
antv: 'AntV'
}, },
document: { copy: 'Copy',
_value: 'Document', editor: {
vue: 'Vue Document', _value: 'Editor',
vite: 'Vite Document', quill: 'Quill',
naive: 'NaiveUI Document', markdown: 'Markdown'
project: 'Project Document',
'project-link': 'Project Document(href)'
}, },
component: { icon: 'Icon',
_value: 'Component', map: 'Map',
button: 'Button', print: 'Print',
card: 'Card', swiper: 'Swiper',
table: 'Table' video: 'Video'
},
'auth-demo': {
_value: 'Auth Demo',
permission: 'Toggle Permission',
super: 'Super Auth'
},
function: {
_value: 'Function',
tab: 'System Tab'
},
exception: {
_value: 'Exception',
403: '403',
404: '404',
500: '500'
},
'multi-menu': {
_value: 'Multi Degree Menu',
first: {
_value: 'First Degree',
second: 'Second Degree',
'second-new': {
_value: 'Second Degree With Children',
third: 'Third Degree'
}
}
},
management: {
_value: 'System Management',
auth: 'Auth',
role: 'Role',
route: 'Route',
user: 'User'
},
about: 'About'
},
layout: {
settingDrawer: {
title: 'Theme configuration',
themeModeTitle: 'Theme mode',
darkMode: 'Dark mode',
layoutModelTitle: 'Layout mode',
systemThemeTitle: 'System theme',
pageFunctionsTitle: 'Page functions',
pageViewTitle: 'Page view',
followSystemTheme: 'Follow the system',
isCustomizeDarkModeTransition: 'Custom dark theme animation transition',
scrollMode: 'scrollMode',
scrollModeList: {
wrapper: 'Outer layer scroll',
content: 'Main body scroll'
}, },
plugin: { fixedHeaderAndTab: 'Fixed header and multiple tabs',
_value: 'Plugin', header: {
charts: { inverted: 'darkHead',
_value: 'Chart', height: 'Head Height',
echarts: 'ECharts', crumb: {
antv: 'AntV' visible: 'Crumb',
}, icon: 'Crumb icon'
copy: 'Copy',
editor: {
_value: 'Editor',
quill: 'Quill',
markdown: 'Markdown'
},
icon: 'Icon',
map: 'Map',
print: 'Print',
swiper: 'Swiper',
video: 'Video'
},
'auth-demo': {
_value: 'Auth Demo',
permission: 'Toggle Permission',
super: 'Super Auth'
},
function: {
_value: 'Function',
tab: 'System Tab'
},
exception: {
_value: 'Exception',
403: '403',
404: '404',
500: '500'
},
'multi-menu': {
_value: 'Multi Degree Menu',
first: {
_value: 'First Degree',
second: 'Second Degree',
'second-new': {
_value: 'Second Degree With Children',
third: 'Third Degree'
}
} }
}, },
management: { tab: {
_value: 'System Management', visible: 'Multi-page tab',
auth: 'Auth', height: 'Multiple tab height',
role: 'Role', modeList: {
route: 'Route', mode: 'Multi-tab style',
user: 'User' chrome: 'Google style',
button: 'Button style'
},
isCache: 'Multiple tab caching'
}, },
about: 'About' sider: {
inverted: 'Dark sidebar',
width: 'Sidebar expanded width',
mixWidth: 'Left hybrid sidebar expanded width'
},
menu: {
horizontalPosition: 'Top menu position',
horizontalPositionList: {
flexStart: 'Right',
center: 'center',
flexEnd: 'Left'
}
},
footer: {
inverted: 'Dark bottom',
visible: 'Show bottom',
fixed: 'Fixed bottom',
right: 'Bottom to the right'
},
page: {
animate: 'switch animation',
animateMode: 'switch animation type',
animateModeList: {
zoomFade: 'Gradual change',
zoomOut: 'Flash',
fadeSlide: 'Slide',
fade: 'Fade away',
fadeBottom: 'Bottom fade',
fadeScale: 'Resizing fade away'
}
},
systemTheme: {
moreColors: 'More colors'
},
themeConfiguration: {
title: 'Theme configuration',
copy: 'Copy the current configuration',
reset: 'Reset the current configuration',
resetSuccess: 'The configuration has been reset, please copy it again!',
operateSuccess: 'Successful operation',
copySuccess: 'Copy success, please replace the content of src/settings/theme.json!',
confirmCopy: 'Confirm'
}
}
},
page: {
login: {
common: {
userNamePlaceholder: 'Please enter user name',
phonePlaceholder: 'Please enter phone number',
codePlaceholder: 'Please enter verification code',
passwordPlaceholder: 'Please enter password',
confirmPasswordPlaceholder: 'Please enter password again',
codeLogin: 'Verification code login',
confirm: 'Confirm',
back: 'Back',
validateSuccess: 'Verification passed',
loginSuccess: 'Login success',
welcomeBack: 'Welcome back, {userName}!'
},
pwdLogin: {
title: 'Password Login',
rememberMe: 'Remember me',
forgetPassword: 'Forget password?',
register: 'Register account',
otherAccountLogin: 'Other Account Login',
otherLoginMode: 'Other Login Mode',
superAdmin: 'Super Administrator',
admin: 'Administrator',
user: 'Ordinary User'
},
codeLogin: {
title: 'Verification Code Login',
getCode: 'Get verification code',
imageCodePlaceholder: 'Please enter image verification code'
},
register: {
title: 'Register Account',
agreement: 'I have read and agree to',
protocol: '《User Agreement》',
policy: '《Privacy Policy》'
},
resetPwd: {
title: 'Reset Password'
},
bindWeChat: {
title: 'Bind WeChat'
}
} }
} }
}; };

View File

@ -1,13 +0,0 @@
import zhCN from './zh-cn';
import en from './en';
import kmKH from './km-KH';
const locales = {
'zh-CN': zhCN,
en,
'km-KH': kmKH
};
export type LocaleKey = keyof typeof locales;
export default locales;

View File

@ -1,83 +1,217 @@
import type { LocaleMessages } from 'vue-i18n'; const locale: I18nType.Schema = {
system: {
const locale: LocaleMessages<I18nType.Schema> = { title: 'ប្រព័ន្ធគ្រប់គ្រង'
message: { },
system: { common: {
title: 'ប្រព័ន្ធគ្រប់គ្រង' add: 'បន្ថែម',
addSuccess: 'បន្ថែមជោគជ័យ',
edit: 'កែប្រែ',
editSuccess: 'កែប្រែជោគជ័យ',
delete: 'លុប',
deleteSuccess: 'លុបជោគជ័យ',
batchDelete: 'លុបច្រើន',
confirm: 'យល់ព្រម',
cancel: 'បោះបង់',
pleaseCheckValue: 'សូមពិនិត្យមើលតម្លៃដែលបានបញ្ចូលដើម្បីបញ្ជាក់ថាត្រូវប្រើប្រាស់បាន',
action: 'សកម្មភាព'
},
routes: {
dashboard: {
_value: 'ផ្ទាំងទិន្នន័យ',
analysis: 'ផ្ទាំងវិភាគ',
workbench: 'ផ្ទាំងការងារ'
}, },
routes: { document: {
dashboard: { _value: 'ឯកសារ',
_value: 'ផ្ទាំងទិន្នន័យ', vue: 'ឯកសារ​ Vue',
analysis: 'ផ្ទាំងវិភាគ', vite: 'ឯកសារ​ Vite',
workbench: 'ផ្ទាំងការងារ' naive: 'ឯកសារ NaiveUI',
project: 'ឯកសារគម្រោង',
'project-link': 'ឯកសារគម្រោង(href)'
},
component: {
_value: 'សមាស​ភាគ',
button: 'ប៊ូតុង',
card: 'កាត',
table: 'តារាង'
},
plugin: {
_value: 'មុខងារជំនួយ',
charts: {
_value: 'តារាង​ Chart',
echarts: 'តារាង ECharts',
antv: 'AntV'
}, },
document: { copy: 'ចម្លង',
_value: 'ឯកសារ', editor: {
vue: 'ឯកសារ​ Vue', _value: 'កែប្រែ',
vite: 'ឯកសារ​ Vite', quill: 'Quill',
naive: 'ឯកសារ NaiveUI', markdown: 'Markdown'
project: 'ឯកសារគម្រោង',
'project-link': 'ឯកសារគម្រោង(href)'
}, },
component: { icon: 'អាយខន',
_value: 'សមាស​ភាគ', map: 'ផែនទី',
button: 'ប៊ូតុង', print: 'បោះពុម្ភ',
card: 'កាត', swiper: 'Swiper',
table: 'តារាង' video: 'វីដេអូ'
},
'auth-demo': {
_value: 'ឌីមូ Auth',
permission: 'បិទ/បើកការអនុញ្ញាត',
super: 'Super Auth'
},
function: {
_value: 'មុខងារ',
tab: 'ថេបប្រព័ន្ធ'
},
exception: {
_value: 'ករណីពិេសស',
403: '403',
404: '404',
500: '500'
},
'multi-menu': {
_value: 'ម៉ឺនុយពហុដឺក្រេ',
first: {
_value: 'ដឺក្រេទី១',
second: 'ដែក្រេទី២',
'second-new': {
_value: 'ដឺក្រេទី២មានអនុក្រោម',
third: 'ដឺក្រេទី៣'
}
}
},
management: {
_value: 'ការគ្រប់គ្រងប្រព័ន្ធ',
auth: 'Auth',
role: 'សិទ្ធី',
route: 'ផ្លូវប្រព័ន្ធ',
user: 'អ្នកប្រើប្រាស់'
},
about: 'អំពីប្រព័ន្ធ'
},
layout: {
settingDrawer: {
title: 'ការកំណត់ស្បែក',
themeModeTitle: 'ស្បែករបស់របស់អ្នក',
darkMode: 'របៀបងារស្បែកងងឹត',
layoutModelTitle: 'របៀបប្រើប្រាស់របស់អ្នក',
systemThemeTitle: 'ស្បែករបស់ប្រព័ន្ធគ្រប់គ្រង',
pageFunctionsTitle: 'មុខងារទំនាក់ទំនងរបស់ទំព័រ',
pageViewTitle: 'ទំព័រទស្សន៍ទាយ',
followSystemTheme: 'តាមដានស្បែកប្រព័ន្ធគ្រប់គ្រង',
isCustomizeDarkModeTransition: 'ប្រើប្រាស់របៀបងារស្បែកងងឹតផ្ទាល់ខ្លួន',
scrollMode: 'របៀបរុករក',
scrollModeList: {
wrapper: 'រុករកជាក់លាក់',
content: 'រុករកមានមុខងារ'
}, },
plugin: { fixedHeaderAndTab: 'បិទការរុករកជាក់លាក់និងរុករកមានមុខងារ',
_value: 'មុខងារជំនួយ', header: {
charts: { inverted: 'បង្កើតការរុករកជាក់លាក់',
_value: 'តារាង​ Chart', height: 'កម្ពស់',
echarts: 'តារាង ECharts', crumb: {
antv: 'AntV' visible: 'បង្ហាញរុករកជាក់លាក់',
}, icon: 'រុករកជាក់លាក់រូបតំណាង'
copy: 'ចម្លង',
editor: {
_value: 'កែប្រែ',
quill: 'Quill',
markdown: 'Markdown'
},
icon: 'អាយខន',
map: 'ផែនទី',
print: 'បោះពុម្ភ',
swiper: 'Swiper',
video: 'វីដេអូ'
},
'auth-demo': {
_value: 'ឌីមូ Auth',
permission: 'បិទ/បើកការអនុញ្ញាត',
super: 'Super Auth'
},
function: {
_value: 'មុខងារ',
tab: 'ថេបប្រព័ន្ធ'
},
exception: {
_value: 'ករណីពិេសស',
403: '403',
404: '404',
500: '500'
},
'multi-menu': {
_value: 'ម៉ឺនុយពហុដឺក្រេ',
first: {
_value: 'ដឺក្រេទី១',
second: 'ដែក្រេទី២',
'second-new': {
_value: 'ដឺក្រេទី២មានអនុក្រោម',
third: 'ដឺក្រេទី៣'
}
} }
}, },
management: { tab: {
_value: 'ការគ្រប់គ្រងប្រព័ន្ធ', visible: 'បង្ហាញរុករកជាក់លាក់',
auth: 'Auth', height: 'កម្ពស់',
role: 'សិទ្ធី', modeList: {
route: 'ផ្លូវប្រព័ន្ធ', mode: 'របៀប',
chrome: 'ក្រុមហ៊ុន',
button: 'ប៊ូតុង'
},
isCache: 'រក្សាទុកការរុករកជាក់លាក់'
},
sider: {
inverted: 'បង្កើតការរុករកជាក់លាក់',
width: 'ទទឹង',
mixWidth: 'ទទឹងបញ្ចូល'
},
menu: {
horizontalPosition: 'ទីតាំងផ្ដេក',
horizontalPositionList: {
flexStart: 'ចាប់ផ្ដើមឈុត',
center: 'កណ្តាល',
flexEnd: 'ចាប់ផ្ដើមចុងក្រោយ'
}
},
footer: {
inverted: 'បង្កើតការរុករកជាក់លាក់',
visible: 'បង្ហាញការរុករកជាក់លាក់',
fixed: 'ការរុករកជាក់លាក់',
right: 'ត្រឡប់ទៅស្តាំ'
},
page: {
animate: 'ការផ្លាស់ប្តូរ',
animateMode: 'របៀបផ្លាស់ប្តូរ',
animateModeList: {
zoomFade: 'ពង្រីកបង្ហាញនិងលាស់ប្តូរ',
zoomOut: 'ពង្រីកបង្ហាញនិងលាស់ប្តូរ',
fadeSlide: 'ពង្រីកបង្ហាញនិងលាស់ប្តូរ',
fade: 'ពង្រីកបង្ហាញនិងលាស់ប្តូរ',
fadeBottom: 'ពង្រីកបង្ហាញនិងលាស់ប្តូរ',
fadeScale: 'ពង្រីកបង្ហាញនិងលាស់ប្តូរ'
}
},
systemTheme: {
moreColors: 'ពន្លឺច្រើនទៀត'
},
themeConfiguration: {
title: 'ការកំណត់ស្បែក',
copy: 'ចម្លង',
reset: 'កំណត់ឡើងវិញ',
resetSuccess: 'កំណត់ឡើងវិញជោគជ័យ, សូមចម្លងឯកសារស្បែកឡើងវិញ!',
operateSuccess: 'សម្រាប់ការប្រើប្រាស់ជោគជ័យ',
copySuccess: 'ចម្លងជោគជ័យ, សូមជោគជ័យឯកសារ src/settings/theme.json!',
confirmCopy: 'យល់ព្រម'
}
}
},
page: {
login: {
common: {
userNamePlaceholder: 'ឈ្មោះអ្នកប្រើប្រាស់',
phonePlaceholder: 'លេខទូរស័ព្ទ',
codePlaceholder: 'លេខកូដ',
passwordPlaceholder: 'លេខសម្ងាត់',
confirmPasswordPlaceholder: 'បញ្ជាក់លេខសម្ងាត់',
codeLogin: 'ចូលតាមលេខកូដ',
confirm: 'យល់ព្រម',
back: 'ត្រឡប់ក្រោយ',
validateSuccess: 'បញ្ជាក់ជោគជ័យ',
loginSuccess: 'ចូលជោគជ័យ',
welcomeBack: 'សូមស្វាគមន៍ម្តងទៀត, {userName}!'
},
pwdLogin: {
title: 'ចូលគណនី',
rememberMe: 'ចងចាំខ្ញុំ',
forgetPassword: 'ភ្លេចលេខសម្ងាត់',
register: 'ចុះឈ្មោះ',
otherAccountLogin: 'ចូលតាមគណនីផ្សេងទៀត',
otherLoginMode: 'របៀបចូលគណនីផ្សេងទៀត',
superAdmin: 'អ្នកគ្រប់គ្រងសុវត្ថិភាព',
admin: 'អ្នកគ្រប់គ្រង',
user: 'អ្នកប្រើប្រាស់' user: 'អ្នកប្រើប្រាស់'
}, },
about: 'អំពីប្រព័ន្ធ' codeLogin: {
title: 'ចូលតាមលេខកូដ',
getCode: 'ទទួលលេខកូដ',
imageCodePlaceholder: 'លេខកូដរូបភាព'
},
register: {
title: 'ចុះឈ្មោះ',
agreement: 'យល់ព្រមនឹង',
protocol: 'សម្រាប់ការប្រើប្រាស់',
policy: 'គោលការណ៍ផ្សេងៗ'
},
resetPwd: {
title: 'កំណត់លេខសម្ងាត់ថ្មី'
},
bindWeChat: {
title: 'ភ្ជាប់គណនីរបស់អ្នកជាមួយគណនីរបស់អ្នក'
}
} }
} }
}; };

View File

@ -1,85 +0,0 @@
import type { LocaleMessages } from 'vue-i18n';
const locale: LocaleMessages<I18nType.Schema> = {
message: {
system: {
title: 'Soybean管理系统'
},
routes: {
dashboard: {
_value: '仪表盘',
analysis: '分析页',
workbench: '工作台'
},
document: {
_value: '文档',
vue: 'Vue文档',
vite: 'Vite文档',
naive: 'NaiveUI文档',
project: '项目文档',
'project-link': '项目文档(外链)'
},
component: {
_value: '组件示例',
button: '按钮',
card: '卡片',
table: '表格'
},
plugin: {
_value: '插件示例',
charts: {
_value: '图表',
echarts: 'ECharts',
antv: 'AntV'
},
copy: '剪贴板',
editor: {
_value: '编辑器',
quill: '富文本',
markdown: 'Markdown'
},
icon: '图标',
map: '地图',
print: '打印',
swiper: 'Swiper',
video: '视频'
},
'auth-demo': {
_value: '权限示例',
permission: '切换权限',
super: '超级管理员可见'
},
function: {
_value: '功能',
tab: 'Tab页签'
},
exception: {
_value: '异常页',
403: '403',
404: '404',
500: '500'
},
'multi-menu': {
_value: '多级菜单',
first: {
_value: '一级菜单',
second: '二级菜单',
'second-new': {
_value: '二级菜单(有子菜单)',
third: '三级菜单'
}
}
},
management: {
_value: '系统管理',
auth: '权限管理',
role: '角色管理',
route: '路由管理',
user: '用户管理'
},
about: '关于'
}
}
};
export default locale;

219
src/locales/lang/zhCN.ts Normal file
View File

@ -0,0 +1,219 @@
const locale: I18nType.Schema = {
system: {
title: 'Soybean管理系统'
},
common: {
add: '添加',
addSuccess: '添加成功',
edit: '修改',
editSuccess: '修改成功',
delete: '删除',
deleteSuccess: '删除成功',
batchDelete: '批量删除',
confirm: '确认',
cancel: '取消',
pleaseCheckValue: '请检查输入的值是否合法',
action: '操作'
},
routes: {
dashboard: {
_value: '仪表盘',
analysis: '分析页',
workbench: '工作台'
},
document: {
_value: '文档',
vue: 'Vue文档',
vite: 'Vite文档',
naive: 'NaiveUI文档',
project: '项目文档',
'project-link': '项目文档(外链)'
},
component: {
_value: '组件示例',
button: '按钮',
card: '卡片',
table: '表格'
},
plugin: {
_value: '插件示例',
charts: {
_value: '图表',
echarts: 'ECharts',
antv: 'AntV'
},
copy: '剪贴板',
editor: {
_value: '编辑器',
quill: '富文本',
markdown: 'Markdown'
},
icon: '图标',
map: '地图',
print: '打印',
swiper: 'Swiper',
video: '视频'
},
'auth-demo': {
_value: '权限示例',
permission: '切换权限',
super: '超级管理员可见'
},
function: {
_value: '功能',
tab: 'Tab页签'
},
exception: {
_value: '异常页',
403: '403',
404: '404',
500: '500'
},
'multi-menu': {
_value: '多级菜单',
first: {
_value: '一级菜单',
second: '二级菜单',
'second-new': {
_value: '二级菜单(有子菜单)',
third: '三级菜单'
}
}
},
management: {
_value: '系统管理',
auth: '权限管理',
role: '角色管理',
route: '路由管理',
user: '用户管理'
},
about: '关于'
},
layout: {
settingDrawer: {
title: '主题配置',
themeModeTitle: '主题模式',
darkMode: '深色主题',
layoutModelTitle: '布局模式',
systemThemeTitle: '系统主题',
pageFunctionsTitle: '界面功能',
pageViewTitle: '界面显示',
followSystemTheme: '跟随系统',
isCustomizeDarkModeTransition: '自定义暗黑主题动画过渡',
scrollMode: '滚动模式',
scrollModeList: {
wrapper: '外层滚动',
content: '主体滚动'
},
fixedHeaderAndTab: '固定头部和多页签',
header: {
inverted: '头部深色',
height: '头部高度',
crumb: {
visible: '面包屑',
icon: '面包屑图标'
}
},
tab: {
visible: '多页签',
height: '多页签高度',
modeList: {
mode: '多页签风格',
chrome: '谷歌风格',
button: '按钮风格'
},
isCache: '多页签缓存'
},
sider: {
inverted: '侧边栏深色',
width: '侧边栏展开宽度',
mixWidth: '左侧混合侧边栏展开宽度'
},
menu: {
horizontalPosition: '顶部菜单位置',
horizontalPositionList: {
flexStart: '居左',
center: '居中',
flexEnd: '居右'
}
},
footer: {
inverted: '底部深色',
visible: '显示底部',
fixed: '固定底部',
right: '底部居右'
},
page: {
animate: '页面切换动画',
animateMode: '页面切换动画类型',
animateModeList: {
zoomFade: '渐变',
zoomOut: '闪现',
fadeSlide: '滑动',
fade: '消退',
fadeBottom: '底部消退',
fadeScale: '缩放消退'
}
},
systemTheme: {
moreColors: '更多颜色'
},
themeConfiguration: {
title: '主题配置',
copy: '拷贝当前配置',
reset: '重置当前配置',
resetSuccess: '已重置配置,请重新拷贝!',
operateSuccess: '操作成功',
copySuccess: '复制成功,请替换 src/settings/theme.json的内容',
confirmCopy: '确认'
}
}
},
page: {
login: {
common: {
userNamePlaceholder: '请输入用户名',
phonePlaceholder: '请输入手机号',
codePlaceholder: '请输入验证码',
passwordPlaceholder: '请输入密码',
confirmPasswordPlaceholder: '请再次输入密码',
codeLogin: '验证码登录',
confirm: '确定',
back: '返回',
validateSuccess: '验证成功',
loginSuccess: '登录成功',
welcomeBack: '欢迎回来,{userName}!'
},
pwdLogin: {
title: '密码登录',
rememberMe: '记住我',
forgetPassword: '忘记密码?',
register: '注册账号',
otherAccountLogin: '其他账号登录',
otherLoginMode: '其他登录方式',
superAdmin: '超级管理员',
admin: '管理员',
user: '普通用户'
},
codeLogin: {
title: '验证码登录',
getCode: '获取验证码',
imageCodePlaceholder: '请输入图片验证码'
},
register: {
title: '注册账号',
agreement: '我已经仔细阅读并接受',
protocol: '《用户协议》',
policy: '《隐私权政策》'
},
resetPwd: {
title: '重置密码'
},
bindWeChat: {
title: '绑定微信'
}
}
}
};
export default locale;

11
src/locales/locale.ts Normal file
View File

@ -0,0 +1,11 @@
import zhCN from './lang/zhCN';
import en from './lang/en';
import kmKH from './lang/km-KH';
const locales: Record<I18nType.LangType, I18nType.Schema> = {
'zh-CN': zhCN,
en,
'km-KH': kmKH
};
export default locales;

View File

@ -1,6 +1,6 @@
import type { Router } from 'vue-router'; import type { Router } from 'vue-router';
import { useTitle } from '@vueuse/core'; import { useTitle } from '@vueuse/core';
import { t } from '@/locales'; import { $t } from '@/locales';
import { createPermissionGuard } from './permission'; import { createPermissionGuard } from './permission';
/** /**
@ -16,7 +16,7 @@ export function createRouterGuard(router: Router) {
}); });
router.afterEach(to => { router.afterEach(to => {
// 设置document title // 设置document title
useTitle(to.meta.i18nTitle ? t(to.meta.i18nTitle) : to.meta.title); useTitle(to.meta.i18nTitle ? $t(to.meta.i18nTitle) : to.meta.title);
// 结束 loadingBar // 结束 loadingBar
window.$loadingBar?.finish(); window.$loadingBar?.finish();
}); });

View File

@ -1,10 +1,10 @@
const about1: AuthRoute.Route = { const about: AuthRoute.Route = {
name: 'about', name: 'about',
path: '/about', path: '/about',
component: 'self', component: 'self',
meta: { meta: {
title: '关于', title: '关于',
i18nTitle: 'message.routes.about', i18nTitle: 'routes.about',
requiresAuth: true, requiresAuth: true,
keepAlive: true, keepAlive: true,
singleLayout: 'basic', singleLayout: 'basic',
@ -14,4 +14,4 @@ const about1: AuthRoute.Route = {
} }
}; };
export default about1; export default about;

View File

@ -9,7 +9,7 @@ const authDemo: AuthRoute.Route = {
component: 'self', component: 'self',
meta: { meta: {
title: '权限切换', title: '权限切换',
i18nTitle: 'message.routes.auth-demo.permission', i18nTitle: 'routes.auth-demo.permission',
requiresAuth: true, requiresAuth: true,
icon: 'ic:round-construction' icon: 'ic:round-construction'
} }
@ -20,7 +20,7 @@ const authDemo: AuthRoute.Route = {
component: 'self', component: 'self',
meta: { meta: {
title: '超级管理员可见', title: '超级管理员可见',
i18nTitle: 'message.routes.auth-demo.super', i18nTitle: 'routes.auth-demo.super',
requiresAuth: true, requiresAuth: true,
permissions: ['super'], permissions: ['super'],
icon: 'ic:round-supervisor-account' icon: 'ic:round-supervisor-account'
@ -29,7 +29,7 @@ const authDemo: AuthRoute.Route = {
], ],
meta: { meta: {
title: '权限示例', title: '权限示例',
i18nTitle: 'message.routes.auth-demo._value', i18nTitle: 'routes.auth-demo._value',
icon: 'ic:baseline-security', icon: 'ic:baseline-security',
order: 5 order: 5
} }

View File

@ -9,7 +9,7 @@ const component: AuthRoute.Route = {
component: 'self', component: 'self',
meta: { meta: {
title: '按钮', title: '按钮',
i18nTitle: 'message.routes.component.button', i18nTitle: 'routes.component.button',
requiresAuth: true, requiresAuth: true,
icon: 'mdi:button-cursor' icon: 'mdi:button-cursor'
} }
@ -20,7 +20,7 @@ const component: AuthRoute.Route = {
component: 'self', component: 'self',
meta: { meta: {
title: '卡片', title: '卡片',
i18nTitle: 'message.routes.component.card', i18nTitle: 'routes.component.card',
requiresAuth: true, requiresAuth: true,
icon: 'mdi:card-outline' icon: 'mdi:card-outline'
} }
@ -31,7 +31,7 @@ const component: AuthRoute.Route = {
component: 'self', component: 'self',
meta: { meta: {
title: '表格', title: '表格',
i18nTitle: 'message.routes.component.table', i18nTitle: 'routes.component.table',
requiresAuth: true, requiresAuth: true,
icon: 'mdi:table-large' icon: 'mdi:table-large'
} }
@ -39,7 +39,7 @@ const component: AuthRoute.Route = {
], ],
meta: { meta: {
title: '组件示例', title: '组件示例',
i18nTitle: 'message.routes.component._value', i18nTitle: 'routes.component._value',
icon: 'cib:app-store', icon: 'cib:app-store',
order: 3 order: 3
} }

View File

@ -11,7 +11,7 @@ const dashboard: AuthRoute.Route = {
title: '分析页', title: '分析页',
requiresAuth: true, requiresAuth: true,
icon: 'icon-park-outline:analysis', icon: 'icon-park-outline:analysis',
i18nTitle: 'message.routes.dashboard.analysis' i18nTitle: 'routes.dashboard.analysis'
} }
}, },
{ {
@ -22,7 +22,7 @@ const dashboard: AuthRoute.Route = {
title: '工作台', title: '工作台',
requiresAuth: true, requiresAuth: true,
icon: 'icon-park-outline:workbench', icon: 'icon-park-outline:workbench',
i18nTitle: 'message.routes.dashboard.workbench' i18nTitle: 'routes.dashboard.workbench'
} }
} }
], ],
@ -30,7 +30,7 @@ const dashboard: AuthRoute.Route = {
title: '仪表盘', title: '仪表盘',
icon: 'mdi:monitor-dashboard', icon: 'mdi:monitor-dashboard',
order: 1, order: 1,
i18nTitle: 'message.routes.dashboard._value' i18nTitle: 'routes.dashboard._value'
} }
}; };

View File

@ -9,7 +9,7 @@ const document: AuthRoute.Route = {
component: 'self', component: 'self',
meta: { meta: {
title: 'vue文档', title: 'vue文档',
i18nTitle: 'message.routes.document.vue', i18nTitle: 'routes.document.vue',
requiresAuth: true, requiresAuth: true,
icon: 'logos:vue' icon: 'logos:vue'
} }
@ -20,7 +20,7 @@ const document: AuthRoute.Route = {
component: 'self', component: 'self',
meta: { meta: {
title: 'vite文档', title: 'vite文档',
i18nTitle: 'message.routes.document.vite', i18nTitle: 'routes.document.vite',
requiresAuth: true, requiresAuth: true,
icon: 'logos:vitejs' icon: 'logos:vitejs'
} }
@ -31,7 +31,7 @@ const document: AuthRoute.Route = {
component: 'self', component: 'self',
meta: { meta: {
title: 'naive文档', title: 'naive文档',
i18nTitle: 'message.routes.document.naive', i18nTitle: 'routes.document.naive',
requiresAuth: true, requiresAuth: true,
icon: 'logos:naiveui' icon: 'logos:naiveui'
} }
@ -42,7 +42,7 @@ const document: AuthRoute.Route = {
component: 'self', component: 'self',
meta: { meta: {
title: '项目文档', title: '项目文档',
i18nTitle: 'message.routes.document.project', i18nTitle: 'routes.document.project',
requiresAuth: true, requiresAuth: true,
localIcon: 'logo' localIcon: 'logo'
} }
@ -52,7 +52,7 @@ const document: AuthRoute.Route = {
path: '/document/project-link', path: '/document/project-link',
meta: { meta: {
title: '项目文档(外链)', title: '项目文档(外链)',
i18nTitle: 'message.routes.document.project-link', i18nTitle: 'routes.document.project-link',
requiresAuth: true, requiresAuth: true,
localIcon: 'logo', localIcon: 'logo',
href: 'https://docs.soybean.pro/' href: 'https://docs.soybean.pro/'
@ -61,7 +61,7 @@ const document: AuthRoute.Route = {
], ],
meta: { meta: {
title: '文档', title: '文档',
i18nTitle: 'message.routes.document._value', i18nTitle: 'routes.document._value',
icon: 'mdi:file-document-multiple-outline', icon: 'mdi:file-document-multiple-outline',
order: 2 order: 2
} }

View File

@ -9,7 +9,7 @@ const exception: AuthRoute.Route = {
component: 'self', component: 'self',
meta: { meta: {
title: '异常页403', title: '异常页403',
i18nTitle: 'message.routes.exception.403', i18nTitle: 'routes.exception.403',
requiresAuth: true, requiresAuth: true,
icon: 'ic:baseline-block' icon: 'ic:baseline-block'
} }
@ -20,7 +20,7 @@ const exception: AuthRoute.Route = {
component: 'self', component: 'self',
meta: { meta: {
title: '异常页404', title: '异常页404',
i18nTitle: 'message.routes.exception.404', i18nTitle: 'routes.exception.404',
requiresAuth: true, requiresAuth: true,
icon: 'ic:baseline-web-asset-off' icon: 'ic:baseline-web-asset-off'
} }
@ -31,14 +31,14 @@ const exception: AuthRoute.Route = {
component: 'self', component: 'self',
meta: { meta: {
title: '异常页500', title: '异常页500',
i18nTitle: 'message.routes.exception.500', i18nTitle: 'routes.exception.500',
requiresAuth: true, requiresAuth: true,
icon: 'ic:baseline-wifi-off' icon: 'ic:baseline-wifi-off'
} }
} }
], ],
meta: { meta: {
i18nTitle: 'message.routes.exception._value', i18nTitle: 'routes.exception._value',
title: '异常页', title: '异常页',
icon: 'ant-design:exception-outlined', icon: 'ant-design:exception-outlined',
order: 7 order: 7

View File

@ -9,7 +9,7 @@ const functionRoute: AuthRoute.Route = {
component: 'self', component: 'self',
meta: { meta: {
title: 'Tab', title: 'Tab',
i18nTitle: 'message.routes.function.tab', i18nTitle: 'routes.function.tab',
requiresAuth: true, requiresAuth: true,
icon: 'ic:round-tab' icon: 'ic:round-tab'
} }
@ -42,7 +42,7 @@ const functionRoute: AuthRoute.Route = {
], ],
meta: { meta: {
title: '功能', title: '功能',
i18nTitle: 'message.routes.function._value', i18nTitle: 'routes.function._value',
icon: 'icon-park-outline:all-application', icon: 'icon-park-outline:all-application',
order: 6 order: 6
} }

View File

@ -9,7 +9,7 @@ const management: AuthRoute.Route = {
component: 'self', component: 'self',
meta: { meta: {
title: '权限管理', title: '权限管理',
i18nTitle: 'message.routes.management.auth', i18nTitle: 'routes.management.auth',
requiresAuth: true, requiresAuth: true,
icon: 'ic:baseline-security' icon: 'ic:baseline-security'
} }
@ -20,7 +20,7 @@ const management: AuthRoute.Route = {
component: 'self', component: 'self',
meta: { meta: {
title: '角色管理', title: '角色管理',
i18nTitle: 'message.routes.management.role', i18nTitle: 'routes.management.role',
requiresAuth: true, requiresAuth: true,
icon: 'carbon:user-role' icon: 'carbon:user-role'
} }
@ -31,7 +31,7 @@ const management: AuthRoute.Route = {
component: 'self', component: 'self',
meta: { meta: {
title: '用户管理', title: '用户管理',
i18nTitle: 'message.routes.management.user', i18nTitle: 'routes.management.user',
requiresAuth: true, requiresAuth: true,
icon: 'ic:round-manage-accounts' icon: 'ic:round-manage-accounts'
} }
@ -42,7 +42,7 @@ const management: AuthRoute.Route = {
component: 'self', component: 'self',
meta: { meta: {
title: '路由管理', title: '路由管理',
i18nTitle: 'message.routes.management.route', i18nTitle: 'routes.management.route',
requiresAuth: true, requiresAuth: true,
icon: 'material-symbols:route' icon: 'material-symbols:route'
} }
@ -50,7 +50,7 @@ const management: AuthRoute.Route = {
], ],
meta: { meta: {
title: '系统管理', title: '系统管理',
i18nTitle: 'message.routes.management._value', i18nTitle: 'routes.management._value',
icon: 'carbon:cloud-service-management', icon: 'carbon:cloud-service-management',
order: 9 order: 9
} }

View File

@ -14,7 +14,7 @@ const multiMenu: AuthRoute.Route = {
component: 'self', component: 'self',
meta: { meta: {
title: '二级菜单', title: '二级菜单',
i18nTitle: 'message.routes.multi-menu.first.second', i18nTitle: 'routes.multi-menu.first.second',
requiresAuth: true, requiresAuth: true,
icon: 'mdi:menu' icon: 'mdi:menu'
} }
@ -30,7 +30,7 @@ const multiMenu: AuthRoute.Route = {
component: 'self', component: 'self',
meta: { meta: {
title: '三级菜单', title: '三级菜单',
i18nTitle: 'message.routes.multi-menu.first.second-new.third', i18nTitle: 'routes.multi-menu.first.second-new.third',
requiresAuth: true, requiresAuth: true,
icon: 'mdi:menu' icon: 'mdi:menu'
} }
@ -38,21 +38,21 @@ const multiMenu: AuthRoute.Route = {
], ],
meta: { meta: {
title: '二级菜单(有子菜单)', title: '二级菜单(有子菜单)',
i18nTitle: 'message.routes.multi-menu.first.second-new._value', i18nTitle: 'routes.multi-menu.first.second-new._value',
icon: 'mdi:menu' icon: 'mdi:menu'
} }
} }
], ],
meta: { meta: {
title: '一级菜单', title: '一级菜单',
i18nTitle: 'message.routes.multi-menu.first._value', i18nTitle: 'routes.multi-menu.first._value',
icon: 'mdi:menu' icon: 'mdi:menu'
} }
} }
], ],
meta: { meta: {
title: '多级菜单', title: '多级菜单',
i18nTitle: 'message.routes.multi-menu._value', i18nTitle: 'routes.multi-menu._value',
icon: 'carbon:menu', icon: 'carbon:menu',
order: 8 order: 8
} }

View File

@ -14,7 +14,7 @@ const plugin: AuthRoute.Route = {
component: 'self', component: 'self',
meta: { meta: {
title: 'ECharts', title: 'ECharts',
i18nTitle: 'message.routes.plugin.charts.echarts', i18nTitle: 'routes.plugin.charts.echarts',
requiresAuth: true, requiresAuth: true,
icon: 'simple-icons:apacheecharts' icon: 'simple-icons:apacheecharts'
} }
@ -25,7 +25,7 @@ const plugin: AuthRoute.Route = {
component: 'self', component: 'self',
meta: { meta: {
title: 'AntV', title: 'AntV',
i18nTitle: 'message.routes.plugin.charts.antv', i18nTitle: 'routes.plugin.charts.antv',
requiresAuth: true, requiresAuth: true,
icon: 'simple-icons:antdesign' icon: 'simple-icons:antdesign'
} }
@ -33,7 +33,7 @@ const plugin: AuthRoute.Route = {
], ],
meta: { meta: {
title: '图表', title: '图表',
i18nTitle: 'message.routes.plugin.charts._value', i18nTitle: 'routes.plugin.charts._value',
icon: 'mdi:chart-areaspline' icon: 'mdi:chart-areaspline'
} }
}, },
@ -43,7 +43,7 @@ const plugin: AuthRoute.Route = {
component: 'self', component: 'self',
meta: { meta: {
title: '地图', title: '地图',
i18nTitle: 'message.routes.plugin.map', i18nTitle: 'routes.plugin.map',
requiresAuth: true, requiresAuth: true,
icon: 'mdi:map' icon: 'mdi:map'
} }
@ -54,7 +54,7 @@ const plugin: AuthRoute.Route = {
component: 'self', component: 'self',
meta: { meta: {
title: '视频', title: '视频',
i18nTitle: 'message.routes.plugin.video', i18nTitle: 'routes.plugin.video',
requiresAuth: true, requiresAuth: true,
icon: 'mdi:video' icon: 'mdi:video'
} }
@ -70,7 +70,7 @@ const plugin: AuthRoute.Route = {
component: 'self', component: 'self',
meta: { meta: {
title: '富文本编辑器', title: '富文本编辑器',
i18nTitle: 'message.routes.plugin.editor.quill', i18nTitle: 'routes.plugin.editor.quill',
requiresAuth: true, requiresAuth: true,
icon: 'mdi:file-document-edit-outline' icon: 'mdi:file-document-edit-outline'
} }
@ -81,7 +81,7 @@ const plugin: AuthRoute.Route = {
component: 'self', component: 'self',
meta: { meta: {
title: 'markdown编辑器', title: 'markdown编辑器',
i18nTitle: 'message.routes.plugin.editor.markdown', i18nTitle: 'routes.plugin.editor.markdown',
requiresAuth: true, requiresAuth: true,
icon: 'ri:markdown-line' icon: 'ri:markdown-line'
} }
@ -89,7 +89,7 @@ const plugin: AuthRoute.Route = {
], ],
meta: { meta: {
title: '编辑器', title: '编辑器',
i18nTitle: 'message.routes.plugin.editor._value', i18nTitle: 'routes.plugin.editor._value',
icon: 'icon-park-outline:editor' icon: 'icon-park-outline:editor'
} }
}, },
@ -99,7 +99,7 @@ const plugin: AuthRoute.Route = {
component: 'self', component: 'self',
meta: { meta: {
title: 'Swiper插件', title: 'Swiper插件',
i18nTitle: 'message.routes.plugin.swiper', i18nTitle: 'routes.plugin.swiper',
requiresAuth: true, requiresAuth: true,
icon: 'simple-icons:swiper' icon: 'simple-icons:swiper'
} }
@ -110,7 +110,7 @@ const plugin: AuthRoute.Route = {
component: 'self', component: 'self',
meta: { meta: {
title: '剪贴板', title: '剪贴板',
i18nTitle: 'message.routes.plugin.copy', i18nTitle: 'routes.plugin.copy',
requiresAuth: true, requiresAuth: true,
icon: 'mdi:clipboard-outline' icon: 'mdi:clipboard-outline'
} }
@ -121,7 +121,7 @@ const plugin: AuthRoute.Route = {
component: 'self', component: 'self',
meta: { meta: {
title: '图标', title: '图标',
i18nTitle: 'message.routes.plugin.icon', i18nTitle: 'routes.plugin.icon',
requiresAuth: true, requiresAuth: true,
localIcon: 'custom-icon' localIcon: 'custom-icon'
} }
@ -132,7 +132,7 @@ const plugin: AuthRoute.Route = {
component: 'self', component: 'self',
meta: { meta: {
title: '打印', title: '打印',
i18nTitle: 'message.routes.plugin.print', i18nTitle: 'routes.plugin.print',
requiresAuth: true, requiresAuth: true,
icon: 'mdi:printer' icon: 'mdi:printer'
} }
@ -140,7 +140,7 @@ const plugin: AuthRoute.Route = {
], ],
meta: { meta: {
title: '插件示例', title: '插件示例',
i18nTitle: 'message.routes.plugin._value', i18nTitle: 'routes.plugin._value',
icon: 'clarity:plugin-line', icon: 'clarity:plugin-line',
order: 4 order: 4
} }

View File

@ -4,6 +4,7 @@ import { router } from '@/router';
import { fetchLogin, fetchUserInfo } from '@/service'; import { fetchLogin, fetchUserInfo } from '@/service';
import { useRouterPush } from '@/composables'; import { useRouterPush } from '@/composables';
import { localStg } from '@/utils'; import { localStg } from '@/utils';
import { $t } from '@/locales';
import { useTabStore } from '../tab'; import { useTabStore } from '../tab';
import { useRouteStore } from '../route'; import { useRouteStore } from '../route';
import { getToken, getUserInfo, clearAuthStorage } from './helpers'; import { getToken, getUserInfo, clearAuthStorage } from './helpers';
@ -68,8 +69,8 @@ export const useAuthStore = defineStore('auth-store', {
// 登录成功弹出欢迎提示 // 登录成功弹出欢迎提示
if (route.isInitAuthRoute) { if (route.isInitAuthRoute) {
window.$notification?.success({ window.$notification?.success({
title: '登录成功!', title: $t('page.login.common.loginSuccess'),
content: `欢迎回来,${this.userInfo.userName}!`, content: $t('page.login.common.welcomeBack', { userName: this.userInfo.userName }),
duration: 3000 duration: 3000
}); });
} }

View File

@ -69,7 +69,7 @@ export const useTabStore = defineStore('tab-store', {
const item = this.tabs.find(tab => tab.fullPath === this.activeTab); const item = this.tabs.find(tab => tab.fullPath === this.activeTab);
if (item) { if (item) {
if (item.meta.i18nTitle) { if (item.meta.i18nTitle) {
item.meta.i18nTitle = title; item.meta.i18nTitle = title as I18nType.I18nKey;
} else { } else {
item.meta.title = title; item.meta.title = title;
} }

View File

@ -32,7 +32,7 @@ declare namespace AuthRoute {
/** 路由标题(可用来作document.title或者菜单的名称) */ /** 路由标题(可用来作document.title或者菜单的名称) */
title: string; title: string;
/** 用来支持多国语言 如果i18nTitle和title同时存在优先使用i18nTitle */ /** 用来支持多国语言 如果i18nTitle和title同时存在优先使用i18nTitle */
i18nTitle?: string; i18nTitle?: I18nType.I18nKey;
/** 路由的动态路径(需要动态路径的页面需要将path添加进范型参数) */ /** 路由的动态路径(需要动态路径的页面需要将path添加进范型参数) */
dynamicPath?: AuthRouteUtils.GetDynamicPath<K>; dynamicPath?: AuthRouteUtils.GetDynamicPath<K>;
/** 作为单级路由的父级路由布局组件 */ /** 作为单级路由的父级路由布局组件 */

View File

@ -244,7 +244,7 @@ declare namespace App {
routePath: string; routePath: string;
icon?: () => import('vue').VNodeChild; icon?: () => import('vue').VNodeChild;
children?: GlobalMenuOption[]; children?: GlobalMenuOption[];
i18nTitle?: string; i18nTitle?: I18nType.I18nKey;
}; };
/** 面包屑 */ /** 面包屑 */
@ -255,8 +255,8 @@ declare namespace App {
routeName: string; routeName: string;
hasChildren: boolean; hasChildren: boolean;
icon?: import('vue').Component; icon?: import('vue').Component;
i18nTitle?: string; i18nTitle?: I18nType.I18nKey;
options?: (import('naive-ui/es/dropdown/src/interface').DropdownMixedOption & { i18nTitle?: string })[]; options?: (import('naive-ui/es/dropdown/src/interface').DropdownMixedOption & { i18nTitle?: I18nType.I18nKey })[];
}; };
/** 多页签Tab的路由 */ /** 多页签Tab的路由 */
@ -304,12 +304,25 @@ declare namespace App {
} }
declare namespace I18nType { declare namespace I18nType {
type langType = 'en' | 'zh-CN' | 'km-KH'; type LangType = 'en' | 'zh-CN' | 'km-KH';
interface Schema { type Schema = {
system: { system: {
title: string; title: string;
}; };
common: {
add: string;
addSuccess: string;
edit: string;
editSuccess: string;
delete: string;
deleteSuccess: string;
batchDelete: string;
confirm: string;
cancel: string;
pleaseCheckValue: string;
action: string;
};
routes: { routes: {
dashboard: { dashboard: {
_value: string; _value: string;
@ -360,9 +373,9 @@ declare namespace I18nType {
}; };
exception: { exception: {
_value: string; _value: string;
403: string; '403': string;
404: string; '404': string;
500: string; '500': string;
}; };
'multi-menu': { 'multi-menu': {
_value: string; _value: string;
@ -384,5 +397,138 @@ declare namespace I18nType {
}; };
about: string; about: string;
}; };
} layout: {
settingDrawer: {
title: string;
themeModeTitle: string;
darkMode: string;
layoutModelTitle: string;
systemThemeTitle: string;
pageFunctionsTitle: string;
pageViewTitle: string;
followSystemTheme: string;
isCustomizeDarkModeTransition: string;
scrollMode: string;
scrollModeList: {
wrapper: string;
content: string;
};
fixedHeaderAndTab: string;
header: {
inverted: string;
height: string;
crumb: {
visible: string;
icon: string;
};
};
tab: {
visible: string;
height: string;
modeList: {
mode: string;
chrome: string;
button: string;
};
isCache: string;
};
sider: {
inverted: string;
width: string;
mixWidth: string;
};
menu: {
horizontalPosition: string;
horizontalPositionList: {
flexStart: string;
center: string;
flexEnd: string;
};
};
footer: {
inverted: string;
visible: string;
fixed: string;
right: string;
};
page: {
animate: string;
animateMode: string;
animateModeList: {
zoomFade: string;
zoomOut: string;
fadeSlide: string;
fade: string;
fadeBottom: string;
fadeScale: string;
};
};
systemTheme: {
moreColors: string;
};
themeConfiguration: {
title: string;
copy: string;
reset: string;
resetSuccess: string;
operateSuccess: string;
copySuccess: string;
confirmCopy: string;
};
};
};
page: {
login: {
common: {
userNamePlaceholder: string;
phonePlaceholder: string;
codePlaceholder: string;
passwordPlaceholder: string;
confirmPasswordPlaceholder: string;
codeLogin: string;
confirm: string;
back: string;
validateSuccess: string;
loginSuccess: string;
welcomeBack: string;
};
pwdLogin: {
title: string;
rememberMe: string;
forgetPassword: string;
register: string;
otherAccountLogin: string;
otherLoginMode: string;
superAdmin: string;
admin: string;
user: string;
};
codeLogin: {
title: string;
getCode: string;
imageCodePlaceholder: string;
};
register: {
title: string;
agreement: string;
protocol: string;
policy: string;
};
resetPwd: {
title: string;
};
bindWeChat: {
title: string;
};
};
};
};
type GetI18nKey<T extends Record<string, unknown>, K extends keyof T = keyof T> = K extends string
? T[K] extends Record<string, unknown>
? `${K}.${GetI18nKey<T[K]>}`
: K
: never;
type I18nKey = GetI18nKey<Schema>;
} }

View File

@ -1,5 +1,5 @@
import { useIconRender } from '@/composables'; import { useIconRender } from '@/composables';
import { t } from '@/locales'; import { $t } from '@/locales';
/** /**
* *
@ -50,7 +50,7 @@ export function translateMenuLabel(menus: App.GlobalMenuOption[]): App.GlobalMen
const menuItem: App.GlobalMenuOption = { const menuItem: App.GlobalMenuOption = {
...menu, ...menu,
children: menuChildren, children: menuChildren,
label: menu.i18nTitle ? t(menu.i18nTitle) : menu.label label: menu.i18nTitle ? $t(menu.i18nTitle) : menu.label
}; };
globalMenu.push(menuItem); globalMenu.push(menuItem);
}); });

View File

@ -1,11 +1,11 @@
<template> <template>
<n-form ref="formRef" :model="model" :rules="rules" size="large" :show-label="false"> <n-form ref="formRef" :model="model" :rules="rules" size="large" :show-label="false">
<n-form-item path="phone"> <n-form-item path="phone">
<n-input v-model:value="model.phone" placeholder="手机号码" /> <n-input v-model:value="model.phone" :placeholder="$t('page.login.common.phonePlaceholder')" />
</n-form-item> </n-form-item>
<n-form-item path="code"> <n-form-item path="code">
<div class="flex-y-center w-full"> <div class="flex-y-center w-full">
<n-input v-model:value="model.code" placeholder="验证码" /> <n-input v-model:value="model.code" :placeholder="$t('page.login.common.codePlaceholder')" />
<div class="w-18px"></div> <div class="w-18px"></div>
<n-button size="large" :disabled="isCounting" :loading="smsLoading" @click="handleSmsCode"> <n-button size="large" :disabled="isCounting" :loading="smsLoading" @click="handleSmsCode">
{{ label }} {{ label }}
@ -13,8 +13,12 @@
</div> </div>
</n-form-item> </n-form-item>
<n-space :vertical="true" size="large"> <n-space :vertical="true" size="large">
<n-button type="primary" size="large" :block="true" :round="true" @click="handleSubmit">确定</n-button> <n-button type="primary" size="large" :block="true" :round="true" @click="handleSubmit">
<n-button size="large" :block="true" :round="true" @click="toLoginModule('pwd-login')">返回</n-button> {{ $t('page.login.common.confirm') }}
</n-button>
<n-button size="large" :block="true" :round="true" @click="toLoginModule('pwd-login')">
{{ $t('page.login.common.back') }}
</n-button>
</n-space> </n-space>
</n-form> </n-form>
</template> </template>
@ -25,6 +29,7 @@ import type { FormInst } from 'naive-ui';
import { useRouterPush } from '@/composables'; import { useRouterPush } from '@/composables';
import { useSmsCode } from '@/hooks'; import { useSmsCode } from '@/hooks';
import { formRules } from '@/utils'; import { formRules } from '@/utils';
import { $t } from '@/locales';
const { toLoginModule } = useRouterPush(); const { toLoginModule } = useRouterPush();
const { label, isCounting, loading: smsLoading, getSmsCode } = useSmsCode(); const { label, isCounting, loading: smsLoading, getSmsCode } = useSmsCode();
@ -48,7 +53,7 @@ function handleSmsCode() {
async function handleSubmit() { async function handleSubmit() {
await formRef.value?.validate(); await formRef.value?.validate();
window.$message?.success('验证成功!'); window.$message?.success($t('page.login.common.validateSuccess'));
} }
</script> </script>

View File

@ -1,11 +1,11 @@
<template> <template>
<n-form ref="formRef" :model="model" :rules="rules" size="large" :show-label="false"> <n-form ref="formRef" :model="model" :rules="rules" size="large" :show-label="false">
<n-form-item path="phone"> <n-form-item path="phone">
<n-input v-model:value="model.phone" placeholder="手机号码" /> <n-input v-model:value="model.phone" :placeholder="$t('page.login.common.phonePlaceholder')" />
</n-form-item> </n-form-item>
<n-form-item path="code"> <n-form-item path="code">
<div class="flex-y-center w-full"> <div class="flex-y-center w-full">
<n-input v-model:value="model.code" placeholder="验证码" /> <n-input v-model:value="model.code" :placeholder="$t('page.login.common.codePlaceholder')" />
<div class="w-18px"></div> <div class="w-18px"></div>
<n-button size="large" :disabled="isCounting" :loading="smsLoading" @click="handleSmsCode"> <n-button size="large" :disabled="isCounting" :loading="smsLoading" @click="handleSmsCode">
{{ label }} {{ label }}
@ -13,7 +13,7 @@
</div> </div>
</n-form-item> </n-form-item>
<n-form-item path="imgCode"> <n-form-item path="imgCode">
<n-input v-model:value="model.imgCode" placeholder="验证码,点击图片刷新" /> <n-input v-model:value="model.imgCode" :placeholder="$t('page.login.codeLogin.imageCodePlaceholder')" />
<div class="pl-8px"> <div class="pl-8px">
<image-verify v-model:code="imgCode" /> <image-verify v-model:code="imgCode" />
</div> </div>
@ -27,9 +27,11 @@
:loading="auth.loginLoading" :loading="auth.loginLoading"
@click="handleSubmit" @click="handleSubmit"
> >
确定 {{ $t('page.login.common.confirm') }}
</n-button>
<n-button size="large" :block="true" :round="true" @click="toLoginModule('pwd-login')">
{{ $t('page.login.common.back') }}
</n-button> </n-button>
<n-button size="large" :block="true" :round="true" @click="toLoginModule('pwd-login')">返回</n-button>
</n-space> </n-space>
</n-form> </n-form>
</template> </template>
@ -41,6 +43,7 @@ import { useAuthStore } from '@/store';
import { useRouterPush } from '@/composables'; import { useRouterPush } from '@/composables';
import { useSmsCode } from '@/hooks'; import { useSmsCode } from '@/hooks';
import { formRules, getImgCodeRule } from '@/utils'; import { formRules, getImgCodeRule } from '@/utils';
import { $t } from '@/locales';
const auth = useAuthStore(); const auth = useAuthStore();
const { toLoginModule } = useRouterPush(); const { toLoginModule } = useRouterPush();
@ -68,7 +71,7 @@ function handleSmsCode() {
async function handleSubmit() { async function handleSubmit() {
await formRef.value?.validate(); await formRef.value?.validate();
window.$message?.success('验证成功!'); window.$message?.success($t('page.login.common.validateSuccess'));
} }
</script> </script>

View File

@ -1,6 +1,6 @@
<template> <template>
<n-space :vertical="true"> <n-space :vertical="true">
<n-divider class="!mb-0 text-14px text-#666">其他账户登录</n-divider> <n-divider class="!mb-0 text-14px text-#666">{{ $t('page.login.pwdLogin.otherAccountLogin') }}</n-divider>
<n-space justify="center"> <n-space justify="center">
<n-button <n-button
v-for="item in accounts" v-for="item in accounts"
@ -15,25 +15,38 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { userRoleLabels } from '@/constants';
import { $t } from '@/locales';
interface Emits { interface Emits {
(e: 'login', param: { userName: string; password: string }): void; (e: 'login', param: { userName: string; password: string }): void;
} }
const emit = defineEmits<Emits>(); const emit = defineEmits<Emits>();
const accounts = [ interface Account {
key: Auth.RoleType;
label: string;
userName: string;
password: string;
}
const accounts: Account[] = [
{ {
label: '超级管理员', key: 'super',
label: userRoleLabels.super,
userName: 'Super', userName: 'Super',
password: 'super123' password: 'super123'
}, },
{ {
label: '管理员', key: 'admin',
label: userRoleLabels.admin,
userName: 'Admin', userName: 'Admin',
password: 'admin123' password: 'admin123'
}, },
{ {
label: '普通用户', key: 'user',
label: userRoleLabels.user,
userName: 'User01', userName: 'User01',
password: 'user01123' password: 'user01123'
} }

View File

@ -1,6 +1,6 @@
<template> <template>
<n-space :vertical="true"> <n-space :vertical="true">
<n-divider class="!mb-0 text-14px text-#666">其他登录方式</n-divider> <n-divider class="!mb-0 text-14px text-#666">{{ $t('page.login.pwdLogin.otherLoginMode') }}</n-divider>
<div class="flex-center"> <div class="flex-center">
<n-button :text="true"> <n-button :text="true">
<icon-mdi-wechat class="text-22px text-#888 hover:text-#52BF5E" /> <icon-mdi-wechat class="text-22px text-#888 hover:text-#52BF5E" />
@ -9,6 +9,8 @@
</n-space> </n-space>
</template> </template>
<script lang="ts" setup></script> <script lang="ts" setup>
import { $t } from '@/locales';
</script>
<style scoped></style> <style scoped></style>

View File

@ -1,15 +1,22 @@
<template> <template>
<n-form ref="formRef" :model="model" :rules="rules" size="large" :show-label="false"> <n-form ref="formRef" :model="model" :rules="rules" size="large" :show-label="false">
<n-form-item path="userName"> <n-form-item path="userName">
<n-input v-model:value="model.userName" placeholder="请输入用户名" /> <n-input v-model:value="model.userName" :placeholder="$t('page.login.common.userNamePlaceholder')" />
</n-form-item> </n-form-item>
<n-form-item path="password"> <n-form-item path="password">
<n-input v-model:value="model.password" type="password" show-password-on="click" placeholder="请输入密码" /> <n-input
v-model:value="model.password"
type="password"
show-password-on="click"
:placeholder="$t('page.login.common.passwordPlaceholder')"
/>
</n-form-item> </n-form-item>
<n-space :vertical="true" :size="24"> <n-space :vertical="true" :size="24">
<div class="flex-y-center justify-between"> <div class="flex-y-center justify-between">
<n-checkbox v-model:checked="rememberMe">记住我</n-checkbox> <n-checkbox v-model:checked="rememberMe">{{ $t('page.login.pwdLogin.rememberMe') }}</n-checkbox>
<n-button :text="true" @click="toLoginModule('reset-pwd')">忘记密码</n-button> <n-button :text="true" @click="toLoginModule('reset-pwd')">
{{ $t('page.login.pwdLogin.forgetPassword') }}
</n-button>
</div> </div>
<n-button <n-button
type="primary" type="primary"
@ -19,7 +26,7 @@
:loading="auth.loginLoading" :loading="auth.loginLoading"
@click="handleSubmit" @click="handleSubmit"
> >
确定 {{ $t('page.login.common.confirm') }}
</n-button> </n-button>
<div class="flex-y-center justify-between"> <div class="flex-y-center justify-between">
<n-button class="flex-1" :block="true" @click="toLoginModule('code-login')"> <n-button class="flex-1" :block="true" @click="toLoginModule('code-login')">

View File

@ -1,11 +1,11 @@
<template> <template>
<n-form ref="formRef" :model="model" :rules="rules" size="large" :show-label="false"> <n-form ref="formRef" :model="model" :rules="rules" size="large" :show-label="false">
<n-form-item path="phone"> <n-form-item path="phone">
<n-input v-model:value="model.phone" placeholder="手机号码" /> <n-input v-model:value="model.phone" :placeholder="$t('page.login.common.phonePlaceholder')" />
</n-form-item> </n-form-item>
<n-form-item path="code"> <n-form-item path="code">
<div class="flex-y-center w-full"> <div class="flex-y-center w-full">
<n-input v-model:value="model.code" placeholder="验证码" /> <n-input v-model:value="model.code" :placeholder="$t('page.login.common.codePlaceholder')" />
<div class="w-18px"></div> <div class="w-18px"></div>
<n-button size="large" :disabled="isCounting" :loading="smsLoading" @click="handleSmsCode"> <n-button size="large" :disabled="isCounting" :loading="smsLoading" @click="handleSmsCode">
{{ label }} {{ label }}
@ -13,15 +13,29 @@
</div> </div>
</n-form-item> </n-form-item>
<n-form-item path="pwd"> <n-form-item path="pwd">
<n-input v-model:value="model.pwd" type="password" show-password-on="click" placeholder="密码" /> <n-input
v-model:value="model.pwd"
type="password"
show-password-on="click"
:placeholder="$t('page.login.common.passwordPlaceholder')"
/>
</n-form-item> </n-form-item>
<n-form-item path="confirmPwd"> <n-form-item path="confirmPwd">
<n-input v-model:value="model.confirmPwd" type="password" show-password-on="click" placeholder="确认密码" /> <n-input
v-model:value="model.confirmPwd"
type="password"
show-password-on="click"
:placeholder="$t('page.login.common.confirmPasswordPlaceholder')"
/>
</n-form-item> </n-form-item>
<n-space :vertical="true" :size="18"> <n-space :vertical="true" :size="18">
<login-agreement v-model:value="agreement" /> <login-agreement v-model:value="agreement" />
<n-button type="primary" size="large" :block="true" :round="true" @click="handleSubmit">确定</n-button> <n-button type="primary" size="large" :block="true" :round="true" @click="handleSubmit">
<n-button size="large" :block="true" :round="true" @click="toLoginModule('pwd-login')">返回</n-button> {{ $t('page.login.common.confirm') }}
</n-button>
<n-button size="large" :block="true" :round="true" @click="toLoginModule('pwd-login')">
{{ $t('page.login.common.back') }}
</n-button>
</n-space> </n-space>
</n-form> </n-form>
</template> </template>
@ -32,6 +46,7 @@ import type { FormInst, FormRules } from 'naive-ui';
import { useRouterPush } from '@/composables'; import { useRouterPush } from '@/composables';
import { useSmsCode } from '@/hooks'; import { useSmsCode } from '@/hooks';
import { formRules, getConfirmPwdRule } from '@/utils'; import { formRules, getConfirmPwdRule } from '@/utils';
import { $t } from '@/locales';
const { toLoginModule } = useRouterPush(); const { toLoginModule } = useRouterPush();
const { label, isCounting, loading: smsLoading, start } = useSmsCode(); const { label, isCounting, loading: smsLoading, start } = useSmsCode();
@ -60,7 +75,7 @@ function handleSmsCode() {
async function handleSubmit() { async function handleSubmit() {
await formRef.value?.validate(); await formRef.value?.validate();
window.$message?.success('验证成功!'); window.$message?.success($t('page.login.common.validateSuccess'));
} }
</script> </script>

View File

@ -1,11 +1,11 @@
<template> <template>
<n-form ref="formRef" :model="model" :rules="rules" size="large" :show-label="false"> <n-form ref="formRef" :model="model" :rules="rules" size="large" :show-label="false">
<n-form-item path="phone"> <n-form-item path="phone">
<n-input v-model:value="model.phone" placeholder="手机号码" /> <n-input v-model:value="model.phone" :placeholder="$t('page.login.common.phonePlaceholder')" />
</n-form-item> </n-form-item>
<n-form-item path="code"> <n-form-item path="code">
<div class="flex-y-center w-full"> <div class="flex-y-center w-full">
<n-input v-model:value="model.code" placeholder="验证码" /> <n-input v-model:value="model.code" :placeholder="$t('page.login.common.codePlaceholder')" />
<div class="w-18px"></div> <div class="w-18px"></div>
<n-button size="large" :disabled="isCounting" :loading="smsLoading" @click="handleSmsCode"> <n-button size="large" :disabled="isCounting" :loading="smsLoading" @click="handleSmsCode">
{{ label }} {{ label }}
@ -13,14 +13,28 @@
</div> </div>
</n-form-item> </n-form-item>
<n-form-item path="pwd"> <n-form-item path="pwd">
<n-input v-model:value="model.pwd" type="password" show-password-on="click" placeholder="密码" /> <n-input
v-model:value="model.pwd"
type="password"
show-password-on="click"
:placeholder="$t('page.login.common.passwordPlaceholder')"
/>
</n-form-item> </n-form-item>
<n-form-item path="confirmPwd"> <n-form-item path="confirmPwd">
<n-input v-model:value="model.confirmPwd" type="password" show-password-on="click" placeholder="确认密码" /> <n-input
v-model:value="model.confirmPwd"
type="password"
show-password-on="click"
:placeholder="$t('page.login.common.confirmPasswordPlaceholder')"
/>
</n-form-item> </n-form-item>
<n-space :vertical="true" size="large"> <n-space :vertical="true" size="large">
<n-button type="primary" size="large" :block="true" :round="true" @click="handleSubmit">确定</n-button> <n-button type="primary" size="large" :block="true" :round="true" @click="handleSubmit">
<n-button size="large" :block="true" :round="true" @click="toLoginModule('pwd-login')">返回</n-button> {{ $t('page.login.common.confirm') }}
</n-button>
<n-button size="large" :block="true" :round="true" @click="toLoginModule('pwd-login')">
{{ $t('page.login.common.back') }}
</n-button>
</n-space> </n-space>
</n-form> </n-form>
</template> </template>
@ -31,6 +45,7 @@ import type { FormInst, FormRules } from 'naive-ui';
import { useRouterPush } from '@/composables'; import { useRouterPush } from '@/composables';
import { useSmsCode } from '@/hooks'; import { useSmsCode } from '@/hooks';
import { formRules, getConfirmPwdRule } from '@/utils'; import { formRules, getConfirmPwdRule } from '@/utils';
import { $t } from '@/locales';
const { toLoginModule } = useRouterPush(); const { toLoginModule } = useRouterPush();
const { label, isCounting, loading: smsLoading, start } = useSmsCode(); const { label, isCounting, loading: smsLoading, start } = useSmsCode();
@ -57,7 +72,7 @@ function handleSmsCode() {
async function handleSubmit() { async function handleSubmit() {
await formRef.value?.validate(); await formRef.value?.validate();
window.$message?.success('验证成功!'); window.$message?.success($t('page.login.common.validateSuccess'));
} }
</script> </script>

View File

@ -9,7 +9,7 @@
<div class="w-300px sm:w-360px"> <div class="w-300px sm:w-360px">
<header class="flex-y-center justify-between"> <header class="flex-y-center justify-between">
<system-logo class="text-64px text-primary" /> <system-logo class="text-64px text-primary" />
<n-gradient-text type="primary" :size="28">{{ title }}</n-gradient-text> <n-gradient-text type="primary" :size="28">{{ $t('system.title') }}</n-gradient-text>
</header> </header>
<main class="pt-24px"> <main class="pt-24px">
<h3 class="text-18px text-primary font-medium">{{ activeModule.label }}</h3> <h3 class="text-18px text-primary font-medium">{{ activeModule.label }}</h3>
@ -30,8 +30,8 @@ import { computed } from 'vue';
import type { Component } from 'vue'; import type { Component } from 'vue';
import { loginModuleLabels } from '@/constants'; import { loginModuleLabels } from '@/constants';
import { useThemeStore } from '@/store'; import { useThemeStore } from '@/store';
import { useAppInfo } from '@/composables';
import { getColorPalette, mixColor } from '@/utils'; import { getColorPalette, mixColor } from '@/utils';
import { $t } from '@/locales';
import { BindWechat, CodeLogin, LoginBg, PwdLogin, Register, ResetPwd } from './components'; import { BindWechat, CodeLogin, LoginBg, PwdLogin, Register, ResetPwd } from './components';
interface Props { interface Props {
@ -42,7 +42,6 @@ interface Props {
const props = defineProps<Props>(); const props = defineProps<Props>();
const theme = useThemeStore(); const theme = useThemeStore();
const { title } = useAppInfo();
interface LoginModule { interface LoginModule {
key: UnionKey.LoginModule; key: UnionKey.LoginModule;