Compare commits

..

1 Commits

Author SHA1 Message Date
Soybean
92cabdb5d4 chore(projects): release v0.10.3 tauri branch 2023-06-15 19:40:53 +08:00
156 changed files with 8970 additions and 4429 deletions

8
.env
View File

@@ -13,8 +13,8 @@ VITE_AUTH_ROUTE_MODE=static
VITE_ROUTE_HOME_PATH=/dashboard/analysis
# iconify图标作为组件的前缀
VITE_ICON_PREFIX=icon
VITE_ICON_PREFFIX=icon
# 本地SVG图标作为组件的前缀, 请注意一定要包含 VITE_ICON_PREFIX
# 格式 {VITE_ICON_PREFIX}-{本地图标集合名称}
VITE_ICON_LOCAL_PREFIX=icon-local
# 本地SVG图标作为组件的前缀, 请注意一定要包含 VITE_ICON_PREFFIX
# 格式 {VITE_ICON_PREFFIX}-{本地图标集合名称}
VITE_ICON_LOCAL_PREFFIX=icon-local

View File

@@ -1,3 +1,5 @@
!.env-config.ts
components.d.ts
router-page.d.ts
*.svg
src-tauri/target

View File

@@ -10,8 +10,7 @@ module.exports = {
{
files: ['*.vue'],
rules: {
'no-undef': 'off', // use tsc to check the ts code of the vue
'vue/no-setup-props-destructure': 'off' // wait to fix this rule
'no-undef': 'off' // use tsc to check the ts code of the vue
}
}
],

1
.gitignore vendored
View File

@@ -34,4 +34,3 @@ stats.html
/src/typings/components.d.ts
package-lock.json
yarn.lock
pnpm-lock.yaml

View File

@@ -1,19 +1,27 @@
{
"recommendations": [
"afzalsayed96.icones",
"antfu.iconify",
"antfu.unocss",
"christian-kohler.path-intellisense",
"dbaeumer.vscode-eslint",
"eamodio.gitlens",
"editorconfig.editorconfig",
"esbenp.prettier-vscode",
"formulahendry.auto-complete-tag",
"formulahendry.auto-close-tag",
"formulahendry.auto-complete-tag",
"formulahendry.auto-rename-tag",
"kisstkondoros.vscode-gutter-preview",
"lokalise.i18n-ally",
"mariusalchimavicius.json-to-ts",
"mhutchie.git-graph",
"mikestead.dotenv",
"naumovs.color-highlight",
"pkief.material-icon-theme",
"sdras.vue-vscode-snippets",
"streetsidesoftware.code-spell-checker",
"vue.volar",
"vue.vscode-typescript-vue-plugin"
"vue.vscode-typescript-vue-plugin",
"whtouche.vscode-js-console-utils",
"zhuangtongfa.material-theme"
]
}

122
.vscode/settings.json vendored
View File

@@ -1,77 +1,75 @@
{
"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": [
"AMAP",
"antdesign",
"antv",
"apacheecharts",
"areaspline",
"bmapgl",
"colord",
"echarts",
"gitee",
"gridicons",
"iconify",
"jsapi",
"naiveui",
"Popconfirm",
"Posva",
"Shenzhen",
"Sider",
"tauri",
"unocss",
"unplugin",
"vditor",
"VERCEL",
"Vite",
"vitejs",
"vuedraggable",
"vueuse",
"wangeditor",
"wechat",
"xgplayer",
"yanbowe",
"ភាសាខ្មែរ"
],
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
"editor.fontLigatures": true,
"editor.formatOnSave": false,
"editor.guides.bracketPairs": "active",
"editor.quickSuggestions": {
"strings": true
},
"editor.tabSize": 2,
"eslint.validate": ["json"],
"eslint.validate": ["javascript", "javascriptreact", "typescript", "typescriptreact", "vue", "json"],
"files.associations": {
"*.env.*": "dotenv",
"*.svg": "html"
"*.env.*": "dotenv"
},
"files.eol": "\n",
"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]": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true
"git.enableSmartCommit": true,
"gutterpreview.paths": {
"@": "/src",
"~@": "/src"
},
"prettier": {}
"material-icon-theme.activeIconPack": "angular",
"material-icon-theme.files.associations": {},
"material-icon-theme.folders.associations": {
"src-tauri": "src",
"enum": "typescript",
"enums": "typescript",
"store": "context",
"stores": "context",
"composable": "hook",
"composables": "hook",
"directive": "tools",
"directives": "tools",
"business": "core",
"request": "api",
"adapter": "middleware"
},
"path-intellisense.mappings": {
"@": "${workspaceFolder}/src",
"~@": "${workspaceFolder}/src"
},
"terminal.integrated.fontSize": 14,
"terminal.integrated.fontWeight": 500,
"terminal.integrated.tabs.enabled": true,
"workbench.iconTheme": "material-icon-theme",
"workbench.colorTheme": "One Dark Pro",
"[html]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[json]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[jsonc]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[javascriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[markdown]": {
"editor.defaultFormatter": "yzhang.markdown-all-in-one"
},
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[vue]": {
"editor.defaultFormatter": "Vue.volar"
},
"i18n-ally.localesPaths": ["src/locales", "src/locales/lang"]
}

View File

@@ -1,86 +1,6 @@
# Changelog
## [v0.10.4](https://github.com/honghuangdc/soybean-admin/compare/v0.10.3...v0.10.4) (23-09-20)
###    🚀 Features
- **auth**:
- 防止多次刷新token &nbsp;-&nbsp; by @eAliwei [<samp>(0eaa3)</samp>](https://github.com/honghuangdc/soybean-admin/commit/0eaa327)
- **hooks**:
- add useHookTable &nbsp;-&nbsp; by @honghuangdc [<samp>(b3ae7)</samp>](https://github.com/honghuangdc/soybean-admin/commit/b3ae760)
- **projects**:
- add websocket demo &nbsp;-&nbsp; by @honghuangdc [<samp>(af53e)</samp>](https://github.com/honghuangdc/soybean-admin/commit/af53ec7)
- add switch for customize darkmode transition &nbsp;-&nbsp; by @honghuangdc [<samp>(6e0cc)</samp>](https://github.com/honghuangdc/soybean-admin/commit/6e0cce4)
- new i18n function $t & login page and setting drawer config i18n &nbsp;-&nbsp; by @honghuangdc [<samp>(854d0)</samp>](https://github.com/honghuangdc/soybean-admin/commit/854d0bc)
- add plugin-web-update-notification &nbsp;-&nbsp; by @honghuangdc [<samp>(c9164)</samp>](https://github.com/honghuangdc/soybean-admin/commit/c91644b)
### &nbsp;&nbsp;&nbsp;🐞 Bug Fixes
- **components**:
- 修复动态路由主页404 &nbsp;-&nbsp; by @lapislazulisch [<samp>(3ae19)</samp>](https://github.com/honghuangdc/soybean-admin/commit/3ae1952)
- 修复动态路由home页404 &nbsp;-&nbsp; by @lapislazulisch [<samp>(ad6ac)</samp>](https://github.com/honghuangdc/soybean-admin/commit/ad6ac72)
- **projects**:
- fix set tab title (fixed #256) &nbsp;-&nbsp; by @honghuangdc in https://github.com/honghuangdc/soybean-admin/issues/256 [<samp>(13f6c)</samp>](https://github.com/honghuangdc/soybean-admin/commit/13f6cd8)
- correct the lang file name & add recommend vscode plugin i18n-ally &nbsp;-&nbsp; by @honghuangdc [<samp>(864ec)</samp>](https://github.com/honghuangdc/soybean-admin/commit/864ec47)
- fix reload button animate &nbsp;-&nbsp; by @honghuangdc [<samp>(41f23)</samp>](https://github.com/honghuangdc/soybean-admin/commit/41f2338)
- **styles**:
- 用户管理页面布局自适应屏幕高度 (fixed #253) &nbsp;-&nbsp; by @honghuangdc in https://github.com/honghuangdc/soybean-admin/issues/253 [<samp>(0f7b9)</samp>](https://github.com/honghuangdc/soybean-admin/commit/0f7b9d5)
### &nbsp;&nbsp;&nbsp;🔥 Performance
- **hooks**:
- perf use-table &nbsp;-&nbsp; by @honghuangdc [<samp>(33180)</samp>](https://github.com/honghuangdc/soybean-admin/commit/3318041)
- perf useHookTable &nbsp;-&nbsp; by @honghuangdc [<samp>(809fa)</samp>](https://github.com/honghuangdc/soybean-admin/commit/809fa85)
- **projects**:
- add type declaration for document startViewTransition &nbsp;-&nbsp; by @honghuangdc [<samp>(d3ebe)</samp>](https://github.com/honghuangdc/soybean-admin/commit/d3ebe95)
### &nbsp;&nbsp;&nbsp;💅 Refactors
- **projects**:
- 生产环境缓存主题变更为sessionStorage &nbsp;-&nbsp; by @honghuangdc [<samp>(c46a5)</samp>](https://github.com/honghuangdc/soybean-admin/commit/c46a592)
- add reCacheRoute method &nbsp;-&nbsp; by @honghuangdc [<samp>(f92ee)</samp>](https://github.com/honghuangdc/soybean-admin/commit/f92ee77)
- update soybean domain &nbsp;-&nbsp; by @honghuangdc [<samp>(073fd)</samp>](https://github.com/honghuangdc/soybean-admin/commit/073fd16)
### &nbsp;&nbsp;&nbsp;📖 Documentation
- **projects**:
- update README.md logo &nbsp;-&nbsp; by @honghuangdc [<samp>(19141)</samp>](https://github.com/honghuangdc/soybean-admin/commit/19141a7)
- update Docker deployment method &nbsp;-&nbsp; by @snowords [<samp>(00da0)</samp>](https://github.com/honghuangdc/soybean-admin/commit/00da000)
- update git hooks init command &nbsp;-&nbsp; by @snowords [<samp>(7f35e)</samp>](https://github.com/honghuangdc/soybean-admin/commit/7f35e87)
- update README.md &nbsp;-&nbsp; by @eltociear [<samp>(93ed5)</samp>](https://github.com/honghuangdc/soybean-admin/commit/93ed5ad)
### &nbsp;&nbsp;&nbsp;🏡 Chore
- **deps**:
- update deps &nbsp;-&nbsp; by @honghuangdc [<samp>(bba68)</samp>](https://github.com/honghuangdc/soybean-admin/commit/bba68bf)
- update deps &nbsp;-&nbsp; by @honghuangdc [<samp>(0e6d2)</samp>](https://github.com/honghuangdc/soybean-admin/commit/0e6d289)
- update deps &nbsp;-&nbsp; by @honghuangdc [<samp>(135ce)</samp>](https://github.com/honghuangdc/soybean-admin/commit/135ce77)
- update deps &nbsp;-&nbsp; by @honghuangdc [<samp>(44ba3)</samp>](https://github.com/honghuangdc/soybean-admin/commit/44ba327)
- update deps &nbsp;-&nbsp; by @honghuangdc [<samp>(9296e)</samp>](https://github.com/honghuangdc/soybean-admin/commit/9296e69)
- update deps &nbsp;-&nbsp; by @honghuangdc [<samp>(751de)</samp>](https://github.com/honghuangdc/soybean-admin/commit/751ded4)
- update deps &nbsp;-&nbsp; by @honghuangdc [<samp>(305d9)</samp>](https://github.com/honghuangdc/soybean-admin/commit/305d956)
- **projects**:
- update deps and fix swiper &nbsp;-&nbsp; by @honghuangdc [<samp>(9d105)</samp>](https://github.com/honghuangdc/soybean-admin/commit/9d1051b)
- update package.json &nbsp;-&nbsp; by @honghuangdc [<samp>(d7aea)</samp>](https://github.com/honghuangdc/soybean-admin/commit/d7aea9d)
- update deps & fix eslint code &nbsp;-&nbsp; by @honghuangdc [<samp>(08e0c)</samp>](https://github.com/honghuangdc/soybean-admin/commit/08e0cf5)
- update pnpm-lock.yaml &nbsp;-&nbsp; by @honghuangdc [<samp>(94644)</samp>](https://github.com/honghuangdc/soybean-admin/commit/9464473)
- update VSCode setting &nbsp;-&nbsp; by @honghuangdc [<samp>(56c77)</samp>](https://github.com/honghuangdc/soybean-admin/commit/56c770c)
- correct the word spell &nbsp;-&nbsp; by @honghuangdc [<samp>(458e3)</samp>](https://github.com/honghuangdc/soybean-admin/commit/458e387)
- correct word spell & eslint fix code &nbsp;-&nbsp; by @honghuangdc [<samp>(cffc3)</samp>](https://github.com/honghuangdc/soybean-admin/commit/cffc30a)
- When tab is switched, keep the page without refreshing &nbsp;-&nbsp; by @linjiangl [<samp>(83f25)</samp>](https://github.com/honghuangdc/soybean-admin/commit/83f2514)
### &nbsp;&nbsp;&nbsp;🎨 Styles
- **projects**:
- unify card border radius, 16px to 8px &nbsp;-&nbsp; by @honghuangdc [<samp>(cbda4)</samp>](https://github.com/honghuangdc/soybean-admin/commit/cbda4a3)
- update default theme color &nbsp;-&nbsp; by @honghuangdc [<samp>(43ac2)</samp>](https://github.com/honghuangdc/soybean-admin/commit/43ac23f)
- prettier format code &nbsp;-&nbsp; by @honghuangdc [<samp>(24cf1)</samp>](https://github.com/honghuangdc/soybean-admin/commit/24cf1d9)
### &nbsp;&nbsp;&nbsp;❤️ Contributors
[![honghuangdc](https://github.com/honghuangdc.png?size=48)](https://github.com/honghuangdc)&nbsp;&nbsp;[![eltociear](https://github.com/eltociear.png?size=48)](https://github.com/eltociear)&nbsp;&nbsp;[![linjiangl](https://github.com/linjiangl.png?size=48)](https://github.com/linjiangl)&nbsp;&nbsp;[![lapislazulisch](https://github.com/lapislazulisch.png?size=48)](https://github.com/lapislazulisch)&nbsp;&nbsp;[![snowords](https://github.com/snowords.png?size=48)](https://github.com/snowords)&nbsp;&nbsp;[![eAliwei](https://github.com/eAliwei.png?size=48)](https://github.com/eAliwei)&nbsp;&nbsp;[![honghuangdc](https://github.com/honghuangdc.png?size=48)](https://github.com/honghuangdc)&nbsp;&nbsp;
## [v0.10.3](https://github.com/honghuangdc/soybean-admin/compare/v0.10.2...v0.10.3) (23-06-15)
### &nbsp;&nbsp;&nbsp;🐞 Bug Fixes

View File

@@ -1,29 +1,10 @@
<div align="center">
<img src="./public/favicon.svg" style="width: 160px;"/>
<img src="https://soybeanjs-1300612522.cos.ap-guangzhou.myqcloud.com/uPic/soybean.svg" style="width: 160px;"/>
<h1>Soybean Admin</h1>
</div>
[![license](https://img.shields.io/badge/license-MIT-green.svg)](./LICENSE) ![](https://img.shields.io/github/stars/honghuangdc/soybean-admin) ![](https://img.shields.io/github/forks/honghuangdc/soybean-admin)
## 注意 SoybeanAdmin 正在重构,全新 1.0 即将发布
Soybean Admin v1.0 :
- [x] 采用基于 pnpm 的 monorepo 管理项目
- [x] 第三方 soybeanjs 的工具库直接抽离到项目中(ElegantRouter除外),不再作为依赖
- [x] 采用全新的路由插件 ElegantRouter
- [x] 使用基于 ApiFox 的远程 mock 代替本地 mock
- [x] 基于现有路由插件迁移至新路由插件的指南
- [x] 代码实现遵循 SoybeanJS 的代码规范
- [ ] 项目的 main 分支保留系统核心部分,示例页面和无关核心的插件移至 example 分支
- [ ] 完整 1.0 版本的文档
1.0 源代码:[v1.0-beta](https://github.com/honghuangdc/soybean-admin/tree/v1.0-beta)
> 同时推出开源的 [AntDesignVue 版本](https://github.com/soybeanjs/soybean-admin-antd) 和 ElementPlus 版本
> 新开项目建议直接使用 [v1.0-beta](https://github.com/honghuangdc/soybean-admin/tree/v1.0-beta) 或 [AntDesignVue 版本](https://github.com/soybeanjs/soybean-admin-antd)
## 简介
[Soybean Admin](https://github.com/honghuangdc/soybean-admin) 是一个基于 Vue3、Vite3、TypeScript、NaiveUI、Pinia 和 UnoCSS 的清新优雅的中后台模版,它使用了最新流行的前端技术栈,内置丰富的主题配置,有着极高的代码规范,基于文件的路由系统以及基于 Mock 的动态权限路由,开箱即用的中后台前端解决方案,也可用于学习参考。
@@ -53,17 +34,17 @@ Soybean Admin v1.0 :
## 在线预览
- [Soybean Admin 预览地址](https://admin.soybeanjs.cn/)
- [Soybean Admin 预览地址](https://soybean.pro/)
## 文档
- [项目文档预览地址](https://admin-docs.soybeanjs.cn/)
- [项目文档预览地址](https://docs.soybean.pro)
## 代码仓库
| 仓库 | GitHub 地址 | gitee 镜像 | 预览 |
| 仓库 | github 地址 | gitee 镜像 | 预览 |
| -------------- | ----------------------------------------------------------------------------- | ---------------------------------------------------------------------------- | --------------------------------------------------------- |
| soybean-admin | [GitHub](https://github.com/honghuangdc/soybean-admin) | [gitee](https://gitee.com/honghuangdc/soybean-admin) | [预览](https://admin.soybeanjs.cn/) |
| soybean-admin | [github](https://github.com/honghuangdc/soybean-admin) | [gitee](https://gitee.com/honghuangdc/soybean-admin) | [预览](https://soybean.pro/) |
| tauri 版 | [tauri 版](https://github.com/honghuangdc/soybean-admin/tree/tauri) | [tauri 版](https://gitee.com/honghuangdc/soybean-admin/tree/tauri) | |
| 精简版 | [精简版](https://github.com/honghuangdc/soybean-admin/tree/thin) | [精简版](https://gitee.com/honghuangdc/soybean-admin/tree/thin) | |
| 集成 fast-crud | [集成 fast-crud](https://github.com/honghuangdc/soybean-admin/tree/fast-crud) | [集成 fast-crud](https://gitee.com/honghuangdc/soybean-admin/tree/fast-crud) | [预览](http://fast-crud.docmirror.cn/soybean/#/crud/demo) |
@@ -142,8 +123,7 @@ pnpm build
- Docker 部署 Soybean
```bash
docker build -t soybean-admin-image -f docker/Dockerfile .
docker run -d -p 80:80 soybean-admin-image
docker run --name soybean -p 80:80 -d soybeanjs/soybean-admin:v0.9.6
```
- 访问 SoybeanAdmin
@@ -158,7 +138,7 @@ docker run -d -p 80:80 soybean-admin-image
项目已经内置 Angular 提交规范,直接执行 commit 命令即可生成符合 Angular 提交规范的 commit。
项目已用 simple-git-hooks 代替了 husky, 旧版本用了 husky执行 pnpm soy init-simple-git-hooks 进行初始化配置
项目已用 simple-git-hooks 代替了 husky, 旧版本用了 husky执行 pnpm soy init-git-hooks 进行初始化配置
## 浏览器支持
@@ -184,7 +164,7 @@ docker run -d -p 80:80 soybean-admin-image
<img src="https://i.loli.net/2021/11/24/1J6REWXiHomU2kM.jpg" style="width:200px" />
</div>
<div>
<p>添加本人微信,欢迎来业务咨询(技术交流请加QQ群)</p>
<p>添加本人微信,欢迎来技术交流,业务咨询</p>
<img src="https://s2.loli.net/2023/06/07/sVyCUFBvzQ9f5b7.jpg" style="width:200px" />
</div>
</div>

View File

@@ -7,13 +7,13 @@ import { createSvgIconsPlugin } from 'vite-plugin-svg-icons';
import { getSrcPath } from '../utils';
export default function unplugin(viteEnv: ImportMetaEnv) {
const { VITE_ICON_PREFIX, VITE_ICON_LOCAL_PREFIX } = viteEnv;
const { VITE_ICON_PREFFIX, VITE_ICON_LOCAL_PREFFIX } = viteEnv;
const srcPath = getSrcPath();
const localIconPath = `${srcPath}/assets/svg-icon`;
/** 本地svg图标集合名称 */
const collectionName = VITE_ICON_LOCAL_PREFIX.replace(`${VITE_ICON_PREFIX}-`, '');
const collectionName = VITE_ICON_LOCAL_PREFFIX.replace(`${VITE_ICON_PREFFIX}-`, '');
return [
Icons({
@@ -31,12 +31,12 @@ export default function unplugin(viteEnv: ImportMetaEnv) {
types: [{ from: 'vue-router', names: ['RouterLink', 'RouterView'] }],
resolvers: [
NaiveUiResolver(),
IconsResolver({ customCollections: [collectionName], componentPrefix: VITE_ICON_PREFIX })
IconsResolver({ customCollections: [collectionName], componentPrefix: VITE_ICON_PREFFIX })
]
}),
createSvgIconsPlugin({
iconDirs: [localIconPath],
symbolId: `${VITE_ICON_LOCAL_PREFIX}-[dir]-[name]`,
symbolId: `${VITE_ICON_LOCAL_PREFFIX}-[dir]-[name]`,
inject: 'body-last',
customDomId: '__SVG_ICON_LOCAL__'
})

View File

@@ -1,4 +1,3 @@
<!-- prettier-ignore -->
<!DOCTYPE html>
<html lang="zh-cmn-Hans">
<head>

View File

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

View File

@@ -1,11 +1,11 @@
{
"name": "soybean-admin",
"version": "0.10.4",
"version": "0.10.3",
"description": "A fresh and elegant admin template, based on Vue3、Vite3、TypeScript、NaiveUI and UnoCSS. 一个基于Vue3、Vite3、TypeScript、NaiveUI and UnoCSS的清新优雅的中后台模版。",
"author": {
"name": "Soybean",
"email": "soybeanjs@outlook.com",
"url": "https://github.com/soybeanjs"
"email": "honghuangdc@gmail.com",
"url": "https://github.com/honghuangdc"
},
"license": "MIT",
"homepage": "https://github.com/honghuangdc/soybean-admin",
@@ -38,10 +38,13 @@
"dev": "cross-env VITE_SERVICE_ENV=dev vite",
"dev:test": "cross-env VITE_SERVICE_ENV=test vite",
"dev:prod": "cross-env VITE_SERVICE_ENV=prod vite",
"dev:tauri": "pnpm tauri dev",
"build": "npm run typecheck && cross-env VITE_SERVICE_ENV=prod vite build",
"build:dev": "npm run typecheck && cross-env VITE_SERVICE_ENV=dev vite build",
"build:test": "npm run typecheck && cross-env VITE_SERVICE_ENV=test vite build",
"build:vercel": "cross-env VITE_HASH_ROUTE=Y VITE_VERCEL=Y vite build",
"build:tauri": "pnpm tauri build",
"tauri-icon": "pnpm tauri icon ./public/logo.png",
"preview": "vite preview",
"typecheck": "vue-tsc --noEmit --skipLibCheck",
"lint": "eslint . --fix",
@@ -59,65 +62,65 @@
"@antv/g2": "4.2.10",
"@better-scroll/core": "2.5.1",
"@soybeanjs/vue-materials": "0.2.0",
"@vueuse/core": "10.5.0",
"axios": "1.5.1",
"@vueuse/core": "10.1.2",
"axios": "1.4.0",
"clipboard": "2.0.11",
"colord": "2.9.3",
"crypto-js": "4.1.1",
"dayjs": "1.11.10",
"echarts": "5.4.3",
"dayjs": "1.11.8",
"echarts": "5.4.2",
"form-data": "4.0.0",
"lodash-es": "4.17.21",
"naive-ui": "2.35.0",
"pinia": "2.1.6",
"naive-ui": "2.34.4",
"pinia": "2.1.4",
"print-js": "1.6.0",
"qs": "6.11.2",
"socket.io-client": "4.7.2",
"swiper": "10.3.1",
"ua-parser-js": "1.0.36",
"vditor": "3.9.6",
"swiper": "9.4.1",
"ua-parser-js": "1.0.35",
"vditor": "3.9.3",
"vue": "3.3.4",
"vue-i18n": "9.5.0",
"vue-router": "4.2.5",
"vue-i18n": "9.2.2",
"vue-router": "4.2.2",
"vuedraggable": "4.1.0",
"wangeditor": "4.7.15",
"xgplayer": "3.0.9"
"xgplayer": "3.0.4"
},
"devDependencies": {
"@amap/amap-jsapi-types": "0.0.13",
"@iconify/json": "2.2.128",
"@iconify/json": "2.2.78",
"@iconify/vue": "4.1.1",
"@soybeanjs/cli": "0.7.4",
"@soybeanjs/vite-plugin-vue-page-route": "0.0.10",
"@soybeanjs/cli": "0.6.2",
"@soybeanjs/vite-plugin-vue-page-route": "0.0.5",
"@tauri-apps/cli": "^1.3.1",
"@types/bmapgl": "0.0.7",
"@types/crypto-js": "4.1.2",
"@types/node": "20.8.4",
"@types/qs": "6.9.8",
"@types/ua-parser-js": "0.7.37",
"@unocss/preset-uno": "0.56.5",
"@unocss/transformer-directives": "0.56.5",
"@unocss/vite": "0.56.5",
"@vitejs/plugin-vue": "4.4.0",
"@vitejs/plugin-vue-jsx": "3.0.2",
"@types/crypto-js": "4.1.1",
"@types/node": "20.3.1",
"@types/qs": "6.9.7",
"@types/ua-parser-js": "0.7.36",
"@unocss/preset-uno": "0.53.1",
"@unocss/transformer-directives": "0.53.1",
"@unocss/vite": "0.53.1",
"@vitejs/plugin-vue": "4.2.3",
"@vitejs/plugin-vue-jsx": "3.0.1",
"cross-env": "7.0.3",
"eslint": "8.51.0",
"eslint-config-soybeanjs": "0.5.7",
"eslint": "8.42.0",
"eslint-config-soybeanjs": "0.4.9",
"mockjs": "1.1.0",
"rollup-plugin-visualizer": "5.9.2",
"sass": "1.69.3",
"simple-git-hooks": "2.9.0",
"tsx": "3.13.0",
"typescript": "5.2.2",
"unplugin-icons": "0.17.0",
"unplugin-vue-components": "0.25.2",
"vite": "4.4.11",
"sass": "1.63.4",
"simple-git-hooks": "2.8.1",
"tsx": "3.12.7",
"typescript": "5.1.3",
"unplugin-icons": "0.16.3",
"unplugin-vue-components": "0.25.1",
"vite": "4.3.9",
"vite-plugin-compression": "0.5.1",
"vite-plugin-mock": "2.9.8",
"vite-plugin-progress": "0.0.7",
"vite-plugin-pwa": "0.16.5",
"vite-plugin-pwa": "0.16.4",
"vite-plugin-svg-icons": "2.0.1",
"vite-plugin-vue-devtools": "1.0.0-rc.5",
"vue-tsc": "1.8.19"
"vite-plugin-vue-devtools": "0.2.0",
"vue-tsc": "1.6.5"
},
"pnpm": {
"patchedDependencies": {
@@ -126,7 +129,7 @@
},
"simple-git-hooks": {
"commit-msg": "pnpm soy git-commit-verify",
"pre-commit": "pnpm typecheck && pnpm soy lint-staged"
"pre-commit": "pnpm typecheck && pnpm lint"
},
"soybean": {
"useSoybeanToken": true

5932
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -1 +1 @@
<svg viewBox="0 0 160 160" xmlns="http://www.w3.org/2000/svg"><path d="M81.28 55.9c-.1-11.67-2.93-22.55-9.37-32.38-1-1.5-2.14-2.86-2.5-4.71a8.1 8.1 0 014-8.61 7.89 7.89 0 019.3 1.23 35.999 35.999 0 015.9 8.83 75.18 75.18 0 018.44 28.58 83.211 83.211 0 01-5.23 36.74 102.983 102.983 0 01-3 7.28 1.2 1.2 0 000 1.41c9.58 13.3 21.76 23 37.85 27.24a54.37 54.37 0 0019.68 1.57 7.72 7.72 0 018.36 6.9 7.903 7.903 0 01-6.7 9 64.744 64.744 0 01-23-1.33 77.68 77.68 0 01-36.93-19.88 93.628 93.628 0 01-11.91-13.71 2.18 2.18 0 00-2.3-1.06 72.744 72.744 0 00-27.38 7.55c-11.6 6-20.67 14.58-26.4 26.45a10.134 10.134 0 01-3.7 4.7 8 8 0 01-9.19-.7 7.86 7.86 0 01-2.36-9.28 60.324 60.324 0 018.72-14.52c12.2-15.43 28.21-24.59 47.32-28.57A85.085 85.085 0 0173.07 87c.524.015 1-.307 1.18-.8a76.06 76.06 0 006.53-22.3c.351-2.652.518-5.325.5-8z" fill="#646cff"/><path d="M136.26 108.34a44.742 44.742 0 01-11.13-2.87 46.108 46.108 0 01-19.66-13.76 8 8 0 015.72-13.22 7.93 7.93 0 016.54 2.93 33.27 33.27 0 0018.87 10.75c1.546.155 3.058.553 4.48 1.18a8.08 8.08 0 013.84 9.21c-.92 3.52-4.13 5.81-8.66 5.78zm-80.6-75.02a7.61 7.61 0 016.64 5 49.139 49.139 0 013.64 17 46.33 46.33 0 01-2.46 17.28c-2 5.77-8.24 7.79-12.89 4.15a8.1 8.1 0 01-2.39-9 31.679 31.679 0 001.68-12.36 35.77 35.77 0 00-2.43-11c-2.1-5.45 1.75-11.07 8.21-11.07zm22.26 93.25a8 8 0 01-6.68 7.86 32.88 32.88 0 00-19.7 12.19 8.13 8.13 0 01-11.21 1.62 8 8 0 01-1.41-11.58A51.043 51.043 0 0154 123.81a45.842 45.842 0 0114-5.1c5.35-1.04 9.91 2.56 9.92 7.86z" fill="#646cff"/></svg>
<svg viewBox="0 0 160 160" xmlns="http://www.w3.org/2000/svg"><path d="M81.28 55.9c-.1-11.67-2.93-22.55-9.37-32.38-1-1.5-2.14-2.86-2.5-4.71a8.1 8.1 0 014-8.61 7.89 7.89 0 019.3 1.23 35.999 35.999 0 015.9 8.83 75.18 75.18 0 018.44 28.58 83.211 83.211 0 01-5.23 36.74 102.983 102.983 0 01-3 7.28 1.2 1.2 0 000 1.41c9.58 13.3 21.76 23 37.85 27.24a54.37 54.37 0 0019.68 1.57 7.72 7.72 0 018.36 6.9 7.903 7.903 0 01-6.7 9 64.744 64.744 0 01-23-1.33 77.68 77.68 0 01-36.93-19.88 93.628 93.628 0 01-11.91-13.71 2.18 2.18 0 00-2.3-1.06 72.744 72.744 0 00-27.38 7.55c-11.6 6-20.67 14.58-26.4 26.45a10.134 10.134 0 01-3.7 4.7 8 8 0 01-9.19-.7 7.86 7.86 0 01-2.36-9.28 60.324 60.324 0 018.72-14.52c12.2-15.43 28.21-24.59 47.32-28.57A85.085 85.085 0 0173.07 87c.524.015 1-.307 1.18-.8a76.06 76.06 0 006.53-22.3c.351-2.652.518-5.325.5-8z" fill="#1890ff"/><path d="M136.26 108.34a44.742 44.742 0 01-11.13-2.87 46.108 46.108 0 01-19.66-13.76 8 8 0 015.72-13.22 7.93 7.93 0 016.54 2.93 33.27 33.27 0 0018.87 10.75c1.546.155 3.058.553 4.48 1.18a8.08 8.08 0 013.84 9.21c-.92 3.52-4.13 5.81-8.66 5.78zm-80.6-75.02a7.61 7.61 0 016.64 5 49.139 49.139 0 013.64 17 46.33 46.33 0 01-2.46 17.28c-2 5.77-8.24 7.79-12.89 4.15a8.1 8.1 0 01-2.39-9 31.679 31.679 0 001.68-12.36 35.77 35.77 0 00-2.43-11c-2.1-5.45 1.75-11.07 8.21-11.07zm22.26 93.25a8 8 0 01-6.68 7.86 32.88 32.88 0 00-19.7 12.19 8.13 8.13 0 01-11.21 1.62 8 8 0 01-1.41-11.58A51.043 51.043 0 0154 123.81a45.842 45.842 0 0114-5.1c5.35-1.04 9.91 2.56 9.92 7.86z" fill="#1890ff"/></svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

3
src-tauri/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
# Generated by Cargo
# will have compiled files and executables
/target/

4302
src-tauri/Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

28
src-tauri/Cargo.toml Normal file
View File

@@ -0,0 +1,28 @@
[package]
name = "app"
version = "0.1.0"
description = "A Tauri App"
authors = ["you"]
license = ""
repository = ""
default-run = "app"
edition = "2021"
rust-version = "1.57"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[build-dependencies]
tauri-build = { version = "1.1.1", features = [] }
[dependencies]
serde_json = "1.0"
serde = { version = "1.0", features = ["derive"] }
tauri = { version = "1.1.1", features = ["api-all"] }
[features]
# by default Tauri runs in production mode
# when `tauri dev` runs it is executed with `cargo run --no-default-features` if `devPath` is an URL
default = [ "custom-protocol" ]
# this feature is used for production builds where `devPath` points to the filesystem
# DO NOT remove this
custom-protocol = [ "tauri/custom-protocol" ]

3
src-tauri/build.rs Normal file
View File

@@ -0,0 +1,3 @@
fn main() {
tauri_build::build()
}

BIN
src-tauri/icons/128x128.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

BIN
src-tauri/icons/32x32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

BIN
src-tauri/icons/icon.icns Normal file

Binary file not shown.

BIN
src-tauri/icons/icon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

BIN
src-tauri/icons/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

10
src-tauri/src/main.rs Normal file
View File

@@ -0,0 +1,10 @@
#![cfg_attr(
all(not(debug_assertions), target_os = "windows"),
windows_subsystem = "windows"
)]
fn main() {
tauri::Builder::default()
.run(tauri::generate_context!())
.expect("error while running tauri application");
}

60
src-tauri/tauri.conf.json Normal file
View File

@@ -0,0 +1,60 @@
{
"$schema": "../node_modules/@tauri-apps/cli/schema.json",
"build": {
"beforeBuildCommand": "npm run build",
"beforeDevCommand": "npm run dev",
"devPath": "http://localhost:3200",
"distDir": "../dist"
},
"package": {
"productName": "soybean-admin",
"version": "0.1.0"
},
"tauri": {
"allowlist": {
"all": true
},
"bundle": {
"active": true,
"category": "DeveloperTool",
"copyright": "",
"deb": {
"depends": []
},
"externalBin": [],
"icon": ["icons/32x32.png", "icons/128x128.png", "icons/128x128@2x.png", "icons/icon.icns", "icons/icon.ico"],
"identifier": "cn.soybeanjs.tauri-admin",
"longDescription": "",
"macOS": {
"entitlements": null,
"exceptionDomain": "",
"frameworks": [],
"providerShortName": null,
"signingIdentity": null
},
"resources": [],
"shortDescription": "",
"targets": "all",
"windows": {
"certificateThumbprint": null,
"digestAlgorithm": "sha256",
"timestampUrl": ""
}
},
"security": {
"csp": null
},
"updater": {
"active": false
},
"windows": [
{
"fullscreen": false,
"height": 800,
"resizable": true,
"title": "soybean-admin",
"width": 1000
}
]
}
}

View File

@@ -4,23 +4,25 @@
<div class="w-56px h-56px my-36px">
<div class="relative h-full animate-spin">
<div
v-for="(item, index) in loadingClasses"
v-for="(item, index) in lodingClasses"
:key="index"
class="absolute w-16px h-16px bg-primary rounded-8px animate-pulse"
:class="item"
></div>
</div>
</div>
<h2 class="text-28px font-500 text-#646464">{{ $t('system.title') }}</h2>
<h2 class="text-28px font-500 text-#646464">{{ title }}</h2>
</div>
</template>
<script setup lang="ts">
import { sessionStg, getRgbOfColor } from '@/utils';
import { $t } from '@/locales';
import { useAppInfo } from '@/composables';
import { localStg, getRgbOfColor } from '@/utils';
import themeSettings from '@/settings/theme.json';
const loadingClasses = [
const { title } = useAppInfo();
const lodingClasses = [
'left-0 top-0',
'left-0 bottom-0 animate-delay-500',
'right-0 top-0 animate-delay-1000',
@@ -29,7 +31,7 @@ const loadingClasses = [
function addThemeColorCssVars() {
const defaultColor = themeSettings.themeColor;
const themeColor = sessionStg.get('themeColor') || defaultColor;
const themeColor = localStg.get('themeColor') || defaultColor;
const { r, g, b } = getRgbOfColor(themeColor);

View File

@@ -13,8 +13,6 @@ defineOptions({ name: 'DarkModeSwitch' });
interface Props {
/** 暗黑模式 */
dark?: boolean;
/** 自定义暗黑模式动画过渡 */
customizeTransition?: boolean;
}
const props = withDefaults(defineProps<Props>(), {
@@ -36,35 +34,32 @@ const darkMode = computed({
}
});
async function handleSwitch(event: MouseEvent) {
function handleSwitch(event: MouseEvent) {
const x = event.clientX;
const y = event.clientY;
if (!props.customizeTransition || !document.startViewTransition) {
const endRadius = Math.hypot(Math.max(x, innerWidth - x), Math.max(y, innerHeight - y));
// @ts-expect-error: Transition API
if (!document.startViewTransition) {
darkMode.value = !darkMode.value;
return;
}
const endRadius = Math.hypot(Math.max(x, innerWidth - x), Math.max(y, innerHeight - y));
// @ts-expect-error: Transition API
const transition = document.startViewTransition(() => {
darkMode.value = !darkMode.value;
});
await transition.ready;
const clipPath = [`circle(0px at ${x}px ${y}px)`, `circle(${endRadius}px at ${x}px ${y}px)`];
document.documentElement.animate(
{
clipPath: darkMode.value ? clipPath : [...clipPath].reverse()
},
{
duration: 300,
easing: 'ease-in',
pseudoElement: darkMode.value ? '::view-transition-new(root)' : '::view-transition-old(root)'
}
);
transition.ready.then(() => {
const clipPath = [`circle(0px at ${x}px ${y}px)`, `circle(${endRadius}px at ${x}px ${y}px)`];
document.documentElement.animate(
{
clipPath: darkMode.value ? clipPath : [...clipPath].reverse()
},
{
duration: 300,
easing: 'ease-in',
pseudoElement: darkMode.value ? '::view-transition-new(root)' : '::view-transition-old(root)'
}
);
});
}
</script>

View File

@@ -8,7 +8,7 @@ import { isNumber } from '@/utils';
defineOptions({ name: 'CountTo' });
type TransitionKey = keyof typeof TransitionPresets;
type TansitionKey = keyof typeof TransitionPresets;
interface Props {
/** 初始值 */
@@ -32,7 +32,7 @@ interface Props {
/** 使用缓冲动画函数 */
useEasing?: boolean;
/** 缓冲动画函数类型 */
transition?: TransitionKey;
transition?: TansitionKey;
}
const props = withDefaults(defineProps<Props>(), {

View File

@@ -37,13 +37,13 @@ const bindAttrs = computed<{ class: string; style: string }>(() => ({
}));
const symbolId = computed(() => {
const { VITE_ICON_LOCAL_PREFIX: prefix } = import.meta.env;
const { VITE_ICON_LOCAL_PREFFIX: preffix } = import.meta.env;
const defaultLocalIcon = 'no-icon';
const icon = props.localIcon || defaultLocalIcon;
return `#${prefix}-${icon}`;
return `#${preffix}-${icon}`;
});
/** 渲染本地icon */

View File

@@ -4,4 +4,3 @@ export * from './layout';
export * from './events';
export * from './echarts';
export * from './icon';
export * from './websocket';

View File

@@ -2,6 +2,26 @@ import UAParser from 'ua-parser-js';
import { useAuthStore } from '@/store';
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() {
const parser = new UAParser();

View File

@@ -1,50 +0,0 @@
import { io } from 'socket.io-client';
import type { Socket } from 'socket.io-client';
import { useAppStore } from '../store';
type ListenEvents = {
update: (id: string, data: { name: string; age: number }) => void;
};
type EmitEvents = {
update: (id: string, data: { name: string; age: number }) => void;
};
export function useWebsocket() {
const app = useAppStore();
const socket: Socket<ListenEvents, EmitEvents> = (app.socket || io('ws://localhost:8080')) as Socket<
ListenEvents,
EmitEvents
>;
if (!app.socket) {
app.setSocket(socket);
}
function init() {
window.console.log('[socket.io] connecting...');
socket.on('connect', () => {
window.console.log('[socket.io] connected.');
});
socket.on('disconnect', () => {
window.console.log('[socket.io] disconnected.');
});
socket.on('update', (id, data) => {
window.console.log('[socket.io] update', id, data);
});
}
function handleUpdate(id: string, data: { name: string; age: number }) {
socket.emit('update', id, data);
}
init();
return {
handleUpdate
};
}

View File

@@ -2,7 +2,7 @@
export const BAIDU_MAP_SDK_URL = `https://api.map.baidu.com/getscript?v=3.0&ak=KSezYymXPth1DIGILRX3oYN9PxbOQQmU&services=&t=20210201100830&s=1`;
/** 高德地图sdk地址 */
export const AMAP_SDK_URL = 'https://webapi.amap.com/maps?v=2.0&key=e7bd02bd504062087e6563daf4d6721d';
export const GAODE_MAP_SDK_URL = 'https://webapi.amap.com/maps?v=2.0&key=e7bd02bd504062087e6563daf4d6721d';
/** 腾讯地图sdk地址 */
export const TENCENT_MAP_SDK_URL = 'https://map.qq.com/api/gljs?v=1.exp&key=A6DBZ-KXPLW-JKSRY-ONZF4-CPHY3-K6BL7';

View File

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

View File

@@ -1,180 +0,0 @@
import { ref, reactive } from 'vue';
import type { Ref } from 'vue';
import type { PaginationProps, DataTableBaseColumn, DataTableSelectionColumn, DataTableExpandColumn } from 'naive-ui';
import type { TableColumnGroup } from 'naive-ui/es/data-table/src/interface';
import { useLoadingEmpty } from '../common';
/**
* 接口请求函数
*/
type ApiFn<T = any, R = any> = (args: T) => Promise<Service.RequestResult<R>>;
/**
* 接口请求函数的参数
*/
type GetApiFnParameters<T extends ApiFn, R = any> = T extends (args: infer P) => Promise<Service.RequestResult<R>>
? P
: never;
/**
* 接口请求函数的返回值
*/
type GetApiFnReturnType<T extends ApiFn, P = any> = T extends (args: P) => Promise<Service.RequestResult<infer R>>
? R
: never;
/**
* 表格接口请求后转换后的数据
*/
type Transformer<TableData, Response> = (response: Response) => {
data: TableData[];
pageNum: number;
pageSize: number;
total: number;
};
/**
* 列表接口参数更新
*/
type ApiParamsUpdater<P, R> = (params: P) => R;
/**
* 分页参数
*/
type PagePropsOfPagination = Pick<PaginationProps, 'page' | 'pageSize'>;
/**
* 自定义的列 key
*/
type CustomColumnKey<K = never> = K | 'action';
/**
* 表格的列
*/
type HookTableColumn<T = Record<string, unknown>> =
| (Omit<TableColumnGroup<T>, 'key'> & { key: CustomColumnKey<keyof T> })
| (Omit<DataTableBaseColumn<T>, 'key'> & { key: CustomColumnKey<keyof T> })
| DataTableSelectionColumn<T>
| DataTableExpandColumn<T>;
/**
* 表格配置
*/
type HookTableConfig<TableData, Fn extends ApiFn> = {
/**
* 列表接口参数
*/
apiParams: GetApiFnParameters<Fn>;
/**
* 列表接口返回数据转换
*/
transformer: Transformer<TableData, GetApiFnReturnType<Fn>>;
/**
* 列表列
*/
columns: () => HookTableColumn<TableData>[];
/**
* 列表接口参数更新
* @description 用于更新分页参数, 如果列表接口的参数不包含同名分页参数属性 `page` 和 `pageSize`, 需要通过此函数更新
* @default p => p
*/
apiParamsUpdater?: ApiParamsUpdater<GetApiFnParameters<Fn> & Partial<PagePropsOfPagination>, GetApiFnParameters<Fn>>;
/**
* 列表分页参数
*/
pagination?: PaginationProps;
/**
* 是否立即请求
* @default true
*/
immediate?: boolean;
};
/**
* 通用表格 hook
* @param apiFn 接口请求函数
* @param config 表格配置
*/
export default function useHookTable<TableData, Fn extends ApiFn>(apiFn: Fn, config: HookTableConfig<TableData, Fn>) {
const { loading, startLoading, endLoading, empty, setEmpty } = useLoadingEmpty();
const { apiParams, transformer, apiParamsUpdater = p => p, immediate = true } = config;
const data: Ref<TableData[]> = ref([]);
function updateData(update: TableData[]) {
data.value = update;
}
const columns = ref(config.columns()) as Ref<HookTableColumn<TableData>[]>;
const requestParams = ref(apiParams) as Ref<HookTableConfig<TableData, Fn>['apiParams']>;
function updateRequestParamsByPagination(p: PagePropsOfPagination) {
requestParams.value = apiParamsUpdater({ ...requestParams.value, ...p });
}
const pagination = reactive({
page: 1,
pageSize: 10,
showSizePicker: true,
pageSizes: [10, 15, 20, 25, 30],
onChange: (page: number) => {
pagination.page = page;
updateRequestParamsByPagination({ page });
getData();
},
onUpdatePageSize: (pageSize: number) => {
pagination.pageSize = pageSize;
pagination.page = 1;
updateRequestParamsByPagination({ pageSize });
getData();
},
...config.pagination
}) as PaginationProps;
function updatePagination(update: Partial<PaginationProps>) {
Object.assign(pagination, update);
updateRequestParamsByPagination({ page: pagination.page, pageSize: pagination.pageSize });
}
async function getData() {
startLoading();
const { data: apiData, error } = await apiFn(requestParams.value);
if (!error && data) {
const { data: tableData, pageNum, pageSize, total } = transformer(apiData);
updateData(tableData);
setEmpty(tableData.length === 0);
updatePagination({ page: pageNum, pageSize, itemCount: total });
}
endLoading();
}
function reloadColumns() {
columns.value = config.columns();
}
if (immediate) {
getData();
}
return {
data,
columns,
loading,
empty,
pagination,
getData,
updatePagination,
reloadColumns
};
}

View File

@@ -0,0 +1,151 @@
import { ref, reactive } from 'vue';
import type { Ref } from 'vue';
import type { DataTableBaseColumn, DataTableSelectionColumn, DataTableExpandColumn, PaginationProps } from 'naive-ui';
import type { TableColumnGroup, InternalRowData } from 'naive-ui/es/data-table/src/interface';
import { useLoadingEmpty } from '../common';
/**
* 表格分页参数
*/
type PaginationParams = Pick<PaginationProps, 'page' | 'pageSize'>;
/**
* 表格请求接口的参数
*/
type ApiParams = Record<string, unknown> & PaginationParams;
/**
* 表格请求接口的结果
* @description 这里用属性list来表示后端接口返回的表格数据
*/
type ApiData<TableData = Record<string, unknown>> = Record<string, unknown> & { list: TableData[] };
/**
* 表格接口的请求函数
*/
type ApiFn<Params = ApiParams, TableData = Record<string, unknown>> = (
params: Params
) => Promise<Service.RequestResult<ApiData<TableData>>>;
/**
* 表格接口请求后转换后的数据
*/
type TransformedTableData<TableData = Record<string, unknown>> = {
data: TableData[];
pageNum: number;
pageSize: number;
total: number;
};
/**
* 表格的列
*/
type DataTableColumn<T = InternalRowData> =
| (Omit<TableColumnGroup<T>, 'key'> & { key: keyof T })
| (Omit<DataTableBaseColumn<T>, 'key'> & { key: keyof T })
| DataTableSelectionColumn<T>
| DataTableExpandColumn<T>;
/**
* 表格数据转换器
* @description 将不同接口的表格数据转换成统一的类型
*/
type Transformer<TableData = Record<string, unknown>> = (
apiData: ApiData<TableData>
) => TransformedTableData<TableData>;
type TableParams<TableData = Record<string, unknown>, Params = ApiParams> = {
apiFn: ApiFn<Params, TableData>;
apiParams: Params;
transformer: Transformer<TableData>;
columns: DataTableColumn<TableData>[];
pagination?: PaginationProps;
};
export function useTable<TableData extends Record<string, unknown>, Params extends ApiParams>(
params: TableParams<TableData, Params>,
immediate = true
) {
const { loading, startLoading, endLoading, empty, setEmpty } = useLoadingEmpty();
const data: Ref<TableData[]> = ref([]);
function updateData(update: TableData[]) {
data.value = update;
}
let dataSource: TableData[] = [];
function setDataSource(source: TableData[]) {
dataSource = source;
}
function resetData() {
data.value = dataSource;
}
const columns = ref(params.columns) as Ref<DataTableColumn<TableData>[]>;
const pagination = reactive({
...getPagination(params.pagination),
onChange: (page: number) => {
pagination.page = page;
},
onUpdatePageSize: (pageSize: number) => {
pagination.pageSize = pageSize;
pagination.page = 1;
}
}) as PaginationProps;
function updatePagination(update: Partial<PaginationProps>) {
Object.assign(pagination, update);
}
async function getData() {
const apiParams: Params = { ...params.apiParams };
apiParams.page = apiParams.page || pagination.page;
apiParams.pageSize = apiParams.pageSize || pagination.pageSize;
startLoading();
const { data: apiData } = await params.apiFn(apiParams);
if (apiData) {
const transformedData = params.transformer(apiData);
updateData(transformedData.data);
setDataSource(transformedData.data);
setEmpty(transformedData.data.length === 0);
updatePagination({ page: transformedData.pageNum, pageSize: transformedData.pageSize });
}
endLoading();
}
if (immediate) {
getData();
}
return {
data,
columns,
loading,
empty,
pagination,
getData,
updateData,
resetData
};
}
function getPagination(pagination?: Partial<PaginationProps>) {
const defaultPagination: Partial<PaginationProps> = {
page: 1,
pageSize: 10,
showSizePicker: true,
pageSizes: [10, 15, 20, 25, 30]
};
Object.assign(defaultPagination, pagination);
return defaultPagination;
}

View File

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

View File

@@ -1,11 +1,6 @@
<template>
<hover-container class="w-40px" :inverted="theme.header.inverted" tooltip-content="主题模式">
<dark-mode-switch
:dark="theme.darkMode"
:customize-transition="theme.isCustomizeDarkModeTransition"
class="wh-full"
@update:dark="theme.setDarkMode"
/>
<dark-mode-switch :dark="theme.darkMode" class="wh-full" @update:dark="theme.setDarkMode" />
</hover-container>
</template>

View File

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

View File

@@ -2,14 +2,14 @@
<router-link :to="routeHomePath" class="flex-center w-full nowrap-hidden">
<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">
{{ $t('system.title') }}
{{ t('message.system.title') }}
</h2>
</router-link>
</template>
<script setup lang="ts">
import { routePath } from '@/router';
import { $t } from '@/locales';
import { t } from '@/locales';
defineOptions({ name: 'GlobalLogo' });

View File

@@ -22,9 +22,6 @@ defineOptions({ name: 'SearchFooter' });
<style lang="scss" scoped>
.icon {
box-shadow:
inset 0 -2px #cdcde6,
inset 0 0 1px 1px #fff,
0 1px 2px 1px #1e235a66;
box-shadow: inset 0 -2px #cdcde6, inset 0 0 1px 1px #fff, 0 1px 2px 1px #1e235a66;
}
</style>

View File

@@ -34,7 +34,6 @@ import { useRouter } from 'vue-router';
import { onKeyStroke, useDebounceFn } from '@vueuse/core';
import { useRouteStore } from '@/store';
import { useBasicLayout } from '@/composables';
import { $t } from '@/locales';
import SearchResult from './search-result.vue';
import SearchFooter from './search-footer.vue';
@@ -83,12 +82,14 @@ watch(show, async val => {
/** 查询 */
function search() {
resultOptions.value = routeStore.searchMenus.filter(menu => {
const trimKeyword = keyword.value.toLocaleLowerCase().trim();
const title = (menu.meta.i18nTitle ? $t(menu.meta.i18nTitle) : menu.meta.title).toLocaleLowerCase();
return trimKeyword && title.includes(trimKeyword);
});
activePath.value = resultOptions.value[0]?.path ?? '';
resultOptions.value = routeStore.searchMenus.filter(
menu => keyword.value && menu.meta?.title.toLocaleLowerCase().includes(keyword.value.toLocaleLowerCase().trim())
);
if (resultOptions.value?.length > 0) {
activePath.value = resultOptions.value[0].path;
} else {
activePath.value = '';
}
}
function handleClose() {

View File

@@ -12,9 +12,7 @@
@mouseenter="handleMouse(item)"
>
<svg-icon :icon="item.meta.icon" :local-icon="item.meta.localIcon" />
<span class="flex-1 ml-5px">
{{ (item.meta?.i18nTitle && $t(item.meta?.i18nTitle)) || item.meta?.title }}
</span>
<span class="flex-1 ml-5px">{{ item.meta?.title }}</span>
<icon-ant-design-enter-outlined class="icon text-20px p-2px mr-3px" />
</div>
</template>
@@ -25,7 +23,6 @@
<script lang="ts" setup>
import { computed } from 'vue';
import { useThemeStore } from '@/store';
import { $t } from '@/locales';
defineOptions({ name: 'SearchResult' });

View File

@@ -9,7 +9,7 @@
:style="{ width: showDrawer ? theme.sider.mixChildMenuWidth + 'px' : '0px' }"
>
<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">{{ $t('system.title') }}</h2>
<h2 class="text-primary pl-8px text-16px font-bold">{{ title }}</h2>
<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 v-else />
@@ -35,9 +35,8 @@ import { computed, ref, watch } from 'vue';
import { useRoute } from 'vue-router';
import type { MenuOption } from 'naive-ui';
import { useAppStore, useThemeStore } from '@/store';
import { useRouterPush } from '@/composables';
import { useAppInfo, useRouterPush } from '@/composables';
import { getActiveKeyPathsOfMenus } from '@/utils';
import { $t } from '@/locales';
defineOptions({ name: 'MixMenuDrawer' });
@@ -54,6 +53,7 @@ const route = useRoute();
const app = useAppStore();
const theme = useThemeStore();
const { routerPush } = useRouterPush();
const { title } = useAppInfo();
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 { translateMenuLabel } from '@/utils';
import { GlobalLogo } from '@/layouts/common';
import { $t } from '@/locales';
import { t } from '@/locales';
import { MixMenuCollapse, MixMenuDetail, MixMenuDrawer } from './components';
defineOptions({ name: 'VerticalMixSider' });
@@ -53,7 +53,7 @@ const firstDegreeMenus = computed(() =>
return {
routeName,
label: i18nTitle ? $t(i18nTitle) : label,
label: i18nTitle ? t(i18nTitle) : label,
icon,
hasChildren
};

View File

@@ -6,21 +6,26 @@
<script setup lang="ts">
import { useRoute } from 'vue-router';
import { useRouteStore } from '@/store';
import { useAppStore, useRouteStore } from '@/store';
import { useLoading } from '@/hooks';
defineOptions({ name: 'ReloadButton' });
const { reCacheRoute } = useRouteStore();
const app = useAppStore();
const routeStore = useRouteStore();
const route = useRoute();
const { loading, startLoading, endLoading } = useLoading();
async function handleRefresh() {
function handleRefresh() {
const isCached = routeStore.cacheRoutes.includes(String(route.name));
if (isCached) {
routeStore.removeCacheRoute(route.name as AuthRoute.AllRouteKey);
}
startLoading();
await reCacheRoute(route.name as AuthRoute.AllRouteKey);
app.reloadPage();
setTimeout(() => {
if (isCached) {
routeStore.addCacheRoute(route.name as AuthRoute.AllRouteKey);
}
endLoading();
}, 1000);
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,8 +1,8 @@
import type { App } from 'vue';
import { createI18n } from 'vue-i18n';
import type { TranslateOptions } from 'vue-i18n';
import { localStg } from '@/utils/storage';
import messages from './locale';
import { localStg } from '@/utils';
import messages from './lang';
import type { LocaleKey } from './lang';
const i18n = createI18n({
locale: localStg.get('lang') || 'zh-CN',
@@ -15,20 +15,10 @@ export function setupI18n(app: App) {
app.use(i18n);
}
interface T {
(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 t(key: string) {
return i18n.global.t(key);
}
export const $t = i18n.global.t as T;
export function setLocale(locale: I18nType.LangType) {
export function setLocale(locale: LocaleKey) {
i18n.global.locale.value = locale;
}

View File

@@ -1,217 +1,83 @@
const locale: I18nType.Schema = {
system: {
title: 'SoybeanAdmin'
},
common: {
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'
import type { LocaleMessages } from 'vue-i18n';
const locale: LocaleMessages<I18nType.Schema> = {
message: {
system: {
title: 'SoybeanAdmin'
},
document: {
_value: 'Document',
vue: 'Vue Document',
vite: 'Vite Document',
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'
routes: {
dashboard: {
_value: 'Dashboard',
analysis: 'Analysis',
workbench: 'Workbench'
},
copy: 'Copy',
editor: {
_value: 'Editor',
quill: 'Quill',
markdown: 'Markdown'
document: {
_value: 'Document',
vue: 'Vue Document',
vite: 'Vite Document',
naive: 'NaiveUI Document',
project: 'Project Document',
'project-link': 'Project Document(href)'
},
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: {
_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'
component: {
_value: 'Component',
button: 'Button',
card: 'Card',
table: 'Table'
},
fixedHeaderAndTab: 'Fixed header and multiple tabs',
header: {
inverted: 'darkHead',
height: 'Head Height',
crumb: {
visible: 'Crumb',
icon: 'Crumb icon'
}
},
tab: {
visible: 'Multi-page tab',
height: 'Multiple tab height',
modeList: {
mode: 'Multi-tab style',
chrome: 'Google style',
button: 'Button style'
plugin: {
_value: 'Plugin',
charts: {
_value: 'Chart',
echarts: 'ECharts',
antv: 'AntV'
},
isCache: 'Multiple tab caching'
copy: 'Copy',
editor: {
_value: 'Editor',
quill: 'Quill',
markdown: 'Markdown'
},
icon: 'Icon',
map: 'Map',
print: 'Print',
swiper: 'Swiper',
video: 'Video'
},
sider: {
inverted: 'Dark sidebar',
width: 'Sidebar expanded width',
mixWidth: 'Left hybrid sidebar expanded width'
'auth-demo': {
_value: 'Auth Demo',
permission: 'Toggle Permission',
super: 'Super Auth'
},
menu: {
horizontalPosition: 'Top menu position',
horizontalPositionList: {
flexStart: 'Right',
center: 'center',
flexEnd: 'Left'
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'
}
}
},
footer: {
inverted: 'Dark bottom',
visible: 'Show bottom',
fixed: 'Fixed bottom',
right: 'Bottom to the right'
management: {
_value: 'System Management',
auth: 'Auth',
role: 'Role',
route: 'Route',
user: 'User'
},
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'
}
about: 'About'
}
}
};

13
src/locales/lang/index.ts Normal file
View File

@@ -0,0 +1,13 @@
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,217 +1,83 @@
const locale: I18nType.Schema = {
system: {
title: 'ប្រព័ន្ធគ្រប់គ្រង'
},
common: {
add: 'បន្ថែម',
addSuccess: 'បន្ថែមជោគជ័យ',
edit: 'កែប្រែ',
editSuccess: 'កែប្រែជោគជ័យ',
delete: 'លុប',
deleteSuccess: 'លុបជោគជ័យ',
batchDelete: 'លុបច្រើន',
confirm: 'យល់ព្រម',
cancel: 'បោះបង់',
pleaseCheckValue: 'សូមពិនិត្យមើលតម្លៃដែលបានបញ្ចូលដើម្បីបញ្ជាក់ថាត្រូវប្រើប្រាស់បាន',
action: 'សកម្មភាព'
},
routes: {
dashboard: {
_value: 'ផ្ទាំងទិន្នន័យ',
analysis: 'ផ្ទាំងវិភាគ',
workbench: 'ផ្ទាំងការងារ'
import type { LocaleMessages } from 'vue-i18n';
const locale: LocaleMessages<I18nType.Schema> = {
message: {
system: {
title: 'ប្រព័ន្ធគ្រប់គ្រង'
},
document: {
_value: 'ឯកសារ',
vue: 'ឯកសារ​ Vue',
vite: 'ឯកសារ​ Vite',
naive: 'ឯកសារ NaiveUI',
project: 'ឯកសារគម្រោង',
'project-link': 'ឯកសារគម្រោង(href)'
},
component: {
_value: 'សមាស​ភាគ',
button: 'ប៊ូតុង',
card: 'កាត',
table: 'តារាង'
},
plugin: {
_value: 'មុខងារជំនួយ',
charts: {
_value: 'តារាង​ Chart',
echarts: 'តារាង ECharts',
antv: 'AntV'
routes: {
dashboard: {
_value: 'ផ្ទាំងទិន្នន័យ',
analysis: 'ផ្ទាំងវិភាគ',
workbench: 'ផ្ទាំងការងារ'
},
copy: 'ចម្លង',
editor: {
_value: 'កែប្រែ',
quill: 'Quill',
markdown: 'Markdown'
document: {
_value: 'ឯកសារ',
vue: 'ឯកសារ​ Vue',
vite: 'ឯកសារ​ Vite',
naive: 'ឯកសារ NaiveUI',
project: 'ឯកសារគម្រោង',
'project-link': 'ឯកសារគម្រោង(href)'
},
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: {
_value: 'ការគ្រប់គ្រងប្រព័ន្ធ',
auth: 'Auth',
role: 'សិទ្ធី',
route: 'ផ្លូវប្រព័ន្ធ',
user: 'អ្នកប្រើប្រាស់'
},
about: 'អំពីប្រព័ន្ធ'
},
layout: {
settingDrawer: {
title: 'ការកំណត់ស្បែក',
themeModeTitle: 'ស្បែករបស់របស់អ្នក',
darkMode: 'របៀបងារស្បែកងងឹត',
layoutModelTitle: 'របៀបប្រើប្រាស់របស់អ្នក',
systemThemeTitle: 'ស្បែករបស់ប្រព័ន្ធគ្រប់គ្រង',
pageFunctionsTitle: 'មុខងារទំនាក់ទំនងរបស់ទំព័រ',
pageViewTitle: 'ទំព័រទស្សន៍ទាយ',
followSystemTheme: 'តាមដានស្បែកប្រព័ន្ធគ្រប់គ្រង',
isCustomizeDarkModeTransition: 'ប្រើប្រាស់របៀបងារស្បែកងងឹតផ្ទាល់ខ្លួន',
scrollMode: 'របៀបរុករក',
scrollModeList: {
wrapper: 'រុករកជាក់លាក់',
content: 'រុករកមានមុខងារ'
component: {
_value: 'សមាស​ភាគ',
button: 'ប៊ូតុង',
card: 'កាត',
table: 'តារាង'
},
fixedHeaderAndTab: 'បិទការរុករកជាក់លាក់និងរុករកមានមុខងារ',
header: {
inverted: 'បង្កើតការរុករកជាក់លាក់',
height: 'កម្ពស់',
crumb: {
visible: 'បង្ហាញរុករកជាក់លាក់',
icon: 'រុករកជាក់លាក់រូបតំណាង'
}
},
tab: {
visible: 'បង្ហាញរុករកជាក់លាក់',
height: 'កម្ពស់',
modeList: {
mode: 'របៀប',
chrome: 'ក្រុមហ៊ុន',
button: 'ប៊ូតុង'
plugin: {
_value: 'មុខងារជំនួយ',
charts: {
_value: 'តារាង​ Chart',
echarts: 'តារាង ECharts',
antv: 'AntV'
},
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}!'
editor: {
_value: 'កែប្រែ',
quill: 'Quill',
markdown: 'Markdown'
},
icon: 'អាយខន',
map: 'ផែនទី',
print: 'បោះពុម្ភ',
swiper: 'Swiper',
video: 'វីដេអូ'
},
pwdLogin: {
title: 'ចូលគណនី',
rememberMe: 'ចងចាំខ្ញុំ',
forgetPassword: 'ភ្លេចលេខសម្ងាត់',
register: 'ចុះឈ្មោះ',
otherAccountLogin: 'ចូលតាមគណនីផ្សេងទៀត',
otherLoginMode: 'របៀបចូលគណនីផ្សេងទៀត',
superAdmin: 'អ្នកគ្រប់គ្រងសុវត្ថិភាព',
admin: 'អ្នកគ្រប់គ្រង',
'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: 'អ្នកប្រើប្រាស់'
},
codeLogin: {
title: 'ចូលតាមលេខកូដ',
getCode: 'ទទួលលេខកូដ',
imageCodePlaceholder: 'លេខកូដរូបភាព'
},
register: {
title: 'ចុះឈ្មោះ',
agreement: 'យល់ព្រមនឹង',
protocol: 'សម្រាប់ការប្រើប្រាស់',
policy: 'គោលការណ៍ផ្សេងៗ'
},
resetPwd: {
title: 'កំណត់លេខសម្ងាត់ថ្មី'
},
bindWeChat: {
title: 'ភ្ជាប់គណនីរបស់អ្នកជាមួយគណនីរបស់អ្នក'
}
about: 'អំពីប្រព័ន្ធ'
}
}
};

View File

@@ -1,219 +0,0 @@
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;

85
src/locales/lang/zh-cn.ts Normal file
View File

@@ -0,0 +1,85 @@
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;

View File

@@ -1,11 +0,0 @@
import zhCN from './lang/zh-CN';
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

@@ -7,6 +7,4 @@ import 'virtual:svg-icons-register';
import '../styles/css/global.css';
/** import static assets: css, js , font and so on. - [引入静态资源css、js和字体文件等] */
export default function setupAssets() {
//
}
export default function setupAssets() {}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -11,8 +11,6 @@ import {
} from '@/utils';
import { handleRefreshToken } from './helpers';
type RefreshRequestQueue = (config: AxiosRequestConfig) => void;
/**
* 封装axios请求类
* @author Soybean<honghuangdc@gmail.com>
@@ -22,10 +20,6 @@ export default class CustomAxiosInstance {
backendConfig: Service.BackendResultConfig;
isRefreshing: boolean;
retryQueues: RefreshRequestQueue[];
/**
*
* @param axiosConfig - axios配置
@@ -43,8 +37,6 @@ export default class CustomAxiosInstance {
this.backendConfig = backendConfig;
this.instance = axios.create(axiosConfig);
this.setInterceptor();
this.isRefreshing = false;
this.retryQueues = [];
}
/** 设置请求拦截器 */
@@ -68,7 +60,7 @@ export default class CustomAxiosInstance {
);
this.instance.interceptors.response.use(
(async response => {
const { status, config } = response;
const { status } = response;
if (status === 200 || status < 300 || status === 304) {
const backend = response.data;
const { codeKey, dataKey, successCode } = this.backendConfig;
@@ -79,24 +71,10 @@ export default class CustomAxiosInstance {
// token失效, 刷新token
if (REFRESH_TOKEN_CODE.includes(backend[codeKey])) {
// 原始请求
const originRequest = new Promise(resolve => {
this.retryQueues.push((refreshConfig: AxiosRequestConfig) => {
config.headers.Authorization = refreshConfig.headers?.Authorization;
resolve(this.instance.request(config));
});
});
if (!this.isRefreshing) {
this.isRefreshing = true;
const refreshConfig = await handleRefreshToken(response.config);
if (refreshConfig) {
this.retryQueues.map(cb => cb(refreshConfig));
}
this.retryQueues = [];
this.isRefreshing = false;
const config = await handleRefreshToken(response.config);
if (config) {
return this.instance.request(config);
}
return originRequest;
}
const error = handleBackendError(backend, this.backendConfig);

View File

@@ -1,7 +1,6 @@
{
"darkMode": false,
"followSystemTheme": true,
"isCustomizeDarkModeTransition": false,
"layout": {
"minWidth": 900,
"mode": "vertical",
@@ -35,15 +34,15 @@
"label": "主体滚动"
}
],
"themeColor": "#646cff",
"themeColor": "#1890ff",
"themeColorList": [
"#1890ff",
"#409EFF",
"#2d8cf0",
"#007AFF",
"#5ac8fa",
"#5856D6",
"#536dfe",
"#646cff",
"#9c27b0",
"#AF52DE",
"#0096c7",

View File

@@ -10,11 +10,11 @@ import jsonSetting from './theme.json';
const themeColorList = [
'#1890ff',
'#409EFF',
'#2d8cf0',
'#007AFF',
'#5ac8fa',
'#5856D6',
'#536dfe',
'#646cff',
'#9c27b0',
'#AF52DE',
'#0096c7',
@@ -37,7 +37,6 @@ const themeColorList = [
const defaultThemeSetting: Theme.Setting = {
darkMode: false,
followSystemTheme: true,
isCustomizeDarkModeTransition: false,
layout: {
minWidth: 900,
mode: 'vertical',
@@ -45,7 +44,7 @@ const defaultThemeSetting: Theme.Setting = {
},
scrollMode: 'content',
scrollModeList: themeScrollModeOptions,
themeColor: themeColorList[6],
themeColor: themeColorList[0],
themeColorList,
otherColor: {
info: '#2080f0',

View File

@@ -1,6 +1,5 @@
import { nextTick } from 'vue';
import { defineStore } from 'pinia';
import type { Socket } from 'socket.io-client';
import { LAYOUT_SCROLL_EL_ID } from '@soybeanjs/vue-materials';
interface AppState {
@@ -18,8 +17,6 @@ interface AppState {
siderCollapse: boolean;
/** vertical-mix模式下 侧边栏的固定状态 */
mixSiderFixed: boolean;
/** socket.io 实例 */
socket: Socket | null;
}
export const useAppStore = defineStore('app-store', {
@@ -30,8 +27,7 @@ export const useAppStore = defineStore('app-store', {
reloadFlag: true,
settingDrawerVisible: false,
siderCollapse: false,
mixSiderFixed: false,
socket: null
mixSiderFixed: false
}),
actions: {
/**
@@ -101,10 +97,6 @@ export const useAppStore = defineStore('app-store', {
/** 设置主体内容全屏 */
setContentFull(full: boolean) {
this.contentFull = full;
},
/** 设置socket实例 */
setSocket<T extends Socket = Socket>(socket: T) {
this.socket = socket;
}
}
});

View File

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

View File

@@ -14,7 +14,6 @@ import {
transformRoutePathToRouteName,
sortRoutes
} from '@/utils';
import { useAppStore } from '../app';
import { useAuthStore } from '../auth';
import { useTabStore } from '../tab';
@@ -120,10 +119,9 @@ export const useRouteStore = defineStore('route-store', {
const { error, data } = await fetchUserRoutes(userId);
if (!error) {
this.handleAuthRoute(sortRoutes(data.routes));
// home相关处理需要在最后否则会出现找不到主页404的情况
this.routeHomeName = data.home;
this.handleUpdateRootRedirect(data.home);
this.handleAuthRoute(sortRoutes(data.routes));
initHomeTab(data.home, router);
@@ -152,6 +150,7 @@ export const useRouteStore = defineStore('route-store', {
await this.initStaticRoute();
}
},
/** 从缓存路由中去除某个路由 */
removeCacheRoute(name: AuthRoute.AllRouteKey) {
const index = this.cacheRoutes.indexOf(name);
@@ -159,30 +158,13 @@ export const useRouteStore = defineStore('route-store', {
this.cacheRoutes.splice(index, 1);
}
},
/** 添加某个缓存路由 */
addCacheRoute(name: AuthRoute.AllRouteKey) {
const index = this.cacheRoutes.indexOf(name);
if (index === -1) {
this.cacheRoutes.push(name);
}
},
/**
* 重新缓存路由
*/
async reCacheRoute(name: AuthRoute.AllRouteKey) {
const { reloadPage } = useAppStore();
const isCached = this.cacheRoutes.includes(name);
if (isCached) {
this.removeCacheRoute(name);
}
await reloadPage();
if (isCached) {
this.addCacheRoute(name as AuthRoute.AllRouteKey);
}
}
}
});

View File

@@ -1,6 +1,5 @@
import type { RouteLocationNormalizedLoaded, Router } from 'vue-router';
import { defineStore } from 'pinia';
import { useRouteStore } from '@/store';
import { useRouterPush } from '@/composables';
import { localStg } from '@/utils';
import { useThemeStore } from '../theme';
@@ -69,11 +68,7 @@ export const useTabStore = defineStore('tab-store', {
setActiveTabTitle(title: string) {
const item = this.tabs.find(tab => tab.fullPath === this.activeTab);
if (item) {
if (item.meta.i18nTitle) {
item.meta.i18nTitle = title as I18nType.I18nKey;
} else {
item.meta.title = title;
}
item.meta.title = title;
}
},
/**
@@ -120,14 +115,8 @@ export const useTabStore = defineStore('tab-store', {
* @param fullPath - 路由fullPath
*/
async removeTab(fullPath: string) {
const { reCacheRoute } = useRouteStore();
const { routerPush } = useRouterPush(false);
const tabName = this.tabs.find(tab => tab.fullPath === fullPath)?.name as AuthRoute.AllRouteKey | undefined;
if (tabName) {
await reCacheRoute(tabName);
}
const isActive = this.activeTab === fullPath;
const updateTabs = this.tabs.filter(tab => tab.fullPath !== fullPath);
if (!isActive) {

View File

@@ -1,19 +1,19 @@
import type { GlobalThemeOverrides } from 'naive-ui';
import { cloneDeep } from 'lodash-es';
import { themeSetting } from '@/settings';
import { sessionStg, addColorAlpha, getColorPalette } from '@/utils';
import { localStg, addColorAlpha, getColorPalette } from '@/utils';
/** 初始化主题配置 */
export function initThemeSettings() {
const isProd = import.meta.env.PROD;
// 生产环境才缓存主题配置本地开发实时调整配置更改配置的json
const storageSettings = sessionStg.get('themeSettings');
const storageSettings = localStg.get('themeSettings');
if (isProd && storageSettings) {
return storageSettings;
}
const themeColor = sessionStg.get('themeColor') || themeSetting.themeColor;
const themeColor = localStg.get('themeColor') || themeSetting.themeColor;
const info = themeSetting.isCustomizeInfoColor ? themeSetting.otherColor.info : getColorPalette(themeColor, 7);
const otherColor = { ...themeSetting.otherColor, info };
const setting = cloneDeep({ ...themeSetting, themeColor, otherColor });

View File

@@ -1,6 +1,6 @@
import { defineStore } from 'pinia';
import { darkTheme } from 'naive-ui';
import { sessionStg } from '@/utils';
import { localStg } from '@/utils';
import { getNaiveThemeOverrides, initThemeSettings } from './helpers';
type ThemeState = Theme.Setting;
@@ -25,14 +25,14 @@ export const useThemeStore = defineStore('theme-store', {
actions: {
/** 重置theme状态 */
resetThemeStore() {
sessionStg.remove('themeSettings');
localStg.remove('themeSettings');
this.$reset();
},
/** 缓存主题配置 */
cacheThemeSettings() {
const isProd = import.meta.env.PROD;
if (isProd) {
sessionStg.set('themeSettings', this.$state);
localStg.set('themeSettings', this.$state);
}
},
/** 设置暗黑模式 */
@@ -43,10 +43,6 @@ export const useThemeStore = defineStore('theme-store', {
setFollowSystemTheme(visible: boolean) {
this.followSystemTheme = visible;
},
/** 设置自动跟随系统主题 */
setIsCustomizeDarkModeTransition(isCustomize: boolean) {
this.isCustomizeDarkModeTransition = isCustomize;
},
/** 自动跟随系统主题 */
setAutoFollowSystemMode(darkMode: boolean) {
if (this.followSystemTheme) {

View File

@@ -3,7 +3,7 @@ import { useOsTheme } from 'naive-ui';
import type { GlobalThemeOverrides } from 'naive-ui';
import { useElementSize } from '@vueuse/core';
import { kebabCase } from 'lodash-es';
import { sessionStg, getColorPalettes, getRgbOfColor } from '@/utils';
import { localStg, getColorPalettes, getRgbOfColor } from '@/utils';
import { useThemeStore } from '../modules';
/** 订阅theme store */
@@ -19,7 +19,7 @@ export default function subscribeThemeStore() {
watch(
() => theme.themeColor,
newValue => {
sessionStg.set('themeColor', newValue);
localStg.set('themeColor', newValue);
},
{ immediate: true }
);

View File

@@ -24,21 +24,9 @@ html {
-webkit-text-size-adjust: 100%; /* 2 */
-moz-tab-size: 4; /* 3 */
tab-size: 4; /* 3 */
font-family:
ui-sans-serif,
system-ui,
-apple-system,
BlinkMacSystemFont,
"Segoe UI",
Roboto,
"Helvetica Neue",
Arial,
"Noto Sans",
sans-serif,
"Apple Color Emoji",
"Segoe UI Emoji",
"Segoe UI Symbol",
"Noto Color Emoji"; /* 4 */
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont,
"Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif,
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; /* 4 */
}
/*

View File

@@ -25,9 +25,7 @@
/* fade-bottom */
.fade-bottom-enter-active,
.fade-bottom-leave-active {
transition:
opacity 0.25s,
transform 0.3s;
transition: opacity 0.25s, transform 0.3s;
}
.fade-bottom-enter-from {
opacity: 0;
@@ -55,9 +53,7 @@
/* zoom-fade */
.zoom-fade-enter-active,
.zoom-fade-leave-active {
transition:
transform 0.2s,
opacity 0.3s ease-out;
transition: transform 0.2s, opacity 0.3s ease-out;
}
.zoom-fade-enter-from {
opacity: 0;
@@ -71,9 +67,7 @@
/* zoom-out */
.zoom-out-enter-active,
.zoom-out-leave-active {
transition:
opacity 0.1s ease-in-out,
transform 0.15s ease-out;
transition: opacity 0.1s ease-in-out, transform 0.15s ease-out;
}
.zoom-out-enter-from,
.zoom-out-leave-to {

View File

@@ -40,13 +40,13 @@ interface ImportMetaEnv {
/** 路由首页的路径 */
readonly VITE_ROUTE_HOME_PATH: AuthRoute.RoutePath;
/** iconify图标作为组件的前缀 */
readonly VITE_ICON_PREFIX: string;
readonly VITE_ICON_PREFFIX: string;
/**
* 本地SVG图标作为组件的前缀, 请注意一定要包含 VITE_ICON_PREFIX
* - 格式 {VITE_ICON_PREFIX}-{本地图标集合名称}
* 本地SVG图标作为组件的前缀, 请注意一定要包含 VITE_ICON_PREFFIX
* - 格式 {VITE_ICON_PREFFIX}-{本地图标集合名称}
* - 例如icon-local
*/
readonly VITE_ICON_LOCAL_PREFIX: string;
readonly VITE_ICON_LOCAL_PREFFIX: string;
/** 后端服务的环境类型 */
readonly VITE_SERVICE_ENV?: ServiceEnvType;
/** 开启请求代理 */

View File

@@ -5,14 +5,6 @@ interface Window {
$notification?: import('naive-ui').NotificationProviderInst;
}
interface ViewTransition {
ready: Promise<void>;
}
interface Document {
startViewTransition?: (callback: () => Promise<void> | void) => ViewTransition;
}
/** 通用类型 */
declare namespace Common {
/**

View File

@@ -47,7 +47,6 @@ declare namespace PageRoute {
| 'function_tab-detail'
| 'function_tab-multi-detail'
| 'function_tab'
| 'function_websocket'
| 'management'
| 'management_auth'
| 'management_role'
@@ -103,7 +102,6 @@ declare namespace PageRoute {
| 'function_tab-detail'
| 'function_tab-multi-detail'
| 'function_tab'
| 'function_websocket'
| 'management_auth'
| 'management_role'
| 'management_route'

View File

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

Some files were not shown because too many files have changed in this diff Show More