mirror of
https://github.com/soybeanjs/soybean-admin.git
synced 2026-03-15 16:24:25 +08:00
Compare commits
1 Commits
main
...
v2.0-route
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6ac50e7d15 |
2
.github/ISSUE_TEMPLATE/bug-report_cn.yaml
vendored
2
.github/ISSUE_TEMPLATE/bug-report_cn.yaml
vendored
@@ -1,7 +1,7 @@
|
||||
name: 🐞 Bug提交
|
||||
description: 在使用软件或功能的过程中遇到了错误
|
||||
title: '[Bug]: '
|
||||
labels: ['bug?']
|
||||
labels: [ "bug?" ]
|
||||
|
||||
body:
|
||||
- type: markdown
|
||||
|
||||
2
.github/ISSUE_TEMPLATE/bug-report_en.yaml
vendored
2
.github/ISSUE_TEMPLATE/bug-report_en.yaml
vendored
@@ -1,7 +1,7 @@
|
||||
name: 🐞 Bug Report
|
||||
description: Encountered an error while using the software or feature
|
||||
title: '[Bug]: '
|
||||
labels: ['bug?']
|
||||
labels: [ "bug?" ]
|
||||
|
||||
body:
|
||||
- type: markdown
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
---
|
||||
name: 🚀 功能请求
|
||||
description: 提出一个想法以帮助我们改进W&B
|
||||
title: '[功能]: '
|
||||
title: "[功能]: "
|
||||
labels:
|
||||
- '功能请求'
|
||||
- "功能请求"
|
||||
|
||||
body:
|
||||
- type: markdown
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
---
|
||||
name: 🚀 Feature Request
|
||||
description: Suggest an idea to help us improve W&B
|
||||
title: '[Feature]: '
|
||||
title: "[Feature]: "
|
||||
labels:
|
||||
- 'feature_request'
|
||||
- "feature_request"
|
||||
|
||||
body:
|
||||
- type: markdown
|
||||
|
||||
34
.github/workflows/opencode.yml
vendored
34
.github/workflows/opencode.yml
vendored
@@ -1,34 +0,0 @@
|
||||
name: opencode
|
||||
|
||||
on:
|
||||
issue_comment:
|
||||
types: [created]
|
||||
pull_request_review_comment:
|
||||
types: [created]
|
||||
|
||||
jobs:
|
||||
opencode:
|
||||
if: |
|
||||
contains(github.event.comment.body, ' /oc') ||
|
||||
startsWith(github.event.comment.body, '/oc') ||
|
||||
contains(github.event.comment.body, ' /opencode') ||
|
||||
startsWith(github.event.comment.body, '/opencode')
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
id-token: write
|
||||
contents: read
|
||||
pull-requests: read
|
||||
issues: read
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Run opencode
|
||||
uses: anomalyco/opencode/github@latest
|
||||
env:
|
||||
GOOGLE_GENERATIVE_AI_API_KEY: ${{ secrets.GOOGLE_GENERATIVE_AI_API_KEY }}
|
||||
GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
|
||||
with:
|
||||
model: google/gemini-3-pro-preview
|
||||
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@@ -6,7 +6,7 @@ permissions:
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*'
|
||||
- "v*"
|
||||
|
||||
jobs:
|
||||
release:
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -33,3 +33,5 @@ package-lock.json
|
||||
yarn.lock
|
||||
|
||||
.VSCodeCounter
|
||||
|
||||
.temp
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"ignorePatterns": ["src/typings/components.d.ts", "src/typings/elegant-router.d.ts", "src/router/elegant"],
|
||||
"printWidth": 120,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "none",
|
||||
"arrowParens": "avoid",
|
||||
"htmlWhitespaceSensitivity": "ignore",
|
||||
"experimentalSortPackageJson": {
|
||||
"sortScripts": true
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
{
|
||||
"categories": {
|
||||
"correctness": "error",
|
||||
"suspicious": "error"
|
||||
},
|
||||
"plugins": ["eslint", "typescript", "unicorn", "oxc", "import", "vue"],
|
||||
"rules": {
|
||||
"import/no-unassigned-import": "off",
|
||||
"unicorn/consistent-function-scoping": "off",
|
||||
"unicorn/no-array-sort": "off",
|
||||
"unicorn/no-array-reverse": "off",
|
||||
"unicorn/require-module-specifiers": "off"
|
||||
}
|
||||
}
|
||||
19
.vscode/settings.json
vendored
19
.vscode/settings.json
vendored
@@ -1,11 +1,21 @@
|
||||
{
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll.eslint": "explicit",
|
||||
"source.fixAll.oxc": "explicit"
|
||||
"source.organizeImports": "never"
|
||||
},
|
||||
"editor.defaultFormatter": "oxc.oxc-vscode",
|
||||
"editor.formatOnSave": true,
|
||||
"eslint.validate": ["vue"],
|
||||
"editor.formatOnSave": false,
|
||||
"eslint.validate": [
|
||||
"html",
|
||||
"css",
|
||||
"scss",
|
||||
"json",
|
||||
"jsonc",
|
||||
"javascript",
|
||||
"javascriptreact",
|
||||
"typescript",
|
||||
"typescriptreact",
|
||||
"vue"
|
||||
],
|
||||
"i18n-ally.displayLanguage": "zh-cn",
|
||||
"i18n-ally.enabledParsers": ["ts"],
|
||||
"i18n-ally.enabledFrameworks": ["vue"],
|
||||
@@ -16,5 +26,6 @@
|
||||
"moduleResolution": "node"
|
||||
},
|
||||
"prettier.enable": false,
|
||||
"typescript.tsdk": "node_modules/typescript/lib",
|
||||
"unocss.root": ["./"]
|
||||
}
|
||||
|
||||
71
CHANGELOG.md
71
CHANGELOG.md
@@ -1,60 +1,5 @@
|
||||
# Changelog
|
||||
|
||||
## [v2.1.0](https://github.com/soybeanjs/soybean-admin/compare/v2.0.2...v2.1.0) (2026-03-09)
|
||||
|
||||
### 🚨 Breaking Changes
|
||||
|
||||
- **projects**: integrate oxlint and oxfmt - by **soybeanfe** [<samp>(6ff74)</samp>](https://github.com/soybeanjs/soybean-admin/commit/6ff74c0c)
|
||||
|
||||
### 🚀 Features
|
||||
|
||||
- **components**:
|
||||
- Column settings support fixed columns. - by @m-xlsea [<samp>(70658)</samp>](https://github.com/soybeanjs/soybean-admin/commit/70658643)
|
||||
- Add “Select All” to TableColumnSetting - by @wenyuanw [<samp>(0081b)</samp>](https://github.com/soybeanjs/soybean-admin/commit/0081b9c0)
|
||||
- **logo**:
|
||||
- use new logo - by @soybeanjs [<samp>(5aac5)</samp>](https://github.com/soybeanjs/soybean-admin/commit/5aac540a)
|
||||
- **projects**:
|
||||
- add the plugin: vite-plugin-vue-transition-root-validator, to optimize the development experience. - by **Azir-11** [<samp>(30e3c)</samp>](https://github.com/soybeanjs/soybean-admin/commit/30e3cdc7)
|
||||
- **types**:
|
||||
- Added type definition `force` to router push options. - by @m-xlsea [<samp>(a3794)</samp>](https://github.com/soybeanjs/soybean-admin/commit/a37949f2)
|
||||
- **workflows**:
|
||||
- add opencode workflow for issue and PR comment triggers - by @soybeanjs [<samp>(dacee)</samp>](https://github.com/soybeanjs/soybean-admin/commit/dacee143)
|
||||
|
||||
### 🐞 Bug Fixes
|
||||
|
||||
- **projects**:
|
||||
- fix the long list TableColumnSetting component exceeds the viewport. - by **skyfeiz** [<samp>(cbfb9)</samp>](https://github.com/soybeanjs/soybean-admin/commit/cbfb932f)
|
||||
- fix NButton props conflicts. - by **skyfeiz** [<samp>(54107)</samp>](https://github.com/soybeanjs/soybean-admin/commit/54107aca)
|
||||
- ensure HTML lang attribute is updated when setting locale - by @pan0xc [<samp>(f96c3)</samp>](https://github.com/soybeanjs/soybean-admin/commit/f96c3c9e)
|
||||
- correct HTML lang attribute to standard format - by @pan0xc [<samp>(b520d)</samp>](https://github.com/soybeanjs/soybean-admin/commit/b520db3e)
|
||||
- **router**:
|
||||
- simplify route guard logic and remove unnecessary next calls - by **soybeanfe** [<samp>(3c2cb)</samp>](https://github.com/soybeanjs/soybean-admin/commit/3c2cbb74)
|
||||
|
||||
### 🛠 Optimizations
|
||||
|
||||
- **projects**:
|
||||
- modify the injection location of the token. - by **Azir-11** [<samp>(9d48c)</samp>](https://github.com/soybeanjs/soybean-admin/commit/9d48ca5f)
|
||||
- optimize unocss config - by **soybeanfe** [<samp>(6fc6f)</samp>](https://github.com/soybeanjs/soybean-admin/commit/6fc6f1c9)
|
||||
|
||||
### 📖 Documentation
|
||||
|
||||
- **projects**: V2 has been released. - by **skyfeiz** [<samp>(d7394)</samp>](https://github.com/soybeanjs/soybean-admin/commit/d73947a5)
|
||||
|
||||
### 🏡 Chore
|
||||
|
||||
- **deps**:
|
||||
- update deps - by @soybeanjs [<samp>(232e1)</samp>](https://github.com/soybeanjs/soybean-admin/commit/232e1ac4)
|
||||
- update deps - by @soybeanjs [<samp>(2a023)</samp>](https://github.com/soybeanjs/soybean-admin/commit/2a0231da)
|
||||
- update deps - by **soybeanfe** [<samp>(b867c)</samp>](https://github.com/soybeanjs/soybean-admin/commit/b867c290)
|
||||
|
||||
### 🎨 Styles
|
||||
|
||||
- **projects**: fix lint code and format code - by **soybeanfe** [<samp>(781a1)</samp>](https://github.com/soybeanjs/soybean-admin/commit/781a18f4)
|
||||
|
||||
### ❤️ Contributors
|
||||
|
||||
[](https://github.com/pan0xc) [](https://github.com/m-xlsea) [](https://github.com/soybeanjs) [](https://github.com/wenyuanw)
|
||||
[soybeanfe](mailto:honghuangdc@gmail.com), [Azir-11](mailto:2075125282@qq.com), [skyfeiz](mailto:webzhangfei@163.com),
|
||||
|
||||
## [v2.0.2](https://github.com/soybeanjs/soybean-admin/compare/v2.0.1...v2.0.2) (2025-12-23)
|
||||
|
||||
@@ -80,7 +25,7 @@
|
||||
- update QQ group image in README - by @soybeanjs [<samp>(46081)</samp>](https://github.com/soybeanjs/soybean-admin/commit/46081c36)
|
||||
- **projects**:
|
||||
- support theme presets to only set partial content. - by **Azir-11** [<samp>(9da84)</samp>](https://github.com/soybeanjs/soybean-admin/commit/9da847fb)
|
||||
- support theme perset to override component library presets. - by **Azir-11** [<samp>(60517)</samp>](https://github.com/soybeanjs/soybean-admin/commit/605173a1)
|
||||
- support theme perset to override component library presets. - by **Azir-11** [<samp>(60517)</samp>](https://github.com/soybeanjs/soybean-admin/commit/605173a1)
|
||||
- support pinning and unpinning of tabs - by **hooke** [<samp>(b8a76)</samp>](https://github.com/soybeanjs/soybean-admin/commit/b8a767d7)
|
||||
- hybrid layout mode auto select first deepest child menu - by @paynezhuang [<samp>(94019)</samp>](https://github.com/soybeanjs/soybean-admin/commit/9401925f)
|
||||
|
||||
@@ -480,13 +425,13 @@
|
||||
### 🏡 Chore
|
||||
|
||||
- **deps**:
|
||||
- add vscode recommend plugin close #738 - by @tu6ge in https://github.com/soybeanjs/soybean-admin/issues/739 and https://github.com/soybeanjs/soybean-admin/issues/738 [<samp>(61244)</samp>](https://github.com/soybeanjs/soybean-admin/commit/61244f0f)
|
||||
- add vscode recommend plugin close #738 - by @tu6ge in https://github.com/soybeanjs/soybean-admin/issues/739 and https://github.com/soybeanjs/soybean-admin/issues/738 [<samp>(61244)</samp>](https://github.com/soybeanjs/soybean-admin/commit/61244f0f)
|
||||
- update deps - by @soybeanjs [<samp>(41b5f)</samp>](https://github.com/soybeanjs/soybean-admin/commit/41b5f493)
|
||||
- update deps - by @soybeanjs [<samp>(3e4e1)</samp>](https://github.com/soybeanjs/soybean-admin/commit/3e4e17ab)
|
||||
|
||||
### 🤖 CI
|
||||
|
||||
- **hooks**: remove lint-staged in git hook. close #724 - by @Azir-11 in https://github.com/soybeanjs/soybean-admin/issues/743 and https://github.com/soybeanjs/soybean-admin/issues/724 [<samp>(c3abc)</samp>](https://github.com/soybeanjs/soybean-admin/commit/c3abc3df)
|
||||
- **hooks**: remove lint-staged in git hook. close #724 - by @Azir-11 in https://github.com/soybeanjs/soybean-admin/issues/743 and https://github.com/soybeanjs/soybean-admin/issues/724 [<samp>(c3abc)</samp>](https://github.com/soybeanjs/soybean-admin/commit/c3abc3df)
|
||||
|
||||
### ❤️ Contributors
|
||||
|
||||
@@ -606,7 +551,7 @@
|
||||
|
||||
### 📖 Documentation
|
||||
|
||||
- **projects**: ✏️ add element-plus version link - by **一寸灰** in https://github.com/honghuangdc/soybean-admin/issues/679 [<samp>(5c6ab)</samp>](https://github.com/honghuangdc/soybean-admin/commit/5c6ab0b)
|
||||
- **projects**: ✏️ add element-plus version link - by **一寸灰** in https://github.com/honghuangdc/soybean-admin/issues/679 [<samp>(5c6ab)</samp>](https://github.com/honghuangdc/soybean-admin/commit/5c6ab0b)
|
||||
|
||||
### 🏡 Chore
|
||||
|
||||
@@ -648,6 +593,7 @@
|
||||
|
||||
### ❤️ Contributors
|
||||
|
||||
|
||||
[Soybean](mailto:soybeanjs@outlook.com), [青菜白玉汤](mailto:79054161+Azir-11@users.noreply.github.com)
|
||||
|
||||
## [v1.3.8](https://github.com/soybeanjs/soybean-admin/compare/v1.3.7...v1.3.8) (2024-10-25)
|
||||
@@ -1694,7 +1640,7 @@
|
||||
- Optimize internationalized menu search code - by **燕博文** [<samp>(8c1ef)</samp>](https://github.com/soybeanjs/soybean-admin/commit/8c1ef4b)
|
||||
- Optimize menu search code - by **燕博文** [<samp>(296a2)</samp>](https://github.com/soybeanjs/soybean-admin/commit/296a2d2)
|
||||
- perf count-to - by @honghuangdc [<samp>(b2c61)</samp>](https://github.com/soybeanjs/soybean-admin/commit/b2c61f0)
|
||||
- components name is converted to uppercase - by **燕博文** [<samp>(04aa1)</samp>](https://github.com/soybeanjs/soybean-admin/commit/04aa10b)
|
||||
- components name is converted to uppercase - by **燕博文** [<samp>(04aa1)</samp>](https://github.com/soybeanjs/soybean-admin/commit/04aa10b)
|
||||
- perf global-search - by @honghuangdc [<samp>(72745)</samp>](https://github.com/soybeanjs/soybean-admin/commit/7274522)
|
||||
- **projects**:
|
||||
- perf code - by @honghuangdc [<samp>(8081e)</samp>](https://github.com/soybeanjs/soybean-admin/commit/8081e19)
|
||||
@@ -1971,7 +1917,7 @@
|
||||
- Optimize internationalized menu search code - by **燕博文** [<samp>(8c1ef)</samp>](https://github.com/soybeanjs/soybean-admin/commit/8c1ef4b)
|
||||
- Optimize menu search code - by **燕博文** [<samp>(296a2)</samp>](https://github.com/soybeanjs/soybean-admin/commit/296a2d2)
|
||||
- perf count-to - by @honghuangdc [<samp>(b2c61)</samp>](https://github.com/soybeanjs/soybean-admin/commit/b2c61f0)
|
||||
- components name is converted to uppercase - by **燕博文** [<samp>(04aa1)</samp>](https://github.com/soybeanjs/soybean-admin/commit/04aa10b)
|
||||
- components name is converted to uppercase - by **燕博文** [<samp>(04aa1)</samp>](https://github.com/soybeanjs/soybean-admin/commit/04aa10b)
|
||||
- perf global-search - by @honghuangdc [<samp>(72745)</samp>](https://github.com/soybeanjs/soybean-admin/commit/7274522)
|
||||
- **projects**:
|
||||
- perf code - by @honghuangdc [<samp>(8081e)</samp>](https://github.com/soybeanjs/soybean-admin/commit/8081e19)
|
||||
@@ -3366,3 +3312,6 @@
|
||||
### ❤️ Contributors
|
||||
|
||||
[](https://github.com/honghuangdc) [](https://github.com/soybeanjs)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -143,6 +143,7 @@
|
||||
[](https://github.com/honghuangdc) [](https://github.com/Azir-11)
|
||||
[Azir](mailto:2075125282@qq.com),
|
||||
|
||||
|
||||
## [v1.3.0](https://github.com/soybeanjs/soybean-admin/compare/v1.2.8...v1.3.0) (2024-07-22)
|
||||
|
||||
### 🚨 破坏性变更
|
||||
@@ -181,6 +182,7 @@
|
||||
|
||||
[](https://github.com/honghuangdc) [](https://github.com/mmdapl) [](https://github.com/Azir-11)
|
||||
|
||||
|
||||
## [v1.2.8](https://github.com/soybeanjs/soybean-admin/compare/v1.2.7...v1.2.8) (2024-07-20)
|
||||
|
||||
### 🐞 修复
|
||||
@@ -208,6 +210,7 @@
|
||||
[](https://github.com/honghuangdc)
|
||||
[dodu2014](mailto:dodu@live.cn)
|
||||
|
||||
|
||||
## [v1.2.7](https://github.com/honghuangdc/soybean-admin/compare/v1.2.6...v1.2.7) (2024-07-12)
|
||||
|
||||
### 🛠 优化
|
||||
@@ -291,6 +294,7 @@
|
||||
[](https://github.com/soybeanjs) [](https://github.com/Azir-11)
|
||||
[CHENZL](mailto:zlong5568863@qq.com)
|
||||
|
||||
|
||||
## [v1.2.4](https://github.com/soybeanjs/soybean-admin/compare/v1.2.3...v1.2.4) (2024-06-14)
|
||||
|
||||
### 🛠 优化
|
||||
@@ -368,6 +372,7 @@
|
||||
|
||||
[](https://github.com/soybeanjs)
|
||||
|
||||
|
||||
## [v1.2.0](https://github.com/soybeanjs/soybean-admin/compare/v1.1.5...v1.2.0) (2024-06-06)
|
||||
|
||||
### 🚀 功能
|
||||
@@ -588,6 +593,7 @@
|
||||
[](https://github.com/honghuangdc)
|
||||
[paynezhuang](mailto:paynezhuang@gmail.com)
|
||||
|
||||
|
||||
## [v1.1.0-beta.1](https://github.com/soybeanjs/soybean-admin/compare/v1.0.9...v1.1.0-beta.1) (2024-05-07)
|
||||
|
||||
### 🚀 功能
|
||||
|
||||
@@ -23,10 +23,14 @@
|
||||
> [!NOTE]
|
||||
> The `SoybeanAdmin` quick start series videos have been uploaded to [Bilibili](https://www.bilibili.com/video/BV1YKdRYXELC) Go online [click here](https://www.bilibili.com/video/BV1YKdRYXELC) Go check it out
|
||||
|
||||
> [!WARNING]
|
||||
> `SoybeanAdmin` is planning to develop a `V2` version, see [plan list](https://github.com/soybeanjs/soybean-admin/issues/767)
|
||||
|
||||
## Introduction
|
||||
|
||||
[`SoybeanAdmin`](https://github.com/soybeanjs/soybean-admin) is a clean, elegant, beautiful and powerful admin template, based on the latest front-end technology stack, including Vue3, Vite7, TypeScript, Pinia and UnoCSS. It has built-in rich theme configuration and components, strict code specifications, and an automated file routing system. In addition, it also uses the online mock data solution based on ApiFox. `SoybeanAdmin` provides you with a one-stop admin solution, no additional configuration, and out of the box. It is also a best practice for learning cutting-edge technologies quickly.
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
- **Cutting-edge technology application**: using the latest popular technology stack such as Vue3, Vite7, TypeScript, Pinia and UnoCSS.
|
||||
@@ -41,6 +45,7 @@
|
||||
- **Command line tool**: built-in efficient command line tool, git commit, delete file, release, etc.
|
||||
- **Mobile adaptation**: perfectly support mobile terminal to realize adaptive layout.
|
||||
|
||||
|
||||
## Version
|
||||
|
||||
- **NaiveUI Version:**
|
||||
@@ -67,6 +72,7 @@
|
||||
- [Gitee Repository](https://gitee.com/honghuangdc/soybean-admin/tree/legacy)
|
||||
- [Gitcode Repository](https://gitcode.com/soybeanjs/soybean-admin/tree/legacy)
|
||||
|
||||
|
||||
## Documentation
|
||||
|
||||
- [Link](https://docs.soybeanjs.cn)
|
||||
@@ -86,6 +92,7 @@
|
||||

|
||||

|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
**Environment Preparation**
|
||||
@@ -112,7 +119,6 @@ git clone https://gitcode.com/soybeanjs/soybean-admin.git
|
||||
```bash
|
||||
pnpm i
|
||||
```
|
||||
|
||||
> Since this project uses the pnpm monorepo management method, please do not use npm or yarn to install dependencies.
|
||||
|
||||
**Start Project**
|
||||
@@ -147,6 +153,7 @@ Refer to the [Code Synchronization](https://docs.soybeanjs.cn/guide/sync) docume
|
||||
|
||||
More ecosystem please refer to [Ecosystem](https://docs.soybeanjs.cn/awesome) document.
|
||||
|
||||
|
||||
## How to Contribute
|
||||
|
||||
We warmly welcome and appreciate all forms of contributions. If you have any ideas or suggestions, please feel free to share them by submitting [pull requests](https://github.com/soybeanjs/soybean-admin/pulls) or creating GitHub [issue](https://github.com/soybeanjs/soybean-admin/issues/new).
|
||||
@@ -160,8 +167,8 @@ This project has built-in `commit` command, you can execute `pnpm commit` to gen
|
||||
It is recommended to use the latest version of Chrome in development for a better experience.
|
||||
|
||||
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/archive/internet-explorer_9-11/internet-explorer_9-11_48x48.png" alt="IE" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/) | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt=" Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/) | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/) | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/) | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/) |
|
||||
| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| not support | last 2 versions | last 2 versions | last 2 versions | last 2 versions |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| not support | last 2 versions | last 2 versions | last 2 versions | last 2 versions |
|
||||
|
||||
## OpenSource Author
|
||||
|
||||
|
||||
20
README.md
20
README.md
@@ -23,6 +23,9 @@
|
||||
> [!NOTE]
|
||||
> `SoybeanAdmin` 快速上手系列视频已在 [Bilibili](https://www.bilibili.com/video/BV1YKdRYXELC) 上线 [点击这里](https://www.bilibili.com/video/BV1YKdRYXELC) 前往查看
|
||||
|
||||
> [!WARNING]
|
||||
> `SoybeanAdmin` 正在计划开发 `V2` 版本,详情见[计划清单](https://github.com/soybeanjs/soybean-admin/issues/767)
|
||||
|
||||
## 简介
|
||||
|
||||
[`SoybeanAdmin`](https://github.com/soybeanjs/soybean-admin) 是一个清新优雅、高颜值且功能强大的后台管理模板,基于最新的前端技术栈,包括 Vue3, Vite7, TypeScript, Pinia 和 UnoCSS。它内置了丰富的主题配置和组件,代码规范严谨,实现了自动化的文件路由系统。此外,它还采用了基于 ApiFox 的在线Mock数据方案。`SoybeanAdmin` 为您提供了一站式的后台管理解决方案,无需额外配置,开箱即用。同样是一个快速学习前沿技术的最佳实践。
|
||||
@@ -41,6 +44,7 @@
|
||||
- **命令行工具**:内置高效的命令行工具,git提交、删除文件、发布等。
|
||||
- **移动端适配**:完美支持移动端,实现自适应布局。
|
||||
|
||||
|
||||
## 版本
|
||||
|
||||
- **NaiveUI 版本:**
|
||||
@@ -64,11 +68,13 @@
|
||||
- [Gitee 仓库](https://gitee.com/honghuangdc/soybean-admin/tree/legacy)
|
||||
- [Gitcode 仓库](https://gitcode.com/soybeanjs/soybean-admin/tree/legacy)
|
||||
|
||||
|
||||
## 文档
|
||||
|
||||
- [地址](https://docs.soybeanjs.cn)
|
||||
- [旧版文档](https://legacy-docs.soybeanjs.cn)
|
||||
|
||||
|
||||
## 合作事项
|
||||
|
||||
我们非常感谢大家对 [`SoybeanAdmin`](https://github.com/soybeanjs/soybean-admin) 的支持!为了进一步回馈社区,并助力企业和开发者实现个性化需求,我们现提供多种合作服务,期待与您携手共赢。
|
||||
@@ -93,10 +99,11 @@
|
||||
|
||||
- **Email**: [soybeanjs@outlook.com](mailto:soybeanjs@outlook.com)
|
||||
- **GitHub Issues**: 欢迎通过 [GitHub Issues](https://github.com/soybeanjs/soybean-admin/issues/new) 联系我们,进行初步的合作洽谈。
|
||||
- **商务合作微信**: honghuangdc
|
||||
- **商务合作微信**: honghuangdc
|
||||
|
||||
期待与您开展深入合作,共同推动 SoybeanAdmin 项目及其在更多领域的成功应用!
|
||||
|
||||
|
||||
## 示例图片
|
||||
|
||||

|
||||
@@ -111,6 +118,7 @@
|
||||

|
||||

|
||||
|
||||
|
||||
## 使用
|
||||
|
||||
**环境准备**
|
||||
@@ -137,7 +145,6 @@ git clone https://gitcode.com/soybeanjs/soybean-admin.git
|
||||
```bash
|
||||
pnpm i
|
||||
```
|
||||
|
||||
> 由于本项目采用了 pnpm monorepo 的管理方式,因此请不要使用 npm 或 yarn 来安装依赖。
|
||||
|
||||
**启动项目**
|
||||
@@ -172,26 +179,29 @@ pnpm build
|
||||
|
||||
更多周边生态请翻阅 [周边生态](https://docs.soybeanjs.cn/zh/awesome) 文档。
|
||||
|
||||
|
||||
## 如何贡献
|
||||
|
||||
我们热烈欢迎并感谢所有形式的贡献。如果您有任何想法或建议,欢迎通过提交 [pull requests](https://github.com/soybeanjs/soybean-admin/pulls) 或创建 GitHub [issue](https://github.com/soybeanjs/soybean-admin/issues/new) 来分享。
|
||||
|
||||
## Git 提交规范
|
||||
|
||||
本项目已内置 `commit` 命令,您可以通过执行 `pnpm commit` 来生成符合 [Conventional Commits](<[conventionalcommits](https://www.conventionalcommits.org/)>) 规范的提交信息。在提交PR时,请务必使用 `commit` 命令来创建提交信息,以确保信息的规范性。
|
||||
本项目已内置 `commit` 命令,您可以通过执行 `pnpm commit` 来生成符合 [Conventional Commits]([conventionalcommits](https://www.conventionalcommits.org/)) 规范的提交信息。在提交PR时,请务必使用 `commit` 命令来创建提交信息,以确保信息的规范性。
|
||||
|
||||
|
||||
## 浏览器支持
|
||||
|
||||
推荐使用最新版的 Chrome 浏览器进行开发,以获得更好的体验。
|
||||
|
||||
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/archive/internet-explorer_9-11/internet-explorer_9-11_48x48.png" alt="IE" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/) | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt=" Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/) | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/) | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/) | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/) |
|
||||
| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| not support | last 2 versions | last 2 versions | last 2 versions | last 2 versions |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| not support | last 2 versions | last 2 versions | last 2 versions | last 2 versions |
|
||||
|
||||
## 开源作者
|
||||
|
||||
[Soybean](https://github.com/honghuangdc)
|
||||
|
||||
|
||||
## 贡献者
|
||||
|
||||
感谢以下贡献者的贡献。如果您想为本项目做出贡献,请参考 [如何贡献](#如何贡献)。
|
||||
|
||||
@@ -2,8 +2,7 @@ import type { PluginOption } from 'vite';
|
||||
import vue from '@vitejs/plugin-vue';
|
||||
import vueJsx from '@vitejs/plugin-vue-jsx';
|
||||
import progress from 'vite-plugin-progress';
|
||||
import vueRootValidator from 'vite-plugin-vue-transition-root-validator';
|
||||
import { setupElegantRouter } from './router';
|
||||
import elegantRouter from 'elegant-router/vite';
|
||||
import { setupUnocss } from './unocss';
|
||||
import { setupUnplugin } from './unplugin';
|
||||
import { setupHtmlPlugin } from './html';
|
||||
@@ -14,12 +13,11 @@ export function setupVitePlugins(viteEnv: Env.ImportMeta, buildTime: string) {
|
||||
vue(),
|
||||
vueJsx(),
|
||||
setupDevtoolsPlugin(viteEnv),
|
||||
setupElegantRouter(),
|
||||
elegantRouter(),
|
||||
setupUnocss(viteEnv),
|
||||
...setupUnplugin(viteEnv),
|
||||
progress(),
|
||||
setupHtmlPlugin(buildTime),
|
||||
vueRootValidator()
|
||||
setupHtmlPlugin(buildTime)
|
||||
];
|
||||
|
||||
return plugins;
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
import type { RouteMeta } from 'vue-router';
|
||||
import ElegantVueRouter from '@elegant-router/vue/vite';
|
||||
import type { RouteKey } from '@elegant-router/types';
|
||||
|
||||
export function setupElegantRouter() {
|
||||
return ElegantVueRouter({
|
||||
layouts: {
|
||||
base: 'src/layouts/base-layout/index.vue',
|
||||
blank: 'src/layouts/blank-layout/index.vue'
|
||||
},
|
||||
routePathTransformer(routeName, routePath) {
|
||||
const key = routeName as RouteKey;
|
||||
|
||||
if (key === 'login') {
|
||||
const modules: UnionKey.LoginModule[] = ['pwd-login', 'code-login', 'register', 'reset-pwd', 'bind-wechat'];
|
||||
|
||||
const moduleReg = modules.join('|');
|
||||
|
||||
return `/login/:module(${moduleReg})?`;
|
||||
}
|
||||
|
||||
return routePath;
|
||||
},
|
||||
onRouteMetaGen(routeName) {
|
||||
const key = routeName as RouteKey;
|
||||
|
||||
const constantRoutes: RouteKey[] = ['login', '403', '404', '500'];
|
||||
|
||||
const meta: Partial<RouteMeta> = {
|
||||
title: key,
|
||||
i18nKey: `route.${key}` as App.I18n.I18nKey
|
||||
};
|
||||
|
||||
if (constantRoutes.includes(key)) {
|
||||
meta.constant = true;
|
||||
}
|
||||
|
||||
return meta;
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import process from 'node:process';
|
||||
import path from 'node:path';
|
||||
import { presetIcons } from 'unocss';
|
||||
import unocss from 'unocss/vite';
|
||||
import unocss from '@unocss/vite';
|
||||
import presetIcons from '@unocss/preset-icons';
|
||||
import { FileSystemIconLoader } from '@iconify/utils/lib/loader/node-loaders';
|
||||
|
||||
export function setupUnocss(viteEnv: Env.ImportMeta) {
|
||||
|
||||
37
er.config.ts
Normal file
37
er.config.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import type { RouteMeta } from 'vue-router';
|
||||
import { defineConfig } from 'elegant-router';
|
||||
import type { RouteKey } from '@elegant-router/types';
|
||||
|
||||
export default defineConfig({
|
||||
pageDir: ['src/views'],
|
||||
layouts: {
|
||||
base: 'src/layouts/base-layout/index.vue',
|
||||
blank: 'src/layouts/blank-layout/index.vue'
|
||||
},
|
||||
getRoutePath: node => {
|
||||
if (node.name === 'Login') {
|
||||
const modules: UnionKey.LoginModule[] = ['pwd-login', 'code-login', 'register', 'reset-pwd', 'bind-wechat'];
|
||||
|
||||
const moduleReg = modules.join('|');
|
||||
|
||||
return `/login/:module(${moduleReg})?`;
|
||||
}
|
||||
|
||||
return node.path;
|
||||
},
|
||||
getRouteMeta: node => {
|
||||
const constantRoutes: RouteKey[] = ['Login', '403', '404', '500'];
|
||||
|
||||
const name = node.name as RouteKey;
|
||||
|
||||
const meta: Partial<RouteMeta> = {
|
||||
title: name
|
||||
};
|
||||
|
||||
if (constantRoutes.includes(name)) {
|
||||
meta.constant = true;
|
||||
}
|
||||
|
||||
return meta;
|
||||
}
|
||||
});
|
||||
@@ -1,12 +1,24 @@
|
||||
import { defineConfig } from '@soybeanjs/eslint-config-vue';
|
||||
import { defineConfig } from '@soybeanjs/eslint-config';
|
||||
|
||||
export default defineConfig({
|
||||
'vue/component-name-in-template-casing': [
|
||||
'warn',
|
||||
'PascalCase',
|
||||
{
|
||||
registeredComponentsOnly: false,
|
||||
ignores: ['/^icon-/']
|
||||
export default defineConfig(
|
||||
{ vue: true, unocss: true },
|
||||
{
|
||||
rules: {
|
||||
'vue/multi-word-component-names': [
|
||||
'warn',
|
||||
{
|
||||
ignores: ['index', 'App', 'Register', '[id]', '[url]']
|
||||
}
|
||||
],
|
||||
'vue/component-name-in-template-casing': [
|
||||
'warn',
|
||||
'PascalCase',
|
||||
{
|
||||
registeredComponentsOnly: false,
|
||||
ignores: ['/^icon-/']
|
||||
}
|
||||
],
|
||||
'unocss/order-attributify': 'off'
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<html lang="zh-cmn-Hans">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" href="/favicon.svg" />
|
||||
|
||||
98
package.json
98
package.json
@@ -1,31 +1,35 @@
|
||||
{
|
||||
"name": "soybean-admin",
|
||||
"version": "2.1.0",
|
||||
"type": "module",
|
||||
"version": "2.0.2",
|
||||
"description": "A fresh and elegant admin template, based on Vue3、Vite7、TypeScript、NaiveUI and UnoCSS. 一个基于Vue3、Vite7、TypeScript、NaiveUI and UnoCSS的清新优雅的中后台模版。",
|
||||
"keywords": [
|
||||
"TypeScript",
|
||||
"UnoCSS",
|
||||
"Vite7",
|
||||
"Vue3 admin ",
|
||||
"ant-design-vue v4",
|
||||
"naive-ui",
|
||||
"naive-ui-admin",
|
||||
"vue-admin-template"
|
||||
],
|
||||
"homepage": "https://github.com/soybeanjs/soybean-admin",
|
||||
"bugs": {
|
||||
"url": "https://github.com/soybeanjs/soybean-admin/issues"
|
||||
},
|
||||
"license": "MIT",
|
||||
"author": {
|
||||
"name": "Soybean",
|
||||
"email": "soybeanjs@outlook.com",
|
||||
"url": "https://github.com/soybeanjs"
|
||||
},
|
||||
"license": "MIT",
|
||||
"homepage": "https://github.com/soybeanjs/soybean-admin",
|
||||
"repository": {
|
||||
"url": "https://github.com/soybeanjs/soybean-admin.git"
|
||||
},
|
||||
"type": "module",
|
||||
"bugs": {
|
||||
"url": "https://github.com/soybeanjs/soybean-admin/issues"
|
||||
},
|
||||
"keywords": [
|
||||
"Vue3 admin ",
|
||||
"vue-admin-template",
|
||||
"Vite7",
|
||||
"TypeScript",
|
||||
"naive-ui",
|
||||
"naive-ui-admin",
|
||||
"ant-design-vue v4",
|
||||
"UnoCSS"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=20.19.0",
|
||||
"pnpm": ">=10.5.0"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "vite build --mode prod",
|
||||
"build:test": "vite build --mode test",
|
||||
@@ -34,9 +38,8 @@
|
||||
"commit:zh": "sa git-commit -l=zh-cn",
|
||||
"dev": "vite --mode test",
|
||||
"dev:prod": "vite --mode prod",
|
||||
"fmt": "oxfmt",
|
||||
"gen-route": "sa gen-route",
|
||||
"lint": "oxlint --fix && eslint --fix .",
|
||||
"lint": "eslint . --fix",
|
||||
"prepare": "simple-git-hooks",
|
||||
"preview": "vite preview",
|
||||
"release": "sa release",
|
||||
@@ -51,57 +54,58 @@
|
||||
"@sa/hooks": "workspace:*",
|
||||
"@sa/materials": "workspace:*",
|
||||
"@sa/utils": "workspace:*",
|
||||
"@vueuse/core": "14.2.1",
|
||||
"@vueuse/core": "14.1.0",
|
||||
"clipboard": "2.0.11",
|
||||
"dayjs": "1.11.19",
|
||||
"defu": "6.1.4",
|
||||
"echarts": "6.0.0",
|
||||
"json5": "2.2.3",
|
||||
"naive-ui": "2.44.1",
|
||||
"naive-ui": "2.43.2",
|
||||
"nprogress": "0.2.0",
|
||||
"pinia": "3.0.4",
|
||||
"tailwind-merge": "3.5.0",
|
||||
"vue": "3.5.29",
|
||||
"vue-draggable-plus": "0.6.1",
|
||||
"vue-i18n": "11.3.0",
|
||||
"vue-router": "5.0.3"
|
||||
"tailwind-merge": "3.4.0",
|
||||
"vue": "3.5.26",
|
||||
"vue-draggable-plus": "0.6.0",
|
||||
"vue-i18n": "11.2.7",
|
||||
"vue-router": "4.6.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@elegant-router/vue": "0.3.8",
|
||||
"@iconify/json": "2.2.447",
|
||||
"@iconify/json": "2.2.417",
|
||||
"@sa/scripts": "workspace:*",
|
||||
"@sa/uno-preset": "workspace:*",
|
||||
"@soybeanjs/eslint-config-vue": "^0.0.2",
|
||||
"@types/node": "25.3.5",
|
||||
"@soybeanjs/eslint-config": "1.7.4",
|
||||
"@types/node": "25.0.3",
|
||||
"@types/nprogress": "0.2.3",
|
||||
"@vitejs/plugin-vue": "6.0.4",
|
||||
"@vitejs/plugin-vue-jsx": "5.1.4",
|
||||
"@unocss/eslint-config": "66.5.10",
|
||||
"@unocss/preset-icons": "66.5.10",
|
||||
"@unocss/preset-uno": "66.5.10",
|
||||
"@unocss/transformer-directives": "66.5.10",
|
||||
"@unocss/transformer-variant-group": "66.5.10",
|
||||
"@unocss/vite": "66.5.10",
|
||||
"@vitejs/plugin-vue": "6.0.3",
|
||||
"@vitejs/plugin-vue-jsx": "5.1.2",
|
||||
"consola": "3.4.2",
|
||||
"eslint": "10.0.3",
|
||||
"elegant-router": "1.1.0",
|
||||
"eslint": "9.39.2",
|
||||
"eslint-plugin-vue": "10.6.2",
|
||||
"kolorist": "1.8.0",
|
||||
"oxfmt": "^0.36.0",
|
||||
"oxlint": "^1.51.0",
|
||||
"sass": "1.97.3",
|
||||
"sass": "1.97.1",
|
||||
"simple-git-hooks": "2.13.1",
|
||||
"tsx": "4.21.0",
|
||||
"typescript": "5.9.3",
|
||||
"unocss": "^66.6.6",
|
||||
"unplugin-icons": "23.0.1",
|
||||
"unplugin-vue-components": "31.0.0",
|
||||
"vite": "7.3.1",
|
||||
"unplugin-icons": "22.5.0",
|
||||
"unplugin-vue-components": "30.0.0",
|
||||
"vite": "7.3.0",
|
||||
"vite-plugin-progress": "0.0.7",
|
||||
"vite-plugin-svg-icons": "2.0.1",
|
||||
"vite-plugin-vue-devtools": "8.0.7",
|
||||
"vite-plugin-vue-transition-root-validator": "^0.1.0",
|
||||
"vue-tsc": "3.2.5"
|
||||
"vite-plugin-vue-devtools": "8.0.5",
|
||||
"vue-eslint-parser": "10.2.0",
|
||||
"vue-tsc": "3.2.1"
|
||||
},
|
||||
"simple-git-hooks": {
|
||||
"commit-msg": "pnpm sa git-commit-verify",
|
||||
"pre-commit": "pnpm typecheck && pnpm lint && pnpm fmt && git diff --exit-code"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.19.0",
|
||||
"pnpm": ">=10.5.0"
|
||||
"pre-commit": "pnpm typecheck && pnpm lint && git diff --exit-code"
|
||||
},
|
||||
"website": "https://admin.soybeanjs.cn"
|
||||
}
|
||||
|
||||
@@ -1,22 +1,20 @@
|
||||
{
|
||||
"name": "@sa/alova",
|
||||
"version": "2.1.0",
|
||||
"typesVersions": {
|
||||
"*": {
|
||||
"*": [
|
||||
"./src/*"
|
||||
]
|
||||
}
|
||||
},
|
||||
"version": "2.0.2",
|
||||
"exports": {
|
||||
".": "./src/index.ts",
|
||||
"./fetch": "./src/fetch.ts",
|
||||
"./client": "./src/client.ts",
|
||||
"./mock": "./src/mock.ts"
|
||||
},
|
||||
"typesVersions": {
|
||||
"*": {
|
||||
"*": ["./src/*"]
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@alova/mock": "2.0.19",
|
||||
"@alova/mock": "2.0.18",
|
||||
"@sa/utils": "workspace:*",
|
||||
"alova": "3.5.1"
|
||||
"alova": "3.4.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,23 +1,21 @@
|
||||
{
|
||||
"name": "@sa/axios",
|
||||
"version": "2.1.0",
|
||||
"typesVersions": {
|
||||
"*": {
|
||||
"*": [
|
||||
"./src/*"
|
||||
]
|
||||
}
|
||||
},
|
||||
"version": "2.0.2",
|
||||
"exports": {
|
||||
".": "./src/index.ts"
|
||||
},
|
||||
"typesVersions": {
|
||||
"*": {
|
||||
"*": ["./src/*"]
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@sa/utils": "workspace:*",
|
||||
"axios": "1.13.6",
|
||||
"axios": "1.13.2",
|
||||
"axios-retry": "4.5.0",
|
||||
"qs": "6.15.0"
|
||||
"qs": "6.14.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/qs": "6.15.0"
|
||||
"@types/qs": "6.14.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
{
|
||||
"name": "@sa/color",
|
||||
"version": "2.1.0",
|
||||
"typesVersions": {
|
||||
"*": {
|
||||
"*": [
|
||||
"./src/*"
|
||||
]
|
||||
}
|
||||
},
|
||||
"version": "2.0.2",
|
||||
"exports": {
|
||||
".": "./src/index.ts"
|
||||
},
|
||||
"typesVersions": {
|
||||
"*": {
|
||||
"*": ["./src/*"]
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@sa/utils": "workspace:*",
|
||||
"colord": "2.9.3"
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
{
|
||||
"name": "@sa/hooks",
|
||||
"version": "2.1.0",
|
||||
"typesVersions": {
|
||||
"*": {
|
||||
"*": [
|
||||
"./src/*"
|
||||
]
|
||||
}
|
||||
},
|
||||
"version": "2.0.2",
|
||||
"exports": {
|
||||
".": "./src/index.ts"
|
||||
},
|
||||
"typesVersions": {
|
||||
"*": {
|
||||
"*": ["./src/*"]
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@sa/axios": "workspace:*",
|
||||
"@sa/utils": "workspace:*"
|
||||
|
||||
@@ -23,7 +23,6 @@ export type TableColumnCheck = {
|
||||
title: TableColumnCheckTitle;
|
||||
checked: boolean;
|
||||
visible: boolean;
|
||||
fixed: 'left' | 'right' | 'unFixed';
|
||||
};
|
||||
|
||||
export interface UseTableOptions<ResponseData, ApiData, Column, Pagination extends boolean> {
|
||||
@@ -79,14 +78,12 @@ export default function useTable<ResponseData, ApiData, Column, Pagination exten
|
||||
|
||||
function reloadColumns() {
|
||||
const checkMap = new Map(columnChecks.value.map(col => [col.key, col.checked]));
|
||||
const fixedMap = new Map(columnChecks.value.map(col => [col.key, col.fixed]));
|
||||
|
||||
const defaultChecks = getColumnChecks(columns());
|
||||
|
||||
columnChecks.value = defaultChecks.map(col => ({
|
||||
...col,
|
||||
checked: checkMap.get(col.key) ?? col.checked,
|
||||
fixed: (fixedMap.get(col.key) !== 'unFixed' ? fixedMap.get(col.key) : undefined) ?? col.fixed
|
||||
checked: checkMap.get(col.key) ?? col.checked
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
{
|
||||
"name": "@sa/materials",
|
||||
"version": "2.1.0",
|
||||
"typesVersions": {
|
||||
"*": {
|
||||
"*": [
|
||||
"./src/*"
|
||||
]
|
||||
}
|
||||
},
|
||||
"version": "2.0.2",
|
||||
"exports": {
|
||||
".": "./src/index.ts"
|
||||
},
|
||||
"typesVersions": {
|
||||
"*": {
|
||||
"*": ["./src/*"]
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@sa/utils": "workspace:*",
|
||||
"simplebar-vue": "2.4.2"
|
||||
|
||||
@@ -1,30 +1,28 @@
|
||||
{
|
||||
"name": "@sa/scripts",
|
||||
"version": "2.1.0",
|
||||
"version": "2.0.2",
|
||||
"bin": {
|
||||
"sa": "./bin.ts"
|
||||
},
|
||||
"typesVersions": {
|
||||
"*": {
|
||||
"*": [
|
||||
"./src/*"
|
||||
]
|
||||
}
|
||||
},
|
||||
"exports": {
|
||||
".": "./src/index.ts"
|
||||
},
|
||||
"typesVersions": {
|
||||
"*": {
|
||||
"*": ["./src/*"]
|
||||
}
|
||||
},
|
||||
"devDependencies": {
|
||||
"@soybeanjs/changelog": "0.4.3",
|
||||
"bumpp": "10.4.1",
|
||||
"@soybeanjs/changelog": "0.3.25",
|
||||
"bumpp": "10.3.2",
|
||||
"c12": "3.3.3",
|
||||
"cac": "6.7.14",
|
||||
"consola": "3.4.2",
|
||||
"enquirer": "2.4.1",
|
||||
"execa": "9.6.1",
|
||||
"kolorist": "1.8.0",
|
||||
"npm-check-updates": "19.6.3",
|
||||
"npm-check-updates": "19.2.0",
|
||||
"picomatch": "4.0.3",
|
||||
"rimraf": "6.1.3"
|
||||
"rimraf": "6.1.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { cac } from 'cac';
|
||||
import cac from 'cac';
|
||||
import { blue, lightGreen } from 'kolorist';
|
||||
import { version } from '../package.json';
|
||||
import { cleanup, genChangelog, generateRoute, gitCommit, gitCommitVerify, release, updatePkg } from './commands';
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
{
|
||||
"name": "@sa/uno-preset",
|
||||
"version": "2.1.0",
|
||||
"typesVersions": {
|
||||
"*": {
|
||||
"*": [
|
||||
"./src/*"
|
||||
]
|
||||
}
|
||||
},
|
||||
"version": "2.0.2",
|
||||
"exports": {
|
||||
".": "./src/index.ts"
|
||||
},
|
||||
"typesVersions": {
|
||||
"*": {
|
||||
"*": ["./src/*"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// @unocss-include
|
||||
|
||||
import type { Preset } from '@unocss/core';
|
||||
import type { Theme } from '@unocss/preset-mini';
|
||||
import type { Theme } from '@unocss/preset-uno';
|
||||
|
||||
export function presetSoybeanAdmin(): Preset<Theme> {
|
||||
const preset: Preset<Theme> = {
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
{
|
||||
"name": "@sa/utils",
|
||||
"version": "2.1.0",
|
||||
"typesVersions": {
|
||||
"*": {
|
||||
"*": [
|
||||
"./src/*"
|
||||
]
|
||||
}
|
||||
},
|
||||
"version": "2.0.2",
|
||||
"exports": {
|
||||
".": "./src/index.ts"
|
||||
},
|
||||
"typesVersions": {
|
||||
"*": {
|
||||
"*": ["./src/*"]
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"colord": "2.9.3",
|
||||
"crypto-js": "4.2.0",
|
||||
|
||||
3925
pnpm-lock.yaml
generated
3925
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -1,2 +1,2 @@
|
||||
packages:
|
||||
- 'packages/*'
|
||||
- "packages/*"
|
||||
|
||||
@@ -1,60 +1 @@
|
||||
<svg width="100%" height="100%" version="1.1" viewBox="0 0 1000 1000" xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g>
|
||||
<path
|
||||
d="M 200,866 C 100,866 50,779.4 100,692.8 L 200,519.6 C 220,485 240,490 265,499.6 S 360,542.68 360,542.68 C 480.5,601 498,642.5 500,720 C 498,811 462,856 420,866"
|
||||
fill="url(#LinearGradient)" fill-rule="nonzero" opacity="1" stroke="none" />
|
||||
<path
|
||||
d="M 420,866 C 455,861 478,846 500,827 C 614,696 615,597 500,517 C 394,444 333,374 380,207.82 L 260,415.67 C 240.22,450 254.37,465.1 275.28,481.79 S 360,542.68 360,542.68 C 480.5,601 498,642.5 500,720 C 498,811 462,856 420,866"
|
||||
fill="url(#LinearGradient_2)" fill-rule="nonzero" opacity="1" stroke="none" />
|
||||
<path d="M 500,517 C 394,444 333,374 380,207.82 L 400,173.2 C 367,295 421,350 603,428 C 572,440 524,474 500,517"
|
||||
fill="url(#LinearGradient_3)" fill-rule="nonzero" opacity="1" stroke="none" />
|
||||
<path d="M 500,827 L 660,660 C 738,589 710,482 603,428 C 572,440 524,474 500,517 C 615,597 614,696 500,827"
|
||||
fill="url(#LinearGradient_4)" fill-rule="nonzero" opacity="1" stroke="none" />
|
||||
<path d="M 400,173.2 C 367,295 421,350 603,428 C 690,389, 750,445 788,500 L 600,173.2 C 550,86.6 450,86.6 400,173.2"
|
||||
fill="url(#LinearGradient_5)" fill-rule="nonzero" opacity="1" stroke="none" />
|
||||
<path
|
||||
d="M 500,827 L 660,660 C 738,589 710,482 603,428 C 690,389, 750,445 788,500 C 816,554 797,606 750,640 L 500,827"
|
||||
fill="url(#LinearGradient_6)" fill-rule="nonzero" opacity="1" stroke="none" />
|
||||
<path
|
||||
d="M 788,500 C 816,554 797,606 750,640 L 500,827 C 497,851 513,862 540,866 L 800,866 C 900,866 950,779.4 900,692.8 L 788,500"
|
||||
fill="url(#LinearGradient_7)" fill-rule="nonzero" opacity="1" stroke="none" />
|
||||
</g>
|
||||
<defs>
|
||||
<linearGradient gradientTransform="matrix(104.391 -73.3432 73.3432 104.391 277.441 710.122)"
|
||||
gradientUnits="userSpaceOnUse" id="LinearGradient" x1="0" x2="1" y1="0" y2="0">
|
||||
<stop offset="0" stop-color="#373ebf" />
|
||||
<stop offset="1" stop-color="#5058e6" />
|
||||
</linearGradient>
|
||||
<linearGradient gradientTransform="matrix(-173.747 557.324 -557.324 -173.747 508.829 258.172)"
|
||||
gradientUnits="userSpaceOnUse" id="LinearGradient_2" x1="0" x2="1" y1="0" y2="0">
|
||||
<stop offset="0" stop-color="#c2d6ff" />
|
||||
<stop offset="1" stop-color="#646cff" />
|
||||
</linearGradient>
|
||||
<linearGradient gradientTransform="matrix(157.951 295.666 -295.666 157.951 382.944 193.642)"
|
||||
gradientUnits="userSpaceOnUse" id="LinearGradient_3" x1="0" x2="1" y1="0" y2="0">
|
||||
<stop offset="0" stop-color="#5058e6" />
|
||||
<stop offset="1" stop-color="#373ebf" />
|
||||
</linearGradient>
|
||||
<linearGradient gradientTransform="matrix(-44.3023 219.578 -219.578 -44.3023 619.69 469.652)"
|
||||
gradientUnits="userSpaceOnUse" id="LinearGradient_4" x1="0" x2="1" y1="0" y2="0">
|
||||
<stop offset="0" stop-color="#91a7ff" />
|
||||
<stop offset="1" stop-color="#5058e6" />
|
||||
</linearGradient>
|
||||
<linearGradient gradientTransform="matrix(125.52 334.256 -334.256 125.52 539.723 235.139)"
|
||||
gradientUnits="userSpaceOnUse" id="LinearGradient_5" x1="0" x2="1" y1="0" y2="0">
|
||||
<stop offset="0" stop-color="#646cff" />
|
||||
<stop offset="1" stop-color="#c2d6ff" />
|
||||
</linearGradient>
|
||||
<linearGradient gradientTransform="matrix(-241.23 357.206 -357.206 -241.23 754.054 449.312)"
|
||||
gradientUnits="userSpaceOnUse" id="LinearGradient_6" x1="0" x2="1" y1="0" y2="0">
|
||||
<stop offset="0" stop-color="#c2d6ff" />
|
||||
<stop offset="1" stop-color="#646cff" />
|
||||
</linearGradient>
|
||||
<linearGradient gradientTransform="matrix(125.978 210.065 -210.065 125.978 596.433 613.665)"
|
||||
gradientUnits="userSpaceOnUse" id="LinearGradient_7" x1="0" x2="1" y1="0" y2="0">
|
||||
<stop offset="0" stop-color="#373ebf" />
|
||||
<stop offset="1" stop-color="#5058e6" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</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="#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>
|
||||
|
||||
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 1.5 KiB |
@@ -1,5 +1,4 @@
|
||||
<script setup lang="ts" generic="T extends Record<string, unknown>, K = never">
|
||||
import { computed } from 'vue';
|
||||
import { VueDraggable } from 'vue-draggable-plus';
|
||||
import { $t } from '@/locales';
|
||||
|
||||
@@ -10,53 +9,6 @@ defineOptions({
|
||||
const columns = defineModel<NaiveUI.TableColumnCheck[]>('columns', {
|
||||
required: true
|
||||
});
|
||||
|
||||
const tooltipRecord: Record<NaiveUI.TableColumnFixed, App.I18n.I18nKey> = {
|
||||
left: 'datatable.fixed.right',
|
||||
right: 'datatable.fixed.unFixed',
|
||||
unFixed: 'datatable.fixed.left'
|
||||
};
|
||||
|
||||
function handleFixed(column: NaiveUI.TableColumnCheck) {
|
||||
const fixedOptions: NaiveUI.TableColumnFixed[] = ['left', 'right', 'unFixed'];
|
||||
const index = fixedOptions.findIndex(item => item === column.fixed);
|
||||
const nextIndex = index === fixedOptions.length - 1 ? 0 : index + 1;
|
||||
column.fixed = fixedOptions[nextIndex];
|
||||
}
|
||||
|
||||
const visibleStats = computed(() => {
|
||||
let total = 0;
|
||||
let checked = 0;
|
||||
|
||||
columns.value.forEach(column => {
|
||||
if (!column.visible) return;
|
||||
|
||||
total += 1;
|
||||
if (column.checked) checked += 1;
|
||||
});
|
||||
|
||||
return { total, checked };
|
||||
});
|
||||
|
||||
const selectAllChecked = computed(() => {
|
||||
const { total, checked } = visibleStats.value;
|
||||
|
||||
return total > 0 && checked === total;
|
||||
});
|
||||
|
||||
const selectAllIndeterminate = computed(() => {
|
||||
const { total, checked } = visibleStats.value;
|
||||
|
||||
return checked > 0 && checked < total;
|
||||
});
|
||||
|
||||
function toggleSelectAll(checked: boolean) {
|
||||
columns.value.forEach(column => {
|
||||
if (!column.visible) return;
|
||||
|
||||
column.checked = checked;
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -69,48 +21,22 @@ function toggleSelectAll(checked: boolean) {
|
||||
{{ $t('common.columnSetting') }}
|
||||
</NButton>
|
||||
</template>
|
||||
<div>
|
||||
<div class="h-36px flex-y-center rd-4px pl-26px hover:(bg-primary bg-opacity-20)">
|
||||
<NCheckbox
|
||||
:checked="selectAllChecked"
|
||||
:indeterminate="selectAllIndeterminate"
|
||||
:disabled="visibleStats.total === 0"
|
||||
class="flex-1"
|
||||
@update:checked="toggleSelectAll"
|
||||
>
|
||||
{{ $t('common.selectAll') }}
|
||||
<VueDraggable v-model="columns" :animation="150" filter=".none_draggable">
|
||||
<div
|
||||
v-for="item in columns"
|
||||
:key="item.key"
|
||||
class="h-36px flex-y-center rd-4px hover:(bg-primary bg-opacity-20)"
|
||||
:class="{ hidden: !item.visible }"
|
||||
>
|
||||
<icon-mdi-drag class="mr-8px h-full cursor-move text-icon" />
|
||||
<NCheckbox v-model:checked="item.checked" class="none_draggable flex-1">
|
||||
<template v-if="typeof item.title === 'function'">
|
||||
<component :is="item.title" />
|
||||
</template>
|
||||
<template v-else>{{ item.title }}</template>
|
||||
</NCheckbox>
|
||||
</div>
|
||||
<NDivider class="!my-4px" />
|
||||
<VueDraggable v-model="columns" :animation="150" filter=".none_draggable" class="max-h-[200px] overflow-y-auto">
|
||||
<div
|
||||
v-for="item in columns"
|
||||
:key="item.key"
|
||||
class="h-36px flex-y-center justify-between gap-6px"
|
||||
:class="{ hidden: !item.visible }"
|
||||
>
|
||||
<div class="h-full flex-y-center flex-1 rd-4px hover:(bg-primary bg-opacity-20)">
|
||||
<icon-mdi-drag class="mr-8px h-full cursor-move text-icon" />
|
||||
<NCheckbox v-model:checked="item.checked" class="none_draggable flex-1">
|
||||
<template v-if="typeof item.title === 'function'">
|
||||
<component :is="item.title" />
|
||||
</template>
|
||||
<template v-else>{{ item.title }}</template>
|
||||
</NCheckbox>
|
||||
</div>
|
||||
<ButtonIcon
|
||||
:disabled="!item.checked"
|
||||
:focusable="false"
|
||||
:tooltip-content="$t(tooltipRecord[item.fixed!])"
|
||||
@click="handleFixed(item)"
|
||||
>
|
||||
<icon-octicon-pin-16 v-if="item.fixed === 'unFixed'" />
|
||||
<icon-octicon-pin-16 v-else-if="item.fixed === 'left'" class="rotate-270" />
|
||||
<icon-octicon-pin-slash-16 v-else />
|
||||
</ButtonIcon>
|
||||
</div>
|
||||
</VueDraggable>
|
||||
</div>
|
||||
</VueDraggable>
|
||||
</NPopover>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts" setup>
|
||||
import { computed } from 'vue';
|
||||
import { useRouterPush } from '@/hooks/common/router';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { $t } from '@/locales';
|
||||
|
||||
defineOptions({ name: 'ExceptionBase' });
|
||||
@@ -20,7 +20,7 @@ interface Props {
|
||||
|
||||
const props = defineProps<Props>();
|
||||
|
||||
const { routerPushByKey } = useRouterPush();
|
||||
const router = useRouter();
|
||||
|
||||
const iconMap: Record<ExceptionType, string> = {
|
||||
'403': 'no-permission',
|
||||
@@ -36,7 +36,7 @@ const icon = computed(() => iconMap[props.type]);
|
||||
<div class="flex text-400px text-primary">
|
||||
<SvgIcon :local-icon="icon" />
|
||||
</div>
|
||||
<NButton type="primary" @click="routerPushByKey('root')">{{ $t('common.backToHome') }}</NButton>
|
||||
<NButton type="primary" @click="router.push('/')">{{ $t('common.backToHome') }}</NButton>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -1,160 +1,9 @@
|
||||
<script lang="ts" setup>
|
||||
defineOptions({ name: 'SystemLogo' });
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="app-logo">
|
||||
<svg
|
||||
width="100%"
|
||||
height="100%"
|
||||
version="1.1"
|
||||
viewBox="0 0 1000 1000"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
>
|
||||
<g>
|
||||
<path
|
||||
d="M 200,866 C 100,866 50,779.4 100,692.8 L 200,519.6 C 220,485 240,490 265,499.6 S 360,542.68 360,542.68 C 480.5,601 498,642.5 500,720 C 498,811 462,856 420,866"
|
||||
fill="url(#LinearGradient)"
|
||||
fill-rule="nonzero"
|
||||
opacity="1"
|
||||
stroke="none"
|
||||
/>
|
||||
<path
|
||||
d="M 420,866 C 455,861 478,846 500,827 C 614,696 615,597 500,517 C 394,444 333,374 380,207.82 L 260,415.67 C 240.22,450 254.37,465.1 275.28,481.79 S 360,542.68 360,542.68 C 480.5,601 498,642.5 500,720 C 498,811 462,856 420,866"
|
||||
fill="url(#LinearGradient_2)"
|
||||
fill-rule="nonzero"
|
||||
opacity="1"
|
||||
stroke="none"
|
||||
/>
|
||||
<path
|
||||
d="M 500,517 C 394,444 333,374 380,207.82 L 400,173.2 C 367,295 421,350 603,428 C 572,440 524,474 500,517"
|
||||
fill="url(#LinearGradient_3)"
|
||||
fill-rule="nonzero"
|
||||
opacity="1"
|
||||
stroke="none"
|
||||
/>
|
||||
<path
|
||||
d="M 500,827 L 660,660 C 738,589 710,482 603,428 C 572,440 524,474 500,517 C 615,597 614,696 500,827"
|
||||
fill="url(#LinearGradient_4)"
|
||||
fill-rule="nonzero"
|
||||
opacity="1"
|
||||
stroke="none"
|
||||
/>
|
||||
<path
|
||||
d="M 400,173.2 C 367,295 421,350 603,428 C 690,389, 750,445 788,500 L 600,173.2 C 550,86.6 450,86.6 400,173.2"
|
||||
fill="url(#LinearGradient_5)"
|
||||
fill-rule="nonzero"
|
||||
opacity="1"
|
||||
stroke="none"
|
||||
/>
|
||||
<path
|
||||
d="M 500,827 L 660,660 C 738,589 710,482 603,428 C 690,389, 750,445 788,500 C 816,554 797,606 750,640 L 500,827"
|
||||
fill="url(#LinearGradient_6)"
|
||||
fill-rule="nonzero"
|
||||
opacity="1"
|
||||
stroke="none"
|
||||
/>
|
||||
<path
|
||||
d="M 788,500 C 816,554 797,606 750,640 L 500,827 C 497,851 513,862 540,866 L 800,866 C 900,866 950,779.4 900,692.8 L 788,500"
|
||||
fill="url(#LinearGradient_7)"
|
||||
fill-rule="nonzero"
|
||||
opacity="1"
|
||||
stroke="none"
|
||||
/>
|
||||
</g>
|
||||
<defs>
|
||||
<linearGradient
|
||||
id="LinearGradient"
|
||||
gradientTransform="matrix(104.391 -73.3432 73.3432 104.391 277.441 710.122)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="0"
|
||||
x2="1"
|
||||
y1="0"
|
||||
y2="0"
|
||||
>
|
||||
<stop offset="0" stop-color="var(--logo-color-700)" />
|
||||
<stop offset="1" stop-color="var(--logo-color-600)" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="LinearGradient_2"
|
||||
gradientTransform="matrix(-173.747 557.324 -557.324 -173.747 508.829 258.172)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="0"
|
||||
x2="1"
|
||||
y1="0"
|
||||
y2="0"
|
||||
>
|
||||
<stop offset="0" stop-color="var(--logo-color-300)" />
|
||||
<stop offset="1" stop-color="var(--logo-color-500)" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="LinearGradient_3"
|
||||
gradientTransform="matrix(157.951 295.666 -295.666 157.951 382.944 193.642)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="0"
|
||||
x2="1"
|
||||
y1="0"
|
||||
y2="0"
|
||||
>
|
||||
<stop offset="0" stop-color="var(--logo-color-600)" />
|
||||
<stop offset="1" stop-color="var(--logo-color-700)" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="LinearGradient_4"
|
||||
gradientTransform="matrix(-44.3023 219.578 -219.578 -44.3023 619.69 469.652)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="0"
|
||||
x2="1"
|
||||
y1="0"
|
||||
y2="0"
|
||||
>
|
||||
<stop offset="0" stop-color="var(--logo-color-400)" />
|
||||
<stop offset="1" stop-color="var(--logo-color-600)" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="LinearGradient_5"
|
||||
gradientTransform="matrix(125.52 334.256 -334.256 125.52 539.723 235.139)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="0"
|
||||
x2="1"
|
||||
y1="0"
|
||||
y2="0"
|
||||
>
|
||||
<stop offset="0" stop-color="var(--logo-color-500)" />
|
||||
<stop offset="1" stop-color="var(--logo-color-300)" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="LinearGradient_6"
|
||||
gradientTransform="matrix(-241.23 357.206 -357.206 -241.23 754.054 449.312)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="0"
|
||||
x2="1"
|
||||
y1="0"
|
||||
y2="0"
|
||||
>
|
||||
<stop offset="0" stop-color="var(--logo-color-300)" />
|
||||
<stop offset="1" stop-color="var(--logo-color-500)" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="LinearGradient_7"
|
||||
gradientTransform="matrix(125.978 210.065 -210.065 125.978 596.433 613.665)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="0"
|
||||
x2="1"
|
||||
y1="0"
|
||||
y2="0"
|
||||
>
|
||||
<stop offset="0" stop-color="var(--logo-color-700)" />
|
||||
<stop offset="1" stop-color="var(--logo-color-600)" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
</div>
|
||||
<icon-local-logo />
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.app-logo {
|
||||
--logo-color-300: rgb(var(--primary-300-color));
|
||||
--logo-color-400: rgb(var(--primary-400-color));
|
||||
--logo-color-500: rgb(var(--primary-500-color));
|
||||
--logo-color-600: rgb(var(--primary-600-color));
|
||||
--logo-color-700: rgb(var(--primary-700-color));
|
||||
}
|
||||
</style>
|
||||
<style scoped></style>
|
||||
|
||||
@@ -266,7 +266,6 @@ function getColumnChecks<Column extends NaiveUI.TableColumn<any>>(
|
||||
key: column.key as string,
|
||||
title: column.title!,
|
||||
checked: true,
|
||||
fixed: column.fixed ?? 'unFixed',
|
||||
visible: getColumnVisible?.(column) ?? true
|
||||
});
|
||||
} else if (column.type === 'selection') {
|
||||
@@ -274,7 +273,6 @@ function getColumnChecks<Column extends NaiveUI.TableColumn<any>>(
|
||||
key: SELECTION_KEY,
|
||||
title: $t('common.check'),
|
||||
checked: true,
|
||||
fixed: column.fixed ?? 'unFixed',
|
||||
visible: getColumnVisible?.(column) ?? false
|
||||
});
|
||||
} else if (column.type === 'expand') {
|
||||
@@ -282,7 +280,6 @@ function getColumnChecks<Column extends NaiveUI.TableColumn<any>>(
|
||||
key: EXPAND_KEY,
|
||||
title: $t('common.expandColumn'),
|
||||
checked: true,
|
||||
fixed: column.fixed ?? 'unFixed',
|
||||
visible: getColumnVisible?.(column) ?? false
|
||||
});
|
||||
}
|
||||
@@ -304,14 +301,7 @@ function getColumns<Column extends NaiveUI.TableColumn<any>>(cols: Column[], che
|
||||
}
|
||||
});
|
||||
|
||||
const filteredColumns = checks
|
||||
.filter(item => item.checked)
|
||||
.map(check => {
|
||||
return {
|
||||
...columnMap.get(check.key),
|
||||
fixed: check.fixed
|
||||
} as Column;
|
||||
});
|
||||
const filteredColumns = checks.filter(item => item.checked).map(check => columnMap.get(check.key) as Column);
|
||||
|
||||
return filteredColumns;
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ withDefaults(defineProps<Props>(), {
|
||||
|
||||
<template>
|
||||
<RouterLink to="/" class="w-full flex-center nowrap-hidden">
|
||||
<SystemLogo class="size-32px" />
|
||||
<SystemLogo class="text-32px text-primary" />
|
||||
<h2 v-show="showTitle" class="pl-8px text-16px text-primary font-bold transition duration-300 ease-in-out">
|
||||
{{ $t('system.title') }}
|
||||
</h2>
|
||||
|
||||
@@ -68,15 +68,14 @@ const swatches: string[] = [
|
||||
{{ $t('theme.appearance.themeColor.followPrimary') }}
|
||||
</NCheckbox>
|
||||
</template>
|
||||
<div class="w-90px">
|
||||
<NColorPicker
|
||||
:value="themeStore.themeColors[key]"
|
||||
:disabled="key === 'info' && themeStore.isInfoFollowPrimary"
|
||||
:show-alpha="false"
|
||||
:swatches="swatches"
|
||||
@update:value="handleUpdateColor($event, key)"
|
||||
/>
|
||||
</div>
|
||||
<NColorPicker
|
||||
class="w-90px"
|
||||
:value="themeStore.themeColors[key]"
|
||||
:disabled="key === 'info' && themeStore.isInfoFollowPrimary"
|
||||
:show-alpha="false"
|
||||
:swatches="swatches"
|
||||
@update:value="handleUpdateColor($event, key)"
|
||||
/>
|
||||
</SettingItem>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -23,10 +23,4 @@ export const $t = i18n.global.t as App.I18n.$T;
|
||||
|
||||
export function setLocale(locale: App.I18n.LangType) {
|
||||
i18n.global.locale.value = locale;
|
||||
|
||||
document?.querySelector('html')?.setAttribute('lang', locale);
|
||||
}
|
||||
|
||||
export function getLocale(): App.I18n.LangType {
|
||||
return i18n.global.locale.value as App.I18n.LangType;
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@ const local: App.I18n.Schema = {
|
||||
cancel: 'Cancel',
|
||||
close: 'Close',
|
||||
check: 'Check',
|
||||
selectAll: 'Select All',
|
||||
expandColumn: 'Expand Column',
|
||||
columnSetting: 'Column Setting',
|
||||
config: 'Config',
|
||||
@@ -357,12 +356,7 @@ const local: App.I18n.Schema = {
|
||||
unpin: 'Unpin'
|
||||
},
|
||||
datatable: {
|
||||
itemCount: 'Total {total} items',
|
||||
fixed: {
|
||||
left: 'Left Fixed',
|
||||
right: 'Right Fixed',
|
||||
unFixed: 'Unfixed'
|
||||
}
|
||||
itemCount: 'Total {total} items'
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -15,7 +15,6 @@ const local: App.I18n.Schema = {
|
||||
cancel: '取消',
|
||||
close: '关闭',
|
||||
check: '勾选',
|
||||
selectAll: '全选',
|
||||
expandColumn: '展开列',
|
||||
columnSetting: '列设置',
|
||||
config: '配置',
|
||||
@@ -353,12 +352,7 @@ const local: App.I18n.Schema = {
|
||||
unpin: '取消固定'
|
||||
},
|
||||
datatable: {
|
||||
itemCount: '共 {total} 条',
|
||||
fixed: {
|
||||
left: '左固定',
|
||||
right: '右固定',
|
||||
unFixed: '取消固定'
|
||||
}
|
||||
itemCount: '共 {total} 条'
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import { createApp } from 'vue';
|
||||
import './plugins/assets';
|
||||
import { setupVueRootValidator } from 'vite-plugin-vue-transition-root-validator/client';
|
||||
import { setupAppVersionNotification, setupDayjs, setupIconifyOffline, setupLoading, setupNProgress } from './plugins';
|
||||
import { setupStore } from './store';
|
||||
import { setupRouter } from './router';
|
||||
import { getLocale, setupI18n } from './locales';
|
||||
import { setupI18n } from './locales';
|
||||
import App from './App.vue';
|
||||
|
||||
async function setupApp() {
|
||||
@@ -26,10 +25,6 @@ async function setupApp() {
|
||||
|
||||
setupAppVersionNotification();
|
||||
|
||||
setupVueRootValidator(app, {
|
||||
lang: getLocale() === 'zh-CN' ? 'zh' : 'en'
|
||||
});
|
||||
|
||||
app.mount('#app');
|
||||
}
|
||||
|
||||
|
||||
@@ -1,25 +1,18 @@
|
||||
// @unocss-include
|
||||
import { getColorPalette, getRgb } from '@sa/color';
|
||||
import { getRgb } from '@sa/color';
|
||||
import { DARK_CLASS } from '@/constants/app';
|
||||
import { localStg } from '@/utils/storage';
|
||||
import { toggleHtmlClass } from '@/utils/common';
|
||||
import systemLogo from '@/assets/svg-icon/logo.svg?raw';
|
||||
import { $t } from '@/locales';
|
||||
|
||||
export function setupLoading() {
|
||||
const themeColor = localStg.get('themeColor') || '#646cff';
|
||||
const darkMode = localStg.get('darkMode') || false;
|
||||
const palette = getColorPalette(themeColor);
|
||||
|
||||
const { r, g, b } = getRgb(themeColor);
|
||||
|
||||
const primaryColor = `--primary-color: ${r} ${g} ${b}`;
|
||||
|
||||
const svgCssVars = Array.from(palette.entries())
|
||||
.map(([key, value]) => `--logo-color-${key}: ${value}`)
|
||||
.join(';');
|
||||
|
||||
const cssVars = `${primaryColor}; ${svgCssVars}`;
|
||||
|
||||
if (darkMode) {
|
||||
toggleHtmlClass(DARK_CLASS).add();
|
||||
}
|
||||
@@ -31,6 +24,8 @@ export function setupLoading() {
|
||||
'right-0 bottom-0 animate-delay-1500'
|
||||
];
|
||||
|
||||
const logoWithClass = systemLogo.replace('<svg', `<svg class="size-128px text-primary"`);
|
||||
|
||||
const dot = loadingClasses
|
||||
.map(item => {
|
||||
return `<div class="absolute w-16px h-16px bg-primary rounded-8px animate-pulse ${item}"></div>`;
|
||||
@@ -38,10 +33,8 @@ export function setupLoading() {
|
||||
.join('\n');
|
||||
|
||||
const loading = `
|
||||
<div class="fixed-center flex-col bg-layout" style="${cssVars}">
|
||||
<div class="w-128px h-128px">
|
||||
${getLogoSvg()}
|
||||
</div>
|
||||
<div class="fixed-center flex-col bg-layout" style="${primaryColor}">
|
||||
${logoWithClass}
|
||||
<div class="w-56px h-56px my-36px">
|
||||
<div class="relative h-full animate-spin">
|
||||
${dot}
|
||||
@@ -56,155 +49,3 @@ export function setupLoading() {
|
||||
app.innerHTML = loading;
|
||||
}
|
||||
}
|
||||
|
||||
function getLogoSvg() {
|
||||
const logoSvg = `<svg
|
||||
width="100%"
|
||||
height="100%"
|
||||
version="1.1"
|
||||
viewBox="0 0 1000 1000"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
>
|
||||
<g>
|
||||
<path
|
||||
d="M 200,866 C 100,866 50,779.4 100,692.8 L 200,519.6 C 220,485 240,490 265,499.6 S 360,542.68 360,542.68 C 480.5,601 498,642.5 500,720 C 498,811 462,856 420,866"
|
||||
fill="url(#LinearGradient)"
|
||||
fill-rule="nonzero"
|
||||
opacity="1"
|
||||
stroke="none"
|
||||
/>
|
||||
<path
|
||||
d="M 420,866 C 455,861 478,846 500,827 C 614,696 615,597 500,517 C 394,444 333,374 380,207.82 L 260,415.67 C 240.22,450 254.37,465.1 275.28,481.79 S 360,542.68 360,542.68 C 480.5,601 498,642.5 500,720 C 498,811 462,856 420,866"
|
||||
fill="url(#LinearGradient_2)"
|
||||
fill-rule="nonzero"
|
||||
opacity="1"
|
||||
stroke="none"
|
||||
/>
|
||||
<path
|
||||
d="M 500,517 C 394,444 333,374 380,207.82 L 400,173.2 C 367,295 421,350 603,428 C 572,440 524,474 500,517"
|
||||
fill="url(#LinearGradient_3)"
|
||||
fill-rule="nonzero"
|
||||
opacity="1"
|
||||
stroke="none"
|
||||
/>
|
||||
<path
|
||||
d="M 500,827 L 660,660 C 738,589 710,482 603,428 C 572,440 524,474 500,517 C 615,597 614,696 500,827"
|
||||
fill="url(#LinearGradient_4)"
|
||||
fill-rule="nonzero"
|
||||
opacity="1"
|
||||
stroke="none"
|
||||
/>
|
||||
<path
|
||||
d="M 400,173.2 C 367,295 421,350 603,428 C 690,389, 750,445 788,500 L 600,173.2 C 550,86.6 450,86.6 400,173.2"
|
||||
fill="url(#LinearGradient_5)"
|
||||
fill-rule="nonzero"
|
||||
opacity="1"
|
||||
stroke="none"
|
||||
/>
|
||||
<path
|
||||
d="M 500,827 L 660,660 C 738,589 710,482 603,428 C 690,389, 750,445 788,500 C 816,554 797,606 750,640 L 500,827"
|
||||
fill="url(#LinearGradient_6)"
|
||||
fill-rule="nonzero"
|
||||
opacity="1"
|
||||
stroke="none"
|
||||
/>
|
||||
<path
|
||||
d="M 788,500 C 816,554 797,606 750,640 L 500,827 C 497,851 513,862 540,866 L 800,866 C 900,866 950,779.4 900,692.8 L 788,500"
|
||||
fill="url(#LinearGradient_7)"
|
||||
fill-rule="nonzero"
|
||||
opacity="1"
|
||||
stroke="none"
|
||||
/>
|
||||
</g>
|
||||
<defs>
|
||||
<linearGradient
|
||||
id="LinearGradient"
|
||||
gradientTransform="matrix(104.391 -73.3432 73.3432 104.391 277.441 710.122)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="0"
|
||||
x2="1"
|
||||
y1="0"
|
||||
y2="0"
|
||||
>
|
||||
<stop offset="0" stop-color="var(--logo-color-700)" />
|
||||
<stop offset="1" stop-color="var(--logo-color-600)" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="LinearGradient_2"
|
||||
gradientTransform="matrix(-173.747 557.324 -557.324 -173.747 508.829 258.172)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="0"
|
||||
x2="1"
|
||||
y1="0"
|
||||
y2="0"
|
||||
>
|
||||
<stop offset="0" stop-color="var(--logo-color-300)" />
|
||||
<stop offset="1" stop-color="var(--logo-color-500)" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="LinearGradient_3"
|
||||
gradientTransform="matrix(157.951 295.666 -295.666 157.951 382.944 193.642)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="0"
|
||||
x2="1"
|
||||
y1="0"
|
||||
y2="0"
|
||||
>
|
||||
<stop offset="0" stop-color="var(--logo-color-600)" />
|
||||
<stop offset="1" stop-color="var(--logo-color-700)" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="LinearGradient_4"
|
||||
gradientTransform="matrix(-44.3023 219.578 -219.578 -44.3023 619.69 469.652)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="0"
|
||||
x2="1"
|
||||
y1="0"
|
||||
y2="0"
|
||||
>
|
||||
<stop offset="0" stop-color="var(--logo-color-400)" />
|
||||
<stop offset="1" stop-color="var(--logo-color-600)" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="LinearGradient_5"
|
||||
gradientTransform="matrix(125.52 334.256 -334.256 125.52 539.723 235.139)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="0"
|
||||
x2="1"
|
||||
y1="0"
|
||||
y2="0"
|
||||
>
|
||||
<stop offset="0" stop-color="var(--logo-color-500)" />
|
||||
<stop offset="1" stop-color="var(--logo-color-300)" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="LinearGradient_6"
|
||||
gradientTransform="matrix(-241.23 357.206 -357.206 -241.23 754.054 449.312)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="0"
|
||||
x2="1"
|
||||
y1="0"
|
||||
y2="0"
|
||||
>
|
||||
<stop offset="0" stop-color="var(--logo-color-300)" />
|
||||
<stop offset="1" stop-color="var(--logo-color-500)" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="LinearGradient_7"
|
||||
gradientTransform="matrix(125.978 210.065 -210.065 125.978 596.433 613.665)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="0"
|
||||
x2="1"
|
||||
y1="0"
|
||||
y2="0"
|
||||
>
|
||||
<stop offset="0" stop-color="var(--logo-color-700)" />
|
||||
<stop offset="1" stop-color="var(--logo-color-600)" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
`;
|
||||
|
||||
return logoSvg;
|
||||
}
|
||||
|
||||
27
src/router/_generated/imports.ts
Normal file
27
src/router/_generated/imports.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
/* eslint-disable */
|
||||
/* prettier-ignore */
|
||||
/* oxlint-disable */
|
||||
// biome-ignore lint: disable
|
||||
// Generated by elegant-router
|
||||
// Read more: https://github.com/soybeanjs/elegant-router
|
||||
|
||||
import type { RouteFileKey, RouteLayoutKey, RawRouteComponent } from "@elegant-router/types";
|
||||
|
||||
export const layouts: Record<RouteLayoutKey, RawRouteComponent> = {
|
||||
base: () => import("@/layouts/base-layout/index.vue"),
|
||||
blank: () => import("@/layouts/blank-layout/index.vue"),
|
||||
};
|
||||
|
||||
export const views: Record<RouteFileKey, RawRouteComponent> = {
|
||||
403: () => import("@/views/(builtin)/403/index.vue"),
|
||||
404: () => import("@/views/(builtin)/404/index.vue"),
|
||||
500: () => import("@/views/(builtin)/500/index.vue"),
|
||||
Home: () => import("@/views/home/index.vue"),
|
||||
IframeUrl: () => import("@/views/(builtin)/iframe/[url].vue"),
|
||||
Login: () => import("@/views/(builtin)/login/index.vue"),
|
||||
ManageMenu: () => import("@/views/manage/menu/index.vue"),
|
||||
ManageRole: () => import("@/views/manage/role/index.vue"),
|
||||
ManageRoute: () => import("@/views/manage/route/index.vue"),
|
||||
ManageUser: () => import("@/views/manage/user/index.vue"),
|
||||
Wip: () => import("@/views/(builtin)/wip/index.vue"),
|
||||
};
|
||||
113
src/router/_generated/routes.ts
Normal file
113
src/router/_generated/routes.ts
Normal file
@@ -0,0 +1,113 @@
|
||||
/* eslint-disable */
|
||||
/* prettier-ignore */
|
||||
// biome-ignore lint: disable
|
||||
// Generated by elegant-router
|
||||
// Read more: https://github.com/soybeanjs/elegant-router
|
||||
|
||||
import type { AutoRouterRoute } from '@elegant-router/types';
|
||||
|
||||
export const routes: AutoRouterRoute[] = [
|
||||
{
|
||||
name: '403',
|
||||
path: '/403',
|
||||
layout: 'base',
|
||||
component: '403',
|
||||
meta: {
|
||||
title: "403",
|
||||
constant: true
|
||||
},
|
||||
},
|
||||
{
|
||||
name: '404',
|
||||
path: '/404',
|
||||
layout: 'base',
|
||||
component: '404',
|
||||
meta: {
|
||||
title: "404",
|
||||
constant: true
|
||||
},
|
||||
},
|
||||
{
|
||||
name: '500',
|
||||
path: '/500',
|
||||
layout: 'base',
|
||||
component: '500',
|
||||
meta: {
|
||||
title: "500",
|
||||
constant: true
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Home',
|
||||
path: '/home',
|
||||
layout: 'base',
|
||||
component: 'Home',
|
||||
meta: {
|
||||
title: "Home"
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'IframeUrl',
|
||||
path: '/iframe/:url',
|
||||
layout: 'base',
|
||||
component: 'IframeUrl',
|
||||
meta: {
|
||||
title: "IframeUrl"
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'Login',
|
||||
path: '/login/:module(pwd-login|code-login|register|reset-pwd|bind-wechat)?',
|
||||
layout: 'base',
|
||||
component: 'Login',
|
||||
meta: {
|
||||
title: "Login",
|
||||
constant: true
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'ManageMenu',
|
||||
path: '/manage/menu',
|
||||
layout: 'base',
|
||||
component: 'ManageMenu',
|
||||
meta: {
|
||||
title: "ManageMenu"
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'ManageRole',
|
||||
path: '/manage/role',
|
||||
layout: 'base',
|
||||
component: 'ManageRole',
|
||||
meta: {
|
||||
title: "ManageRole"
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'ManageRoute',
|
||||
path: '/manage/route',
|
||||
layout: 'base',
|
||||
component: 'ManageRoute',
|
||||
meta: {
|
||||
title: "ManageRoute"
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'ManageUser',
|
||||
path: '/manage/user',
|
||||
layout: 'base',
|
||||
component: 'ManageUser',
|
||||
meta: {
|
||||
title: "ManageUser"
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Wip',
|
||||
path: '/wip',
|
||||
layout: 'base',
|
||||
component: 'Wip',
|
||||
meta: {
|
||||
title: "Wip"
|
||||
}
|
||||
}
|
||||
];
|
||||
28
src/router/_generated/shared.ts
Normal file
28
src/router/_generated/shared.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
/* eslint-disable */
|
||||
/* prettier-ignore */
|
||||
/* oxlint-disable */
|
||||
// biome-ignore lint: disable
|
||||
// Generated by elegant-router
|
||||
// Read more: https://github.com/soybeanjs/elegant-router
|
||||
|
||||
import type { RouteKey, RoutePathMap } from '@elegant-router/types';
|
||||
|
||||
const routePathMap: RoutePathMap = {
|
||||
"Root": "/",
|
||||
"NotFound": "/:pathMatch(.*)*",
|
||||
"403": "/403",
|
||||
"404": "/404",
|
||||
"500": "/500",
|
||||
"Home": "/home",
|
||||
"IframeUrl": "/iframe/:url",
|
||||
"Login": "/login/:module(pwd-login|code-login|register|reset-pwd|bind-wechat)?",
|
||||
"ManageMenu": "/manage/menu",
|
||||
"ManageRole": "/manage/role",
|
||||
"ManageRoute": "/manage/route",
|
||||
"ManageUser": "/manage/user",
|
||||
"Wip": "/wip",
|
||||
};
|
||||
|
||||
export function getRoutePath(key: RouteKey) {
|
||||
return routePathMap[key];
|
||||
}
|
||||
70
src/router/_generated/transformer.ts
Normal file
70
src/router/_generated/transformer.ts
Normal file
@@ -0,0 +1,70 @@
|
||||
/* eslint-disable */
|
||||
/* prettier-ignore */
|
||||
/* oxlint-disable */
|
||||
// biome-ignore lint: disable
|
||||
// Generated by elegant-router
|
||||
// Read more: https://github.com/soybeanjs/elegant-router
|
||||
|
||||
import type { RouteRecordRaw } from 'vue-router';
|
||||
import type {
|
||||
AutoRouterRedirect,
|
||||
AutoRouterRoute,
|
||||
AutoRouterSingleView,
|
||||
RawRouteComponent,
|
||||
RouteFileKey,
|
||||
RouteLayoutKey
|
||||
} from '@elegant-router/types';
|
||||
|
||||
export function transformToVueRoutes(
|
||||
routes: AutoRouterRoute[],
|
||||
layouts: Record<RouteLayoutKey, RawRouteComponent>,
|
||||
views: Record<RouteFileKey, RawRouteComponent>
|
||||
) {
|
||||
const { redirects, groupedRoutes } = getFormattedRoutes(routes);
|
||||
|
||||
const vueRoutes: RouteRecordRaw[] = [...redirects];
|
||||
|
||||
groupedRoutes.forEach((items, layout) => {
|
||||
const layoutRoute: RouteRecordRaw = {
|
||||
path: `/${layout}-layout`,
|
||||
component: layouts[layout],
|
||||
children: items.map(item => {
|
||||
const { layout: _, component, ...rest } = item;
|
||||
|
||||
return {
|
||||
component: views[component],
|
||||
...rest
|
||||
};
|
||||
})
|
||||
};
|
||||
|
||||
vueRoutes.push(layoutRoute);
|
||||
});
|
||||
|
||||
return vueRoutes;
|
||||
}
|
||||
|
||||
function getFormattedRoutes(routes: AutoRouterRoute[]) {
|
||||
const groupedRoutes = new Map<RouteLayoutKey, AutoRouterSingleView[]>();
|
||||
const redirects: AutoRouterRedirect[] = [];
|
||||
|
||||
routes.forEach(route => {
|
||||
if (isAutoRouterRedirect(route)) {
|
||||
redirects.push(route);
|
||||
return;
|
||||
}
|
||||
|
||||
const items = groupedRoutes.get(route.layout) || [];
|
||||
items.push(route);
|
||||
groupedRoutes.set(route.layout, items);
|
||||
});
|
||||
|
||||
return {
|
||||
redirects,
|
||||
groupedRoutes
|
||||
};
|
||||
}
|
||||
|
||||
function isAutoRouterRedirect(route: AutoRouterRoute): route is AutoRouterRedirect {
|
||||
return 'redirect' in route;
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
/* eslint-disable */
|
||||
/* prettier-ignore */
|
||||
// Generated by elegant-router
|
||||
// Read more: https://github.com/soybeanjs/elegant-router
|
||||
|
||||
import type { RouteComponent } from "vue-router";
|
||||
import type { LastLevelRouteKey, RouteLayout } from "@elegant-router/types";
|
||||
|
||||
import BaseLayout from "@/layouts/base-layout/index.vue";
|
||||
import BlankLayout from "@/layouts/blank-layout/index.vue";
|
||||
|
||||
export const layouts: Record<RouteLayout, RouteComponent | (() => Promise<RouteComponent>)> = {
|
||||
base: BaseLayout,
|
||||
blank: BlankLayout,
|
||||
};
|
||||
|
||||
export const views: Record<LastLevelRouteKey, RouteComponent | (() => Promise<RouteComponent>)> = {
|
||||
403: () => import("@/views/_builtin/403/index.vue"),
|
||||
404: () => import("@/views/_builtin/404/index.vue"),
|
||||
500: () => import("@/views/_builtin/500/index.vue"),
|
||||
"iframe-page": () => import("@/views/_builtin/iframe-page/[url].vue"),
|
||||
login: () => import("@/views/_builtin/login/index.vue"),
|
||||
home: () => import("@/views/home/index.vue"),
|
||||
};
|
||||
@@ -1,78 +0,0 @@
|
||||
/* eslint-disable */
|
||||
/* prettier-ignore */
|
||||
// Generated by elegant-router
|
||||
// Read more: https://github.com/soybeanjs/elegant-router
|
||||
|
||||
import type { GeneratedRoute } from '@elegant-router/types';
|
||||
|
||||
export const generatedRoutes: GeneratedRoute[] = [
|
||||
{
|
||||
name: '403',
|
||||
path: '/403',
|
||||
component: 'layout.blank$view.403',
|
||||
meta: {
|
||||
title: '403',
|
||||
i18nKey: 'route.403',
|
||||
constant: true,
|
||||
hideInMenu: true
|
||||
}
|
||||
},
|
||||
{
|
||||
name: '404',
|
||||
path: '/404',
|
||||
component: 'layout.blank$view.404',
|
||||
meta: {
|
||||
title: '404',
|
||||
i18nKey: 'route.404',
|
||||
constant: true,
|
||||
hideInMenu: true
|
||||
}
|
||||
},
|
||||
{
|
||||
name: '500',
|
||||
path: '/500',
|
||||
component: 'layout.blank$view.500',
|
||||
meta: {
|
||||
title: '500',
|
||||
i18nKey: 'route.500',
|
||||
constant: true,
|
||||
hideInMenu: true
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'home',
|
||||
path: '/home',
|
||||
component: 'layout.base$view.home',
|
||||
meta: {
|
||||
title: 'home',
|
||||
i18nKey: 'route.home',
|
||||
icon: 'mdi:monitor-dashboard',
|
||||
order: 1
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'iframe-page',
|
||||
path: '/iframe-page/:url',
|
||||
component: 'layout.base$view.iframe-page',
|
||||
props: true,
|
||||
meta: {
|
||||
title: 'iframe-page',
|
||||
i18nKey: 'route.iframe-page',
|
||||
constant: true,
|
||||
hideInMenu: true,
|
||||
keepAlive: true
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'login',
|
||||
path: '/login/:module(pwd-login|code-login|register|reset-pwd|bind-wechat)?',
|
||||
component: 'layout.blank$view.login',
|
||||
props: true,
|
||||
meta: {
|
||||
title: 'login',
|
||||
i18nKey: 'route.login',
|
||||
constant: true,
|
||||
hideInMenu: true
|
||||
}
|
||||
}
|
||||
];
|
||||
@@ -1,192 +0,0 @@
|
||||
/* eslint-disable */
|
||||
/* prettier-ignore */
|
||||
// Generated by elegant-router
|
||||
// Read more: https://github.com/soybeanjs/elegant-router
|
||||
|
||||
import type { RouteRecordRaw, RouteComponent } from 'vue-router';
|
||||
import type { ElegantConstRoute } from '@elegant-router/vue';
|
||||
import type { RouteMap, RouteKey, RoutePath } from '@elegant-router/types';
|
||||
|
||||
/**
|
||||
* transform elegant const routes to vue routes
|
||||
* @param routes elegant const routes
|
||||
* @param layouts layout components
|
||||
* @param views view components
|
||||
*/
|
||||
export function transformElegantRoutesToVueRoutes(
|
||||
routes: ElegantConstRoute[],
|
||||
layouts: Record<string, RouteComponent | (() => Promise<RouteComponent>)>,
|
||||
views: Record<string, RouteComponent | (() => Promise<RouteComponent>)>
|
||||
) {
|
||||
return routes.flatMap(route => transformElegantRouteToVueRoute(route, layouts, views));
|
||||
}
|
||||
|
||||
/**
|
||||
* transform elegant route to vue route
|
||||
* @param route elegant const route
|
||||
* @param layouts layout components
|
||||
* @param views view components
|
||||
*/
|
||||
function transformElegantRouteToVueRoute(
|
||||
route: ElegantConstRoute,
|
||||
layouts: Record<string, RouteComponent | (() => Promise<RouteComponent>)>,
|
||||
views: Record<string, RouteComponent | (() => Promise<RouteComponent>)>
|
||||
) {
|
||||
const LAYOUT_PREFIX = 'layout.';
|
||||
const VIEW_PREFIX = 'view.';
|
||||
const ROUTE_DEGREE_SPLITTER = '_';
|
||||
const FIRST_LEVEL_ROUTE_COMPONENT_SPLIT = '$';
|
||||
|
||||
function isLayout(component: string) {
|
||||
return component.startsWith(LAYOUT_PREFIX);
|
||||
}
|
||||
|
||||
function getLayoutName(component: string) {
|
||||
const layout = component.replace(LAYOUT_PREFIX, '');
|
||||
|
||||
if(!layouts[layout]) {
|
||||
throw new Error(`Layout component "${layout}" not found`);
|
||||
}
|
||||
|
||||
return layout;
|
||||
}
|
||||
|
||||
function isView(component: string) {
|
||||
return component.startsWith(VIEW_PREFIX);
|
||||
}
|
||||
|
||||
function getViewName(component: string) {
|
||||
const view = component.replace(VIEW_PREFIX, '');
|
||||
|
||||
if(!views[view]) {
|
||||
throw new Error(`View component "${view}" not found`);
|
||||
}
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
function isFirstLevelRoute(item: ElegantConstRoute) {
|
||||
return !item.name.includes(ROUTE_DEGREE_SPLITTER);
|
||||
}
|
||||
|
||||
function isSingleLevelRoute(item: ElegantConstRoute) {
|
||||
return isFirstLevelRoute(item) && !item.children?.length;
|
||||
}
|
||||
|
||||
function getSingleLevelRouteComponent(component: string) {
|
||||
const [layout, view] = component.split(FIRST_LEVEL_ROUTE_COMPONENT_SPLIT);
|
||||
|
||||
return {
|
||||
layout: getLayoutName(layout),
|
||||
view: getViewName(view)
|
||||
};
|
||||
}
|
||||
|
||||
const vueRoutes: RouteRecordRaw[] = [];
|
||||
|
||||
// add props: true to route
|
||||
if (route.path.includes(':') && !route.props) {
|
||||
route.props = true;
|
||||
}
|
||||
|
||||
const { name, path, component, children, ...rest } = route;
|
||||
|
||||
const vueRoute = { name, path, ...rest } as RouteRecordRaw;
|
||||
|
||||
try {
|
||||
if (component) {
|
||||
if (isSingleLevelRoute(route)) {
|
||||
const { layout, view } = getSingleLevelRouteComponent(component);
|
||||
|
||||
const singleLevelRoute: RouteRecordRaw = {
|
||||
path,
|
||||
component: layouts[layout],
|
||||
meta: {
|
||||
title: route.meta?.title || ''
|
||||
},
|
||||
children: [
|
||||
{
|
||||
name,
|
||||
path: '',
|
||||
component: views[view],
|
||||
...rest
|
||||
} as RouteRecordRaw
|
||||
]
|
||||
};
|
||||
|
||||
return [singleLevelRoute];
|
||||
}
|
||||
|
||||
if (isLayout(component)) {
|
||||
const layoutName = getLayoutName(component);
|
||||
|
||||
vueRoute.component = layouts[layoutName];
|
||||
}
|
||||
|
||||
if (isView(component)) {
|
||||
const viewName = getViewName(component);
|
||||
|
||||
vueRoute.component = views[viewName];
|
||||
}
|
||||
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error(`Error transforming route "${route.name}": ${error.toString()}`);
|
||||
return [];
|
||||
}
|
||||
|
||||
// add redirect to child
|
||||
if (children?.length && !vueRoute.redirect) {
|
||||
vueRoute.redirect = {
|
||||
name: children[0].name
|
||||
};
|
||||
}
|
||||
|
||||
if (children?.length) {
|
||||
const childRoutes = children.flatMap(child => transformElegantRouteToVueRoute(child, layouts, views));
|
||||
|
||||
if(isFirstLevelRoute(route)) {
|
||||
vueRoute.children = childRoutes;
|
||||
} else {
|
||||
vueRoutes.push(...childRoutes);
|
||||
}
|
||||
}
|
||||
|
||||
vueRoutes.unshift(vueRoute);
|
||||
|
||||
return vueRoutes;
|
||||
}
|
||||
|
||||
/**
|
||||
* map of route name and route path
|
||||
*/
|
||||
const routeMap: RouteMap = {
|
||||
"root": "/",
|
||||
"not-found": "/:pathMatch(.*)*",
|
||||
"403": "/403",
|
||||
"404": "/404",
|
||||
"500": "/500",
|
||||
"home": "/home",
|
||||
"iframe-page": "/iframe-page/:url",
|
||||
"login": "/login/:module(pwd-login|code-login|register|reset-pwd|bind-wechat)?"
|
||||
};
|
||||
|
||||
/**
|
||||
* get route path by route name
|
||||
* @param name route name
|
||||
*/
|
||||
export function getRoutePath<T extends RouteKey>(name: T) {
|
||||
return routeMap[name];
|
||||
}
|
||||
|
||||
/**
|
||||
* get route name by route path
|
||||
* @param path route path
|
||||
*/
|
||||
export function getRouteName(path: RoutePath) {
|
||||
const routeEntries = Object.entries(routeMap) as [RouteKey, RoutePath][];
|
||||
|
||||
const routeName: RouteKey | null = routeEntries.find(([, routePath]) => routePath === path)?.[0] || null;
|
||||
|
||||
return routeName;
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
import type { Router } from 'vue-router';
|
||||
|
||||
export function createProgressGuard(router: Router) {
|
||||
router.beforeEach(() => {
|
||||
router.beforeEach((_to, _from, next) => {
|
||||
window.NProgress?.start?.();
|
||||
return;
|
||||
next();
|
||||
});
|
||||
router.afterEach(() => {
|
||||
router.afterEach(_to => {
|
||||
window.NProgress?.done?.();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
import type { LocationQueryRaw, RouteLocationNormalized, RouteLocationRaw, Router } from 'vue-router';
|
||||
import type {
|
||||
LocationQueryRaw,
|
||||
NavigationGuardNext,
|
||||
RouteLocationNormalized,
|
||||
RouteLocationRaw,
|
||||
Router
|
||||
} from 'vue-router';
|
||||
import type { RouteKey, RoutePath } from '@elegant-router/types';
|
||||
import { useAuthStore } from '@/store/modules/auth';
|
||||
import { useRouteStore } from '@/store/modules/route';
|
||||
@@ -11,11 +17,12 @@ import { getRouteName } from '@/router/elegant/transform';
|
||||
* @param router router instance
|
||||
*/
|
||||
export function createRouteGuard(router: Router) {
|
||||
router.beforeEach(async (to, from) => {
|
||||
router.beforeEach(async (to, from, next) => {
|
||||
const location = await initRoute(to);
|
||||
|
||||
if (location) {
|
||||
return location;
|
||||
next(location);
|
||||
return;
|
||||
}
|
||||
|
||||
const authStore = useAuthStore();
|
||||
@@ -33,26 +40,30 @@ export function createRouteGuard(router: Router) {
|
||||
|
||||
// if it is login route when logged in, then switch to the root page
|
||||
if (to.name === loginRoute && isLogin) {
|
||||
return { name: rootRoute };
|
||||
next({ name: rootRoute });
|
||||
return;
|
||||
}
|
||||
|
||||
// if the route does not need login, then it is allowed to access directly
|
||||
if (!needLogin) {
|
||||
return handleRouteSwitch(to, from);
|
||||
handleRouteSwitch(to, from, next);
|
||||
return;
|
||||
}
|
||||
|
||||
// the route need login but the user is not logged in, then switch to the login page
|
||||
if (!isLogin) {
|
||||
return { name: loginRoute, query: { redirect: to.fullPath } };
|
||||
next({ name: loginRoute, query: { redirect: to.fullPath } });
|
||||
return;
|
||||
}
|
||||
|
||||
// if the user is logged in but does not have authorization, then switch to the 403 page
|
||||
if (!hasAuth) {
|
||||
return { name: noAuthorizationRoute };
|
||||
next({ name: noAuthorizationRoute });
|
||||
return;
|
||||
}
|
||||
|
||||
// switch route normally
|
||||
return handleRouteSwitch(to, from);
|
||||
handleRouteSwitch(to, from, next);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -150,13 +161,17 @@ async function initRoute(to: RouteLocationNormalized): Promise<RouteLocationRaw
|
||||
return null;
|
||||
}
|
||||
|
||||
function handleRouteSwitch(to: RouteLocationNormalized, from: RouteLocationNormalized) {
|
||||
function handleRouteSwitch(to: RouteLocationNormalized, from: RouteLocationNormalized, next: NavigationGuardNext) {
|
||||
// route with href
|
||||
if (to.meta.href) {
|
||||
window.open(to.meta.href, '_blank');
|
||||
|
||||
return { path: from.fullPath, replace: true, query: from.query, hash: to.hash };
|
||||
next({ path: from.fullPath, replace: true, query: from.query, hash: to.hash });
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
next();
|
||||
}
|
||||
|
||||
function getRouteQueryOfLoginRoute(to: RouteLocationNormalized, routeHome: RouteKey) {
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
import type { App } from 'vue';
|
||||
import {
|
||||
type RouterHistory,
|
||||
createMemoryHistory,
|
||||
createRouter,
|
||||
createWebHashHistory,
|
||||
createWebHistory
|
||||
} from 'vue-router';
|
||||
import { createMemoryHistory, createRouter, createWebHashHistory, createWebHistory } from 'vue-router';
|
||||
import type { RouterHistory } from 'vue-router';
|
||||
import { createBuiltinVueRoutes } from './routes/builtin';
|
||||
import { createRouterGuard } from './guard';
|
||||
|
||||
@@ -25,6 +20,6 @@ export const router = createRouter({
|
||||
/** Setup Vue Router */
|
||||
export async function setupRouter(app: App) {
|
||||
app.use(router);
|
||||
createRouterGuard(router);
|
||||
// createRouterGuard(router);
|
||||
await router.isReady();
|
||||
}
|
||||
|
||||
@@ -1,31 +1,39 @@
|
||||
import type { CustomRoute } from '@elegant-router/types';
|
||||
import { layouts, views } from '../elegant/imports';
|
||||
import { getRoutePath, transformElegantRoutesToVueRoutes } from '../elegant/transform';
|
||||
import type { AutoRouterRedirect, AutoRouterRoute, AutoRouterSingleView } from '@elegant-router/types';
|
||||
import { layouts, views } from '../_generated/imports';
|
||||
import { transformToVueRoutes } from '../_generated/transformer';
|
||||
import { routes } from '../_generated/routes';
|
||||
|
||||
export const ROOT_ROUTE: CustomRoute = {
|
||||
name: 'root',
|
||||
/**
|
||||
* 根路由
|
||||
*/
|
||||
export const ROOT_ROUTE: AutoRouterRedirect = {
|
||||
name: 'Root',
|
||||
path: '/',
|
||||
redirect: getRoutePath(import.meta.env.VITE_ROUTE_HOME) || '/home',
|
||||
redirect: import.meta.env.VITE_ROUTE_HOME_PATH || '/home',
|
||||
meta: {
|
||||
title: 'root',
|
||||
title: 'Root',
|
||||
constant: true
|
||||
}
|
||||
};
|
||||
|
||||
const NOT_FOUND_ROUTE: CustomRoute = {
|
||||
name: 'not-found',
|
||||
/**
|
||||
* 404 路由
|
||||
*/
|
||||
export const NOT_FOUND_ROUTE: AutoRouterSingleView = {
|
||||
name: 'NotFound',
|
||||
path: '/:pathMatch(.*)*',
|
||||
component: 'layout.blank$view.404',
|
||||
component: '404',
|
||||
layout: 'blank',
|
||||
meta: {
|
||||
title: 'not-found',
|
||||
title: 'NotFound',
|
||||
constant: true
|
||||
}
|
||||
};
|
||||
|
||||
/** builtin routes, it must be constant and setup in vue-router */
|
||||
const builtinRoutes: CustomRoute[] = [ROOT_ROUTE, NOT_FOUND_ROUTE];
|
||||
/** 内置路由,必须是常量路由,且必须在 vue-router 中设置 */
|
||||
const builtinRoutes: AutoRouterRoute[] = [ROOT_ROUTE, NOT_FOUND_ROUTE, ...routes];
|
||||
|
||||
/** create builtin vue routes */
|
||||
/** 创建内置 vue 路由 */
|
||||
export function createBuiltinVueRoutes() {
|
||||
return transformElegantRoutesToVueRoutes(builtinRoutes, layouts, views);
|
||||
return transformToVueRoutes(builtinRoutes, layouts, views);
|
||||
}
|
||||
|
||||
@@ -1,22 +1,14 @@
|
||||
import type { CustomRoute, ElegantConstRoute, ElegantRoute } from '@elegant-router/types';
|
||||
import { generatedRoutes } from '../elegant/routes';
|
||||
import { layouts, views } from '../elegant/imports';
|
||||
import { transformElegantRoutesToVueRoutes } from '../elegant/transform';
|
||||
import type { AutoRouterRoute } from '@elegant-router/types';
|
||||
import { routes } from '../_generated/routes';
|
||||
import { layouts, views } from '../_generated/imports';
|
||||
import { transformToVueRoutes } from '../_generated/transformer';
|
||||
|
||||
/**
|
||||
* custom routes
|
||||
*
|
||||
* @link https://github.com/soybeanjs/elegant-router?tab=readme-ov-file#custom-route
|
||||
*/
|
||||
const customRoutes: CustomRoute[] = [];
|
||||
|
||||
/** create routes when the auth route mode is static */
|
||||
/** 创建静态路由 */
|
||||
export function createStaticRoutes() {
|
||||
const constantRoutes: ElegantRoute[] = [];
|
||||
const constantRoutes: AutoRouterRoute[] = [];
|
||||
const authRoutes: AutoRouterRoute[] = [];
|
||||
|
||||
const authRoutes: ElegantRoute[] = [];
|
||||
|
||||
[...customRoutes, ...generatedRoutes].forEach(item => {
|
||||
routes.forEach(item => {
|
||||
if (item.meta?.constant) {
|
||||
constantRoutes.push(item);
|
||||
} else {
|
||||
@@ -31,10 +23,10 @@ export function createStaticRoutes() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get auth vue routes
|
||||
* 获取认证路由
|
||||
*
|
||||
* @param routes Elegant routes
|
||||
* @param authRoutes 认证路由
|
||||
*/
|
||||
export function getAuthVueRoutes(routes: ElegantConstRoute[]) {
|
||||
return transformElegantRoutesToVueRoutes(routes, layouts, views);
|
||||
export function getAuthVueRoutes(authRoutes: AutoRouterRoute[]) {
|
||||
return transformToVueRoutes(authRoutes, layouts, views);
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ export const useAuthStore = defineStore(SetupStoreId.Auth, () => {
|
||||
const { toLogin, redirectFromLogin } = useRouterPush(false);
|
||||
const { loading: loginLoading, startLoading, endLoading } = useLoading();
|
||||
|
||||
const token = ref('');
|
||||
const token = ref(getToken());
|
||||
|
||||
const userInfo: Api.Auth.UserInfo = reactive({
|
||||
userId: '',
|
||||
@@ -159,10 +159,9 @@ export const useAuthStore = defineStore(SetupStoreId.Auth, () => {
|
||||
}
|
||||
|
||||
async function initUserInfo() {
|
||||
const maybeToken = getToken();
|
||||
const hasToken = getToken();
|
||||
|
||||
if (maybeToken) {
|
||||
token.value = maybeToken;
|
||||
if (hasToken) {
|
||||
const pass = await getUserInfo();
|
||||
|
||||
if (!pass) {
|
||||
|
||||
70
src/typings/api/common.d.ts
vendored
70
src/typings/api/common.d.ts
vendored
@@ -5,46 +5,38 @@
|
||||
*/
|
||||
declare namespace Api {
|
||||
namespace Common {
|
||||
/** common params of paginating */
|
||||
interface PaginatingCommonParams {
|
||||
/** current page number */
|
||||
current: number;
|
||||
/** page size */
|
||||
size: number;
|
||||
/** total count */
|
||||
interface CreatedUpdatedDTO {
|
||||
/** 创建人 */
|
||||
createdBy: string;
|
||||
/** 创建时间 */
|
||||
createdTime: string;
|
||||
/** 更新人 */
|
||||
updatedBy: string;
|
||||
/** 更新时间 */
|
||||
updatedTime: string;
|
||||
}
|
||||
|
||||
interface CommonRecordDTO extends CreatedUpdatedDTO {
|
||||
/** 主键 */
|
||||
id: number;
|
||||
/**
|
||||
* 启用状态 Enable status
|
||||
*
|
||||
* - "1": 启用
|
||||
* - "2": 禁用
|
||||
*/
|
||||
status: Union.EnableStatus | null;
|
||||
}
|
||||
|
||||
interface PaginationQueryDTO {
|
||||
page: number;
|
||||
pageSize: number;
|
||||
sort: string;
|
||||
}
|
||||
|
||||
interface PaginationDTO extends Pick<PaginationQueryDTO, 'page' | 'pageSize'> {
|
||||
/** 总条数 */
|
||||
total: number;
|
||||
}
|
||||
|
||||
/** common params of paginating query list data */
|
||||
interface PaginatingQueryRecord<T = any> extends PaginatingCommonParams {
|
||||
records: T[];
|
||||
}
|
||||
|
||||
/** common search params of table */
|
||||
type CommonSearchParams = Pick<Common.PaginatingCommonParams, 'current' | 'size'>;
|
||||
|
||||
/**
|
||||
* enable status
|
||||
*
|
||||
* - "1": enabled
|
||||
* - "2": disabled
|
||||
*/
|
||||
type EnableStatus = '1' | '2';
|
||||
|
||||
/** common record */
|
||||
type CommonRecord<T = any> = {
|
||||
/** record id */
|
||||
id: number;
|
||||
/** record creator */
|
||||
createBy: string;
|
||||
/** record create time */
|
||||
createTime: string;
|
||||
/** record updater */
|
||||
updateBy: string;
|
||||
/** record update time */
|
||||
updateTime: string;
|
||||
/** record status */
|
||||
status: EnableStatus | null;
|
||||
} & T;
|
||||
}
|
||||
}
|
||||
|
||||
42
src/typings/api/menu.d.ts
vendored
Normal file
42
src/typings/api/menu.d.ts
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
declare namespace Api {
|
||||
namespace Menu {
|
||||
type RouteKey = import('@elegant-router/types').RouteKey;
|
||||
|
||||
interface Menu extends Common.CommonRecordDTO {
|
||||
/** 菜单名称 */
|
||||
name: string;
|
||||
/** 菜单类型 */
|
||||
menuType: Union.MenuType;
|
||||
/** 菜单描述 */
|
||||
description?: string | null;
|
||||
/** 菜单图标 */
|
||||
icon?: string | null;
|
||||
/** 菜单图标类型 */
|
||||
iconType?: string | null;
|
||||
/** 父级菜单ID */
|
||||
parentId?: number | null;
|
||||
/** 菜单排序 */
|
||||
order?: number | null;
|
||||
/** 是否隐藏 */
|
||||
isHidden?: boolean | null;
|
||||
/** iframe 页面URL */
|
||||
iframeUrl?: string | null;
|
||||
/** 链接 */
|
||||
href?: string | null;
|
||||
/** 路由名称 */
|
||||
routeName?: RouteKey | null;
|
||||
/** 路由查询参数 */
|
||||
routeQueries?: Record<string, string | number | boolean> | null;
|
||||
/** 路由路径参数 */
|
||||
routeParams?: Record<string, string | number | boolean> | null;
|
||||
}
|
||||
|
||||
interface MenuListDTO extends Common.PaginationDTO {
|
||||
list: Menu[];
|
||||
}
|
||||
|
||||
interface MenuTreeDTO extends Menu {
|
||||
children?: MenuTreeDTO[];
|
||||
}
|
||||
}
|
||||
}
|
||||
39
src/typings/api/route.d.ts
vendored
39
src/typings/api/route.d.ts
vendored
@@ -1,19 +1,34 @@
|
||||
declare namespace Api {
|
||||
/**
|
||||
* namespace Route
|
||||
*
|
||||
* backend api module: "route"
|
||||
*/
|
||||
namespace Route {
|
||||
type ElegantConstRoute = import('@elegant-router/types').ElegantConstRoute;
|
||||
|
||||
interface MenuRoute extends ElegantConstRoute {
|
||||
id: string;
|
||||
interface RouteDTO extends Common.CommonRecordDTO {
|
||||
/** 路由路径 */
|
||||
path: string;
|
||||
/** 路由名称 */
|
||||
name: string;
|
||||
/** 路由布局 */
|
||||
layout: string;
|
||||
/** 路由组件 */
|
||||
component: string;
|
||||
/** 重定向路径 */
|
||||
redirect?: string | null;
|
||||
/** 路由图标 */
|
||||
icon?: string | null;
|
||||
/** 路由图标类型 */
|
||||
iconType?: string | null;
|
||||
/** 是否缓存 */
|
||||
isCache?: boolean | null;
|
||||
/** 是否支持多开 */
|
||||
isMultiple?: boolean | null;
|
||||
/** 固定索引 */
|
||||
fixedIndex?: number | null;
|
||||
/** 是否需要权限 */
|
||||
requireAuth?: boolean | null;
|
||||
/** 路由属性 */
|
||||
props?: Record<string, string | number | boolean> | null;
|
||||
}
|
||||
|
||||
interface UserRoute {
|
||||
routes: MenuRoute[];
|
||||
home: import('@elegant-router/types').LastLevelRouteKey;
|
||||
interface RouteListDTO extends Common.PaginationDTO {
|
||||
list: RouteDTO[];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
31
src/typings/api/union.d.ts
vendored
Normal file
31
src/typings/api/union.d.ts
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
declare namespace Api {
|
||||
namespace Union {
|
||||
/**
|
||||
* 是否 Yes or No
|
||||
*
|
||||
* - "Y": yes
|
||||
* - "N": no
|
||||
*/
|
||||
type YesOrNo = 'Y' | 'N';
|
||||
|
||||
/**
|
||||
* 启用状态 Enable status
|
||||
*
|
||||
* - "1": 启用
|
||||
* - "2": 禁用
|
||||
*/
|
||||
type EnableStatus = '1' | '2';
|
||||
|
||||
/**
|
||||
* 菜单类型
|
||||
*
|
||||
* - "directory": 目录
|
||||
* - "menu": 菜单
|
||||
* - "iframe": iframe 页面(iframe 嵌入页面)
|
||||
* - "link": 链接(跳转外部链接)
|
||||
* - "page": 页面(不展示在菜单中,可用于作为菜单类型的子菜单展示在面包屑中)
|
||||
* - "other": 其他(作用自行定义)
|
||||
*/
|
||||
type MenuType = 'page' | 'directory' | 'menu' | 'iframe' | 'link' | 'other';
|
||||
}
|
||||
}
|
||||
99
src/typings/app.d.ts
vendored
99
src/typings/app.d.ts
vendored
@@ -188,15 +188,14 @@ declare namespace App {
|
||||
type VNode = import('vue').VNode;
|
||||
type RouteLocationNormalizedLoaded = import('vue-router').RouteLocationNormalizedLoaded;
|
||||
type RouteKey = import('@elegant-router/types').RouteKey;
|
||||
type RouteMap = import('@elegant-router/types').RouteMap;
|
||||
type RoutePathMap = import('@elegant-router/types').RoutePathMap;
|
||||
type RoutePath = import('@elegant-router/types').RoutePath;
|
||||
type LastLevelRouteKey = import('@elegant-router/types').LastLevelRouteKey;
|
||||
type RouteFileKey = import('@elegant-router/types').RouteFileKey;
|
||||
|
||||
/** The router push options */
|
||||
type RouterPushOptions = {
|
||||
query?: Record<string, string>;
|
||||
params?: Record<string, string>;
|
||||
force?: boolean;
|
||||
};
|
||||
|
||||
/** The global header props */
|
||||
@@ -209,77 +208,25 @@ declare namespace App {
|
||||
showMenu?: boolean;
|
||||
}
|
||||
|
||||
type MenuType = 'page' | 'directory' | 'menu' | 'iframe' | 'link' | 'button' | 'other';
|
||||
|
||||
/** The global menu */
|
||||
type Menu = {
|
||||
/**
|
||||
* The menu key
|
||||
*
|
||||
* Equal to the route key
|
||||
*/
|
||||
key: string;
|
||||
/** The menu label */
|
||||
label: string;
|
||||
/** The menu i18n key */
|
||||
i18nKey?: I18n.I18nKey | null;
|
||||
/** The route key */
|
||||
routeKey: RouteKey;
|
||||
/** The route path */
|
||||
routePath: RoutePath;
|
||||
/** The menu icon */
|
||||
icon?: () => VNode;
|
||||
/** The menu children */
|
||||
children?: Menu[];
|
||||
};
|
||||
|
||||
type Breadcrumb = Omit<Menu, 'children'> & {
|
||||
options?: Breadcrumb[];
|
||||
};
|
||||
|
||||
/** Tab route */
|
||||
type TabRoute = Pick<RouteLocationNormalizedLoaded, 'name' | 'path' | 'meta'> &
|
||||
Partial<Pick<RouteLocationNormalizedLoaded, 'fullPath' | 'query' | 'matched'>>;
|
||||
|
||||
/** The global tab */
|
||||
type Tab = {
|
||||
/** The tab id */
|
||||
id: string;
|
||||
/** The tab label */
|
||||
label: string;
|
||||
/**
|
||||
* The new tab label
|
||||
*
|
||||
* If set, the tab label will be replaced by this value
|
||||
*/
|
||||
newLabel?: string;
|
||||
/**
|
||||
* The old tab label
|
||||
*
|
||||
* when reset the tab label, the tab label will be replaced by this value
|
||||
*/
|
||||
oldLabel?: string;
|
||||
/** The tab route key */
|
||||
routeKey: LastLevelRouteKey;
|
||||
/** The tab route path */
|
||||
routePath: RouteMap[LastLevelRouteKey];
|
||||
/** The tab route full path */
|
||||
fullPath: string;
|
||||
/** The tab fixed index */
|
||||
fixedIndex?: number | null;
|
||||
/**
|
||||
* Tab icon
|
||||
*
|
||||
* Iconify icon
|
||||
*/
|
||||
icon?: string;
|
||||
/**
|
||||
* Tab local icon
|
||||
*
|
||||
* Local icon
|
||||
*/
|
||||
localIcon?: string;
|
||||
/** I18n key */
|
||||
i18nKey?: I18n.I18nKey | null;
|
||||
};
|
||||
interface Menu {
|
||||
id: number;
|
||||
name: string;
|
||||
menuType: MenuType;
|
||||
description?: string | null;
|
||||
icon?: string | null;
|
||||
iconType?: string | null;
|
||||
parentId?: number | null;
|
||||
order?: number | null;
|
||||
isHidden?: boolean | null;
|
||||
iframeUrl?: string | null;
|
||||
href?: string | null;
|
||||
routeName?: RouteKey | null;
|
||||
routeQueries?: Record<string, string | number | boolean> | null;
|
||||
routeParams?: Record<string, string | number | boolean> | null;
|
||||
}
|
||||
|
||||
/** Form rule */
|
||||
type FormRule = import('naive-ui').FormItemRule;
|
||||
@@ -327,7 +274,6 @@ declare namespace App {
|
||||
cancel: string;
|
||||
close: string;
|
||||
check: string;
|
||||
selectAll: string;
|
||||
expandColumn: string;
|
||||
columnSetting: string;
|
||||
config: string;
|
||||
@@ -580,11 +526,6 @@ declare namespace App {
|
||||
};
|
||||
datatable: {
|
||||
itemCount: string;
|
||||
fixed: {
|
||||
left: string;
|
||||
right: string;
|
||||
unFixed: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
236
src/typings/elegant-router.d.ts
vendored
236
src/typings/elegant-router.d.ts
vendored
@@ -1,240 +1,100 @@
|
||||
/* eslint-disable */
|
||||
/* prettier-ignore */
|
||||
/* oxlint-disable */
|
||||
// biome-ignore lint: disable
|
||||
// Generated by elegant-router
|
||||
// Read more: https://github.com/soybeanjs/elegant-router
|
||||
|
||||
declare module "@elegant-router/types" {
|
||||
type ElegantConstRoute = import('@elegant-router/vue').ElegantConstRoute;
|
||||
type RouteRecordSingleView = import("vue-router").RouteRecordSingleView;
|
||||
type RouteRecordRedirect = import("vue-router").RouteRecordRedirect;
|
||||
type RouteComponent = import("vue-router").RouteComponent;
|
||||
|
||||
type Lazy<T> = () => Promise<T>;
|
||||
|
||||
export type RawRouteComponent = RouteComponent | Lazy<RouteComponent>;
|
||||
|
||||
/**
|
||||
* route layout
|
||||
* route layout key
|
||||
*/
|
||||
export type RouteLayout = "base" | "blank";
|
||||
export type RouteLayoutKey = "base" | "blank";
|
||||
|
||||
/**
|
||||
* route map
|
||||
* route path map
|
||||
*/
|
||||
export type RouteMap = {
|
||||
"root": "/";
|
||||
"not-found": "/:pathMatch(.*)*";
|
||||
export type RoutePathMap = {
|
||||
"Root": "/";
|
||||
"NotFound": "/:pathMatch(.*)*";
|
||||
"403": "/403";
|
||||
"404": "/404";
|
||||
"500": "/500";
|
||||
"home": "/home";
|
||||
"iframe-page": "/iframe-page/:url";
|
||||
"login": "/login/:module(pwd-login|code-login|register|reset-pwd|bind-wechat)?";
|
||||
"Home": "/home";
|
||||
"IframeUrl": "/iframe/:url";
|
||||
"Login": "/login/:module(pwd-login|code-login|register|reset-pwd|bind-wechat)?";
|
||||
"ManageMenu": "/manage/menu";
|
||||
"ManageRole": "/manage/role";
|
||||
"ManageRoute": "/manage/route";
|
||||
"ManageUser": "/manage/user";
|
||||
"Wip": "/wip";
|
||||
};
|
||||
|
||||
/**
|
||||
* route key
|
||||
*/
|
||||
export type RouteKey = keyof RouteMap;
|
||||
export type RouteKey = keyof RoutePathMap;
|
||||
|
||||
/**
|
||||
* route path
|
||||
*/
|
||||
export type RoutePath = RouteMap[RouteKey];
|
||||
export type RoutePath = RoutePathMap[RouteKey];
|
||||
|
||||
/**
|
||||
* custom route key
|
||||
* root route key
|
||||
*/
|
||||
export type CustomRouteKey = Extract<
|
||||
RouteKey,
|
||||
| "root"
|
||||
| "not-found"
|
||||
>;
|
||||
export type RootRouteKey = 'Root';
|
||||
|
||||
/**
|
||||
* the generated route key
|
||||
* not found route key
|
||||
*/
|
||||
export type GeneratedRouteKey = Exclude<RouteKey, CustomRouteKey>;
|
||||
export type NotFoundRouteKey = 'NotFound';
|
||||
|
||||
/**
|
||||
* the first level route key, which contain the layout of the route
|
||||
* builtin route key
|
||||
*/
|
||||
export type FirstLevelRouteKey = Extract<
|
||||
RouteKey,
|
||||
| "403"
|
||||
| "404"
|
||||
| "500"
|
||||
| "home"
|
||||
| "iframe-page"
|
||||
| "login"
|
||||
>;
|
||||
export type BuiltinRouteKey = RootRouteKey | NotFoundRouteKey;
|
||||
|
||||
/**
|
||||
* the custom first level route key
|
||||
* reuse route key
|
||||
*/
|
||||
export type CustomFirstLevelRouteKey = Extract<
|
||||
CustomRouteKey,
|
||||
| "root"
|
||||
| "not-found"
|
||||
>;
|
||||
export type ReuseRouteKey = never;
|
||||
|
||||
/**
|
||||
* the last level route key, which has the page file
|
||||
* the route file key, which has it's own file
|
||||
*/
|
||||
export type LastLevelRouteKey = Extract<
|
||||
RouteKey,
|
||||
| "403"
|
||||
| "404"
|
||||
| "500"
|
||||
| "iframe-page"
|
||||
| "login"
|
||||
| "home"
|
||||
>;
|
||||
export type RouteFileKey = Exclude<RouteKey, BuiltinRouteKey | ReuseRouteKey>;
|
||||
|
||||
/**
|
||||
* the custom last level route key
|
||||
* mapped name and path
|
||||
*/
|
||||
export type CustomLastLevelRouteKey = Extract<
|
||||
CustomRouteKey,
|
||||
| "root"
|
||||
| "not-found"
|
||||
>;
|
||||
type MappedNamePath = {
|
||||
[K in RouteKey]: { name: K; path: RoutePathMap[K] };
|
||||
}[RouteKey];
|
||||
|
||||
/**
|
||||
* the single level route key
|
||||
* auto router single view
|
||||
*/
|
||||
export type SingleLevelRouteKey = FirstLevelRouteKey & LastLevelRouteKey;
|
||||
export type AutoRouterSingleView = Omit<RouteRecordSingleView, 'component' | 'name' | 'path'> & {
|
||||
component: RouteFileKey;
|
||||
layout: RouteLayoutKey;
|
||||
} & MappedNamePath;
|
||||
|
||||
/**
|
||||
* the custom single level route key
|
||||
* auto router redirect
|
||||
*/
|
||||
export type CustomSingleLevelRouteKey = CustomFirstLevelRouteKey & CustomLastLevelRouteKey;
|
||||
export type AutoRouterRedirect = Omit<RouteRecordRedirect, 'children' | 'name' | 'path'> & MappedNamePath;
|
||||
|
||||
/**
|
||||
* the first level route key, but not the single level
|
||||
*/
|
||||
export type FirstLevelRouteNotSingleKey = Exclude<FirstLevelRouteKey, SingleLevelRouteKey>;
|
||||
|
||||
/**
|
||||
* the custom first level route key, but not the single level
|
||||
* auto router route
|
||||
*/
|
||||
export type CustomFirstLevelRouteNotSingleKey = Exclude<CustomFirstLevelRouteKey, CustomSingleLevelRouteKey>;
|
||||
|
||||
/**
|
||||
* the center level route key
|
||||
*/
|
||||
export type CenterLevelRouteKey = Exclude<GeneratedRouteKey, FirstLevelRouteKey | LastLevelRouteKey>;
|
||||
|
||||
/**
|
||||
* the custom center level route key
|
||||
*/
|
||||
export type CustomCenterLevelRouteKey = Exclude<CustomRouteKey, CustomFirstLevelRouteKey | CustomLastLevelRouteKey>;
|
||||
|
||||
/**
|
||||
* the center level route key
|
||||
*/
|
||||
type GetChildRouteKey<K extends RouteKey, T extends RouteKey = RouteKey> = T extends `${K}_${infer R}`
|
||||
? R extends `${string}_${string}`
|
||||
? never
|
||||
: T
|
||||
: never;
|
||||
|
||||
/**
|
||||
* the single level route
|
||||
*/
|
||||
type SingleLevelRoute<K extends SingleLevelRouteKey = SingleLevelRouteKey> = K extends string
|
||||
? Omit<ElegantConstRoute, 'children'> & {
|
||||
name: K;
|
||||
path: RouteMap[K];
|
||||
component: `layout.${RouteLayout}$view.${K}`;
|
||||
}
|
||||
: never;
|
||||
|
||||
/**
|
||||
* the last level route
|
||||
*/
|
||||
type LastLevelRoute<K extends GeneratedRouteKey> = K extends LastLevelRouteKey
|
||||
? Omit<ElegantConstRoute, 'children'> & {
|
||||
name: K;
|
||||
path: RouteMap[K];
|
||||
component: `view.${K}`;
|
||||
}
|
||||
: never;
|
||||
|
||||
/**
|
||||
* the center level route
|
||||
*/
|
||||
type CenterLevelRoute<K extends GeneratedRouteKey> = K extends CenterLevelRouteKey
|
||||
? Omit<ElegantConstRoute, 'component'> & {
|
||||
name: K;
|
||||
path: RouteMap[K];
|
||||
children: (CenterLevelRoute<GetChildRouteKey<K>> | LastLevelRoute<GetChildRouteKey<K>>)[];
|
||||
}
|
||||
: never;
|
||||
|
||||
/**
|
||||
* the multi level route
|
||||
*/
|
||||
type MultiLevelRoute<K extends FirstLevelRouteNotSingleKey = FirstLevelRouteNotSingleKey> = K extends string
|
||||
? ElegantConstRoute & {
|
||||
name: K;
|
||||
path: RouteMap[K];
|
||||
component: `layout.${RouteLayout}`;
|
||||
children: (CenterLevelRoute<GetChildRouteKey<K>> | LastLevelRoute<GetChildRouteKey<K>>)[];
|
||||
}
|
||||
: never;
|
||||
|
||||
/**
|
||||
* the custom first level route
|
||||
*/
|
||||
type CustomSingleLevelRoute<K extends CustomFirstLevelRouteKey = CustomFirstLevelRouteKey> = K extends string
|
||||
? Omit<ElegantConstRoute, 'children'> & {
|
||||
name: K;
|
||||
path: RouteMap[K];
|
||||
component?: `layout.${RouteLayout}$view.${LastLevelRouteKey}`;
|
||||
}
|
||||
: never;
|
||||
|
||||
/**
|
||||
* the custom last level route
|
||||
*/
|
||||
type CustomLastLevelRoute<K extends CustomRouteKey> = K extends CustomLastLevelRouteKey
|
||||
? Omit<ElegantConstRoute, 'children'> & {
|
||||
name: K;
|
||||
path: RouteMap[K];
|
||||
component?: `view.${LastLevelRouteKey}`;
|
||||
}
|
||||
: never;
|
||||
|
||||
/**
|
||||
* the custom center level route
|
||||
*/
|
||||
type CustomCenterLevelRoute<K extends CustomRouteKey> = K extends CustomCenterLevelRouteKey
|
||||
? Omit<ElegantConstRoute, 'component'> & {
|
||||
name: K;
|
||||
path: RouteMap[K];
|
||||
children: (CustomCenterLevelRoute<GetChildRouteKey<K>> | CustomLastLevelRoute<GetChildRouteKey<K>>)[];
|
||||
}
|
||||
: never;
|
||||
|
||||
/**
|
||||
* the custom multi level route
|
||||
*/
|
||||
type CustomMultiLevelRoute<K extends CustomFirstLevelRouteNotSingleKey = CustomFirstLevelRouteNotSingleKey> =
|
||||
K extends string
|
||||
? ElegantConstRoute & {
|
||||
name: K;
|
||||
path: RouteMap[K];
|
||||
component: `layout.${RouteLayout}`;
|
||||
children: (CustomCenterLevelRoute<GetChildRouteKey<K>> | CustomLastLevelRoute<GetChildRouteKey<K>>)[];
|
||||
}
|
||||
: never;
|
||||
|
||||
/**
|
||||
* the custom route
|
||||
*/
|
||||
type CustomRoute = CustomSingleLevelRoute | CustomMultiLevelRoute;
|
||||
|
||||
/**
|
||||
* the generated route
|
||||
*/
|
||||
type GeneratedRoute = SingleLevelRoute | MultiLevelRoute;
|
||||
|
||||
/**
|
||||
* the elegant route
|
||||
*/
|
||||
type ElegantRoute = GeneratedRoute | CustomRoute;
|
||||
export type AutoRouterRoute = AutoRouterSingleView | AutoRouterRedirect;
|
||||
}
|
||||
|
||||
1
src/typings/naive-ui.d.ts
vendored
1
src/typings/naive-ui.d.ts
vendored
@@ -7,7 +7,6 @@ declare namespace NaiveUI {
|
||||
type DataTableSelectionColumn<T> = import('naive-ui').DataTableSelectionColumn<T>;
|
||||
type TableColumnGroup<T> = import('naive-ui/es/data-table/src/interface').TableColumnGroup<T>;
|
||||
type TableColumnCheck = import('@sa/hooks').TableColumnCheck;
|
||||
type TableColumnFixed = import('@sa/hooks').TableColumnCheck['fixed'];
|
||||
|
||||
type SetTableColumnKey<C, T> = Omit<C, 'key'> & { key: keyof T | (string & {}) };
|
||||
|
||||
|
||||
4
src/typings/router.d.ts
vendored
4
src/typings/router.d.ts
vendored
@@ -1,7 +1,7 @@
|
||||
import 'vue-router';
|
||||
export {};
|
||||
|
||||
declare module 'vue-router' {
|
||||
interface RouteMeta {
|
||||
export interface RouteMeta {
|
||||
/**
|
||||
* Title of the route
|
||||
*
|
||||
|
||||
40
src/typings/typed-router.d.ts
vendored
Normal file
40
src/typings/typed-router.d.ts
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
/* eslint-disable */
|
||||
// @ts-nocheck
|
||||
/* prettier-ignore */
|
||||
/* oxlint-disable */
|
||||
// biome-ignore lint: disable
|
||||
// Generated by elegant-router
|
||||
// Read more: https://github.com/soybeanjs/elegant-router
|
||||
|
||||
export {}
|
||||
|
||||
declare module "vue-router" {
|
||||
type RouteNamedMap = import("vue-router/auto-routes").RouteNamedMap;
|
||||
|
||||
export interface TypesConfig {
|
||||
RouteNamedMap: RouteNamedMap;
|
||||
}
|
||||
}
|
||||
|
||||
declare module "vue-router/auto-routes" {
|
||||
import type { RouteParamsRawGeneric, RouteParamsGeneric, RouteMeta, RouteRecordInfo, ParamValue, ParamValueZeroOrOne } from "vue-router";
|
||||
|
||||
/**
|
||||
* route named map
|
||||
*/
|
||||
export interface RouteNamedMap {
|
||||
"Root": RouteRecordInfo<"Root", "/", Record<never, never>, Record<never, never>>;
|
||||
"NotFound": RouteRecordInfo<"NotFound", "/:pathMatch(.*)*", Record<never, never>, Record<never, never>>;
|
||||
"403": RouteRecordInfo<"403", "/403", Record<never, never>, Record<never, never>>;
|
||||
"404": RouteRecordInfo<"404", "/404", Record<never, never>, Record<never, never>>;
|
||||
"500": RouteRecordInfo<"500", "/500", Record<never, never>, Record<never, never>>;
|
||||
"Home": RouteRecordInfo<"Home", "/home", Record<never, never>, Record<never, never>>;
|
||||
"IframeUrl": RouteRecordInfo<"IframeUrl", "/iframe/:url", { url: ParamValue<true> }, { url: ParamValue<false> }>;
|
||||
"Login": RouteRecordInfo<"Login", "/login/:module(pwd-login|code-login|register|reset-pwd|bind-wechat)?", { module?: ParamValueZeroOrOne<true> }, { module?: ParamValueZeroOrOne<false> }>;
|
||||
"ManageMenu": RouteRecordInfo<"ManageMenu", "/manage/menu", Record<never, never>, Record<never, never>>;
|
||||
"ManageRole": RouteRecordInfo<"ManageRole", "/manage/role", Record<never, never>, Record<never, never>>;
|
||||
"ManageRoute": RouteRecordInfo<"ManageRoute", "/manage/route", Record<never, never>, Record<never, never>>;
|
||||
"ManageUser": RouteRecordInfo<"ManageUser", "/manage/user", Record<never, never>, Record<never, never>>;
|
||||
"Wip": RouteRecordInfo<"Wip", "/wip", Record<never, never>, Record<never, never>>
|
||||
}
|
||||
}
|
||||
@@ -56,7 +56,7 @@ const bgColor = computed(() => {
|
||||
<NCard :bordered="false" class="relative z-4 w-auto rd-12px">
|
||||
<div class="w-400px lt-sm:w-300px">
|
||||
<header class="flex-y-center justify-between">
|
||||
<SystemLogo class="size-64px lt-sm:size-48px" />
|
||||
<SystemLogo class="text-64px text-primary lt-sm:text-48px" />
|
||||
<h3 class="text-28px text-primary font-500 lt-sm:text-22px">{{ $t('system.title') }}</h3>
|
||||
<div class="i-flex-col">
|
||||
<ThemeSchemaSwitch
|
||||
5
src/views/(builtin)/wip/index.vue
Normal file
5
src/views/(builtin)/wip/index.vue
Normal file
@@ -0,0 +1,5 @@
|
||||
<script setup lang="ts"></script>
|
||||
|
||||
<template>
|
||||
<LookForward />
|
||||
</template>
|
||||
5
src/views/manage/menu/index.vue
Normal file
5
src/views/manage/menu/index.vue
Normal file
@@ -0,0 +1,5 @@
|
||||
<script setup lang="ts"></script>
|
||||
|
||||
<template>
|
||||
<div>ManageMenu</div>
|
||||
</template>
|
||||
5
src/views/manage/role/index.vue
Normal file
5
src/views/manage/role/index.vue
Normal file
@@ -0,0 +1,5 @@
|
||||
<script setup lang="ts"></script>
|
||||
|
||||
<template>
|
||||
<div>ManageRole</div>
|
||||
</template>
|
||||
5
src/views/manage/route/index.vue
Normal file
5
src/views/manage/route/index.vue
Normal file
@@ -0,0 +1,5 @@
|
||||
<script setup lang="ts"></script>
|
||||
|
||||
<template>
|
||||
<div>ManageRoute</div>
|
||||
</template>
|
||||
5
src/views/manage/user/index.vue
Normal file
5
src/views/manage/user/index.vue
Normal file
@@ -0,0 +1,5 @@
|
||||
<script setup lang="ts"></script>
|
||||
|
||||
<template>
|
||||
<div>ManageUser</div>
|
||||
</template>
|
||||
@@ -1,8 +1,12 @@
|
||||
import { defineConfig, transformerDirectives, transformerVariantGroup, presetWind3 } from 'unocss';
|
||||
import { defineConfig } from '@unocss/vite';
|
||||
import transformerDirectives from '@unocss/transformer-directives';
|
||||
import transformerVariantGroup from '@unocss/transformer-variant-group';
|
||||
import presetWind3 from '@unocss/preset-wind3';
|
||||
import type { Theme } from '@unocss/preset-uno';
|
||||
import { presetSoybeanAdmin } from '@sa/uno-preset';
|
||||
import { themeVars } from './src/theme/vars';
|
||||
|
||||
export default defineConfig({
|
||||
export default defineConfig<Theme>({
|
||||
content: {
|
||||
pipeline: {
|
||||
exclude: ['node_modules', 'dist']
|
||||
|
||||
Reference in New Issue
Block a user