mirror of
https://github.com/soybeanjs/soybean-admin.git
synced 2025-12-25 22:30:19 +08:00
Compare commits
11 Commits
605173a1cc
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
232e1ac40d | ||
|
|
5aac540a4c | ||
|
|
5e40b85018 | ||
|
|
ec9f9af9a2 | ||
|
|
62a43c3957 | ||
|
|
64226d9bb8 | ||
|
|
e675474b43 | ||
|
|
098cd50e23 | ||
|
|
7cf4083b22 | ||
|
|
9401925f41 | ||
|
|
b8a767d704 |
60
CHANGELOG.md
60
CHANGELOG.md
@@ -1,6 +1,66 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
|
||||||
|
## [v2.0.2](https://github.com/soybeanjs/soybean-admin/compare/v2.0.1...v2.0.2) (2025-12-23)
|
||||||
|
|
||||||
|
### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- **hooks**: update pagination pageSize after data fetch. - by **Azir-11** [<samp>(64226)</samp>](https://github.com/soybeanjs/soybean-admin/commit/64226d9b)
|
||||||
|
- **projects**: fix the incorrect judgment of home by pin tab. - by **Azir-11** [<samp>(62a43)</samp>](https://github.com/soybeanjs/soybean-admin/commit/62a43c39)
|
||||||
|
|
||||||
|
### 🏡 Chore
|
||||||
|
|
||||||
|
- **deps**: update deps - by @soybeanjs [<samp>(ec9f9)</samp>](https://github.com/soybeanjs/soybean-admin/commit/ec9f9af9)
|
||||||
|
|
||||||
|
### ❤️ Contributors
|
||||||
|
|
||||||
|
[](https://github.com/soybeanjs)
|
||||||
|
[Azir-11](mailto:2075125282@qq.com)
|
||||||
|
|
||||||
|
## [v2.0.1](https://github.com/soybeanjs/soybean-admin/compare/v2.0.0...v2.0.1) (2025-12-04)
|
||||||
|
|
||||||
|
### 🚀 Features
|
||||||
|
|
||||||
|
- **docs**:
|
||||||
|
- 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 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)
|
||||||
|
|
||||||
|
### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- **docs**: update project name in ecosystem section of README - by @soybeanjs [<samp>(bb232)</samp>](https://github.com/soybeanjs/soybean-admin/commit/bb232bf8)
|
||||||
|
- **types**: add missing property in theme presets - by **刘璐** [<samp>(4a9cf)</samp>](https://github.com/soybeanjs/soybean-admin/commit/4a9cf6c3)
|
||||||
|
|
||||||
|
### 🛠 Optimizations
|
||||||
|
|
||||||
|
- **projects**: simplify some theme preset configurations. - by **Azir-11** [<samp>(c6d97)</samp>](https://github.com/soybeanjs/soybean-admin/commit/c6d97dba)
|
||||||
|
|
||||||
|
### 📖 Documentation
|
||||||
|
|
||||||
|
- **projects**: add link to ecosystem document. - by **Azir-11** [<samp>(c472a)</samp>](https://github.com/soybeanjs/soybean-admin/commit/c472a943)
|
||||||
|
|
||||||
|
### 🏡 Chore
|
||||||
|
|
||||||
|
- **deps**:
|
||||||
|
- update deps - by @soybeanjs [<samp>(f8dc6)</samp>](https://github.com/soybeanjs/soybean-admin/commit/f8dc639e)
|
||||||
|
- update deps - by @soybeanjs [<samp>(7cf40)</samp>](https://github.com/soybeanjs/soybean-admin/commit/7cf4083b)
|
||||||
|
- **other**:
|
||||||
|
- remove Prettier's recommendation. - by **Azir-11** [<samp>(73e9a)</samp>](https://github.com/soybeanjs/soybean-admin/commit/73e9a0fe)
|
||||||
|
- **styles**:
|
||||||
|
- format code - by @soybeanjs [<samp>(098cd)</samp>](https://github.com/soybeanjs/soybean-admin/commit/098cd50e)
|
||||||
|
|
||||||
|
### 🎨 Styles
|
||||||
|
|
||||||
|
- **projects**: modify homepage prompt title to tip. - by **Azir-11** [<samp>(91a26)</samp>](https://github.com/soybeanjs/soybean-admin/commit/91a261c1)
|
||||||
|
|
||||||
|
### ❤️ Contributors
|
||||||
|
|
||||||
|
[](https://github.com/soybeanjs) [](https://github.com/paynezhuang)
|
||||||
|
[hooke](mailto:hellohooke@foxmail.com), [Azir-11](mailto:2075125282@qq.com), [刘璐](mailto:hi.alue@qq.com)
|
||||||
|
|
||||||
## [v2.0.0](https://github.com/soybeanjs/soybean-admin/compare/v1.3.15...v2.0.0) (2025-11-02)
|
## [v2.0.0](https://github.com/soybeanjs/soybean-admin/compare/v1.3.15...v2.0.0) (2025-11-02)
|
||||||
|
|
||||||
### 🚨 Breaking Changes
|
### 🚨 Breaking Changes
|
||||||
|
|||||||
48
package.json
48
package.json
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "soybean-admin",
|
"name": "soybean-admin",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"version": "2.0.0",
|
"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的清新优雅的中后台模版。",
|
"description": "A fresh and elegant admin template, based on Vue3、Vite7、TypeScript、NaiveUI and UnoCSS. 一个基于Vue3、Vite7、TypeScript、NaiveUI and UnoCSS的清新优雅的中后台模版。",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "Soybean",
|
"name": "Soybean",
|
||||||
@@ -54,53 +54,53 @@
|
|||||||
"@sa/hooks": "workspace:*",
|
"@sa/hooks": "workspace:*",
|
||||||
"@sa/materials": "workspace:*",
|
"@sa/materials": "workspace:*",
|
||||||
"@sa/utils": "workspace:*",
|
"@sa/utils": "workspace:*",
|
||||||
"@vueuse/core": "14.0.0",
|
"@vueuse/core": "14.1.0",
|
||||||
"clipboard": "2.0.11",
|
"clipboard": "2.0.11",
|
||||||
"dayjs": "1.11.19",
|
"dayjs": "1.11.19",
|
||||||
"defu": "6.1.4",
|
"defu": "6.1.4",
|
||||||
"echarts": "6.0.0",
|
"echarts": "6.0.0",
|
||||||
"json5": "2.2.3",
|
"json5": "2.2.3",
|
||||||
"naive-ui": "2.43.1",
|
"naive-ui": "2.43.2",
|
||||||
"nprogress": "0.2.0",
|
"nprogress": "0.2.0",
|
||||||
"pinia": "3.0.4",
|
"pinia": "3.0.4",
|
||||||
"tailwind-merge": "3.4.0",
|
"tailwind-merge": "3.4.0",
|
||||||
"vue": "3.5.24",
|
"vue": "3.5.26",
|
||||||
"vue-draggable-plus": "0.6.0",
|
"vue-draggable-plus": "0.6.0",
|
||||||
"vue-i18n": "11.1.12",
|
"vue-i18n": "11.2.7",
|
||||||
"vue-router": "4.6.3"
|
"vue-router": "4.6.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@elegant-router/vue": "0.3.8",
|
"@elegant-router/vue": "0.3.8",
|
||||||
"@iconify/json": "2.2.407",
|
"@iconify/json": "2.2.417",
|
||||||
"@sa/scripts": "workspace:*",
|
"@sa/scripts": "workspace:*",
|
||||||
"@sa/uno-preset": "workspace:*",
|
"@sa/uno-preset": "workspace:*",
|
||||||
"@soybeanjs/eslint-config": "1.7.3",
|
"@soybeanjs/eslint-config": "1.7.5",
|
||||||
"@types/node": "24.10.1",
|
"@types/node": "25.0.3",
|
||||||
"@types/nprogress": "0.2.3",
|
"@types/nprogress": "0.2.3",
|
||||||
"@unocss/eslint-config": "66.5.6",
|
"@unocss/eslint-config": "66.5.10",
|
||||||
"@unocss/preset-icons": "66.5.6",
|
"@unocss/preset-icons": "66.5.10",
|
||||||
"@unocss/preset-uno": "66.5.6",
|
"@unocss/preset-uno": "66.5.10",
|
||||||
"@unocss/transformer-directives": "66.5.6",
|
"@unocss/transformer-directives": "66.5.10",
|
||||||
"@unocss/transformer-variant-group": "66.5.6",
|
"@unocss/transformer-variant-group": "66.5.10",
|
||||||
"@unocss/vite": "66.5.6",
|
"@unocss/vite": "66.5.10",
|
||||||
"@vitejs/plugin-vue": "6.0.1",
|
"@vitejs/plugin-vue": "6.0.3",
|
||||||
"@vitejs/plugin-vue-jsx": "5.1.1",
|
"@vitejs/plugin-vue-jsx": "5.1.3",
|
||||||
"consola": "3.4.2",
|
"consola": "3.4.2",
|
||||||
"eslint": "9.39.1",
|
"eslint": "9.39.2",
|
||||||
"eslint-plugin-vue": "10.5.1",
|
"eslint-plugin-vue": "10.6.2",
|
||||||
"kolorist": "1.8.0",
|
"kolorist": "1.8.0",
|
||||||
"sass": "1.94.0",
|
"sass": "1.97.1",
|
||||||
"simple-git-hooks": "2.13.1",
|
"simple-git-hooks": "2.13.1",
|
||||||
"tsx": "4.20.6",
|
"tsx": "4.21.0",
|
||||||
"typescript": "5.9.3",
|
"typescript": "5.9.3",
|
||||||
"unplugin-icons": "22.5.0",
|
"unplugin-icons": "22.5.0",
|
||||||
"unplugin-vue-components": "30.0.0",
|
"unplugin-vue-components": "30.0.0",
|
||||||
"vite": "7.2.2",
|
"vite": "7.3.0",
|
||||||
"vite-plugin-progress": "0.0.7",
|
"vite-plugin-progress": "0.0.7",
|
||||||
"vite-plugin-svg-icons": "2.0.1",
|
"vite-plugin-svg-icons": "2.0.1",
|
||||||
"vite-plugin-vue-devtools": "8.0.3",
|
"vite-plugin-vue-devtools": "8.0.5",
|
||||||
"vue-eslint-parser": "10.2.0",
|
"vue-eslint-parser": "10.2.0",
|
||||||
"vue-tsc": "3.1.4"
|
"vue-tsc": "3.2.1"
|
||||||
},
|
},
|
||||||
"simple-git-hooks": {
|
"simple-git-hooks": {
|
||||||
"commit-msg": "pnpm sa git-commit-verify",
|
"commit-msg": "pnpm sa git-commit-verify",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@sa/alova",
|
"name": "@sa/alova",
|
||||||
"version": "2.0.0",
|
"version": "2.0.2",
|
||||||
"exports": {
|
"exports": {
|
||||||
".": "./src/index.ts",
|
".": "./src/index.ts",
|
||||||
"./fetch": "./src/fetch.ts",
|
"./fetch": "./src/fetch.ts",
|
||||||
@@ -13,8 +13,8 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@alova/mock": "2.0.17",
|
"@alova/mock": "2.0.18",
|
||||||
"@sa/utils": "workspace:*",
|
"@sa/utils": "workspace:*",
|
||||||
"alova": "3.3.4"
|
"alova": "3.4.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@sa/axios",
|
"name": "@sa/axios",
|
||||||
"version": "2.0.0",
|
"version": "2.0.2",
|
||||||
"exports": {
|
"exports": {
|
||||||
".": "./src/index.ts"
|
".": "./src/index.ts"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -119,8 +119,11 @@ export type FlatResponseData<ResponseData, ApiData> =
|
|||||||
| FlatResponseSuccessData<ResponseData, ApiData>
|
| FlatResponseSuccessData<ResponseData, ApiData>
|
||||||
| FlatResponseFailData<ResponseData>;
|
| FlatResponseFailData<ResponseData>;
|
||||||
|
|
||||||
export interface FlatRequestInstance<ResponseData, ApiData, State extends Record<string, unknown>>
|
export interface FlatRequestInstance<
|
||||||
extends RequestInstanceCommon<State> {
|
ResponseData,
|
||||||
|
ApiData,
|
||||||
|
State extends Record<string, unknown>
|
||||||
|
> extends RequestInstanceCommon<State> {
|
||||||
<T extends ApiData = ApiData, R extends ResponseType = 'json'>(
|
<T extends ApiData = ApiData, R extends ResponseType = 'json'>(
|
||||||
config: CustomAxiosRequestConfig<R>
|
config: CustomAxiosRequestConfig<R>
|
||||||
): Promise<FlatResponseData<ResponseData, MappedType<R, T>>>;
|
): Promise<FlatResponseData<ResponseData, MappedType<R, T>>>;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@sa/color",
|
"name": "@sa/color",
|
||||||
"version": "2.0.0",
|
"version": "2.0.2",
|
||||||
"exports": {
|
"exports": {
|
||||||
".": "./src/index.ts"
|
".": "./src/index.ts"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@sa/hooks",
|
"name": "@sa/hooks",
|
||||||
"version": "2.0.0",
|
"version": "2.0.2",
|
||||||
"exports": {
|
"exports": {
|
||||||
".": "./src/index.ts"
|
".": "./src/index.ts"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -26,8 +26,11 @@ export type HookRequestInstanceResponseData<ResponseData, ApiData> = {
|
|||||||
loading: Ref<boolean>;
|
loading: Ref<boolean>;
|
||||||
} & (HookRequestInstanceResponseSuccessData<ApiData> | HookRequestInstanceResponseFailData<ResponseData>);
|
} & (HookRequestInstanceResponseSuccessData<ApiData> | HookRequestInstanceResponseFailData<ResponseData>);
|
||||||
|
|
||||||
export interface HookRequestInstance<ResponseData, ApiData, State extends Record<string, unknown>>
|
export interface HookRequestInstance<
|
||||||
extends RequestInstanceCommon<State> {
|
ResponseData,
|
||||||
|
ApiData,
|
||||||
|
State extends Record<string, unknown>
|
||||||
|
> extends RequestInstanceCommon<State> {
|
||||||
<T extends ApiData = ApiData, R extends ResponseType = 'json'>(
|
<T extends ApiData = ApiData, R extends ResponseType = 'json'>(
|
||||||
config: CustomAxiosRequestConfig
|
config: CustomAxiosRequestConfig
|
||||||
): HookRequestInstanceResponseData<ResponseData, MappedType<R, T>>;
|
): HookRequestInstanceResponseData<ResponseData, MappedType<R, T>>;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@sa/materials",
|
"name": "@sa/materials",
|
||||||
"version": "2.0.0",
|
"version": "2.0.2",
|
||||||
"exports": {
|
"exports": {
|
||||||
".": "./src/index.ts"
|
".": "./src/index.ts"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -146,7 +146,8 @@ export type LayoutScrollMode = 'wrapper' | 'content';
|
|||||||
|
|
||||||
/** Admin layout props */
|
/** Admin layout props */
|
||||||
export interface AdminLayoutProps
|
export interface AdminLayoutProps
|
||||||
extends AdminLayoutHeaderConfig,
|
extends
|
||||||
|
AdminLayoutHeaderConfig,
|
||||||
AdminLayoutTabConfig,
|
AdminLayoutTabConfig,
|
||||||
AdminLayoutSiderConfig,
|
AdminLayoutSiderConfig,
|
||||||
AdminLayoutContentConfig,
|
AdminLayoutContentConfig,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@sa/scripts",
|
"name": "@sa/scripts",
|
||||||
"version": "2.0.0",
|
"version": "2.0.2",
|
||||||
"bin": {
|
"bin": {
|
||||||
"sa": "./bin.ts"
|
"sa": "./bin.ts"
|
||||||
},
|
},
|
||||||
@@ -13,16 +13,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@soybeanjs/changelog": "0.3.25",
|
"@soybeanjs/changelog": "0.4.3",
|
||||||
"bumpp": "10.3.1",
|
"bumpp": "10.3.2",
|
||||||
"c12": "3.3.2",
|
"c12": "3.3.3",
|
||||||
"cac": "6.7.14",
|
"cac": "6.7.14",
|
||||||
"consola": "3.4.2",
|
"consola": "3.4.2",
|
||||||
"enquirer": "2.4.1",
|
"enquirer": "2.4.1",
|
||||||
"execa": "9.6.0",
|
"execa": "9.6.1",
|
||||||
"kolorist": "1.8.0",
|
"kolorist": "1.8.0",
|
||||||
"npm-check-updates": "19.1.2",
|
"npm-check-updates": "19.2.0",
|
||||||
"picomatch": "4.0.3",
|
"picomatch": "4.0.3",
|
||||||
"rimraf": "6.1.0"
|
"rimraf": "6.1.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@sa/uno-preset",
|
"name": "@sa/uno-preset",
|
||||||
"version": "2.0.0",
|
"version": "2.0.2",
|
||||||
"exports": {
|
"exports": {
|
||||||
".": "./src/index.ts"
|
".": "./src/index.ts"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@sa/utils",
|
"name": "@sa/utils",
|
||||||
"version": "2.0.0",
|
"version": "2.0.2",
|
||||||
"exports": {
|
"exports": {
|
||||||
".": "./src/index.ts"
|
".": "./src/index.ts"
|
||||||
},
|
},
|
||||||
|
|||||||
1943
pnpm-lock.yaml
generated
1943
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -1 +1,60 @@
|
|||||||
<svg viewBox="0 0 160 160" xmlns="http://www.w3.org/2000/svg"><path d="M81.28 55.9c-.1-11.67-2.93-22.55-9.37-32.38-1-1.5-2.14-2.86-2.5-4.71a8.1 8.1 0 014-8.61 7.89 7.89 0 019.3 1.23 35.999 35.999 0 015.9 8.83 75.18 75.18 0 018.44 28.58 83.211 83.211 0 01-5.23 36.74 102.983 102.983 0 01-3 7.28 1.2 1.2 0 000 1.41c9.58 13.3 21.76 23 37.85 27.24a54.37 54.37 0 0019.68 1.57 7.72 7.72 0 018.36 6.9 7.903 7.903 0 01-6.7 9 64.744 64.744 0 01-23-1.33 77.68 77.68 0 01-36.93-19.88 93.628 93.628 0 01-11.91-13.71 2.18 2.18 0 00-2.3-1.06 72.744 72.744 0 00-27.38 7.55c-11.6 6-20.67 14.58-26.4 26.45a10.134 10.134 0 01-3.7 4.7 8 8 0 01-9.19-.7 7.86 7.86 0 01-2.36-9.28 60.324 60.324 0 018.72-14.52c12.2-15.43 28.21-24.59 47.32-28.57A85.085 85.085 0 0173.07 87c.524.015 1-.307 1.18-.8a76.06 76.06 0 006.53-22.3c.351-2.652.518-5.325.5-8z" fill="#646cff"/><path d="M136.26 108.34a44.742 44.742 0 01-11.13-2.87 46.108 46.108 0 01-19.66-13.76 8 8 0 015.72-13.22 7.93 7.93 0 016.54 2.93 33.27 33.27 0 0018.87 10.75c1.546.155 3.058.553 4.48 1.18a8.08 8.08 0 013.84 9.21c-.92 3.52-4.13 5.81-8.66 5.78zm-80.6-75.02a7.61 7.61 0 016.64 5 49.139 49.139 0 013.64 17 46.33 46.33 0 01-2.46 17.28c-2 5.77-8.24 7.79-12.89 4.15a8.1 8.1 0 01-2.39-9 31.679 31.679 0 001.68-12.36 35.77 35.77 0 00-2.43-11c-2.1-5.45 1.75-11.07 8.21-11.07zm22.26 93.25a8 8 0 01-6.68 7.86 32.88 32.88 0 00-19.7 12.19 8.13 8.13 0 01-11.21 1.62 8 8 0 01-1.41-11.58A51.043 51.043 0 0154 123.81a45.842 45.842 0 0114-5.1c5.35-1.04 9.91 2.56 9.92 7.86z" fill="#646cff"/></svg>
|
<svg 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>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 3.8 KiB |
@@ -1,9 +1,160 @@
|
|||||||
<script lang="ts" setup>
|
|
||||||
defineOptions({ name: 'SystemLogo' });
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<icon-local-logo />
|
<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>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped></style>
|
<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>
|
||||||
|
|||||||
@@ -131,6 +131,7 @@ export function useNaivePaginatedTable<ResponseData, ApiData>(
|
|||||||
getColumns,
|
getColumns,
|
||||||
onFetched: data => {
|
onFetched: data => {
|
||||||
pagination.itemCount = data.total;
|
pagination.itemCount = data.total;
|
||||||
|
pagination.pageSize = data.pageSize;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ withDefaults(defineProps<Props>(), {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<RouterLink to="/" class="w-full flex-center nowrap-hidden">
|
<RouterLink to="/" class="w-full flex-center nowrap-hidden">
|
||||||
<SystemLogo class="text-32px text-primary" />
|
<SystemLogo class="size-32px" />
|
||||||
<h2 v-show="showTitle" class="pl-8px text-16px text-primary font-bold transition duration-300 ease-in-out">
|
<h2 v-show="showTitle" class="pl-8px text-16px text-primary font-bold transition duration-300 ease-in-out">
|
||||||
{{ $t('system.title') }}
|
{{ $t('system.title') }}
|
||||||
</h2>
|
</h2>
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { useRoute } from 'vue-router';
|
|||||||
import { useContext } from '@sa/hooks';
|
import { useContext } from '@sa/hooks';
|
||||||
import type { RouteKey } from '@elegant-router/types';
|
import type { RouteKey } from '@elegant-router/types';
|
||||||
import { useRouteStore } from '@/store/modules/route';
|
import { useRouteStore } from '@/store/modules/route';
|
||||||
|
import { useThemeStore } from '@/store/modules/theme';
|
||||||
import { useRouterPush } from '@/hooks/common/router';
|
import { useRouterPush } from '@/hooks/common/router';
|
||||||
|
|
||||||
export const [provideMixMenuContext, useMixMenuContext] = useContext('MixMenu', useMixMenu);
|
export const [provideMixMenuContext, useMixMenuContext] = useContext('MixMenu', useMixMenu);
|
||||||
@@ -10,6 +11,7 @@ export const [provideMixMenuContext, useMixMenuContext] = useContext('MixMenu',
|
|||||||
function useMixMenu() {
|
function useMixMenu() {
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const routeStore = useRouteStore();
|
const routeStore = useRouteStore();
|
||||||
|
const themeStore = useThemeStore();
|
||||||
const { selectedKey } = useMenu();
|
const { selectedKey } = useMenu();
|
||||||
const { routerPushByKeyWithMetaQuery } = useRouterPush();
|
const { routerPushByKeyWithMetaQuery } = useRouterPush();
|
||||||
|
|
||||||
@@ -100,10 +102,46 @@ function useMixMenu() {
|
|||||||
() => secondLevelMenus.value.find(menu => menu.key === activeSecondLevelMenuKey.value)?.children || []
|
() => secondLevelMenus.value.find(menu => menu.key === activeSecondLevelMenuKey.value)?.children || []
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const hasChildLevelMenus = computed(() => childLevelMenus.value.length > 0);
|
||||||
|
|
||||||
|
function getDeepestLevelMenuKey(): RouteKey | null {
|
||||||
|
if (!secondLevelMenus.value.length || !themeStore.sider.autoSelectFirstMenu) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const secondLevelFirstMenu = secondLevelMenus.value[0];
|
||||||
|
|
||||||
|
if (!secondLevelFirstMenu) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function findDeepest(menu: App.Global.Menu): RouteKey {
|
||||||
|
if (!menu.children?.length) {
|
||||||
|
return menu.routeKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
return findDeepest(menu.children[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return findDeepest(secondLevelFirstMenu);
|
||||||
|
}
|
||||||
|
|
||||||
|
function activeDeepestLevelMenuKey() {
|
||||||
|
const deepestLevelMenuKey = getDeepestLevelMenuKey();
|
||||||
|
if (!deepestLevelMenuKey) return;
|
||||||
|
|
||||||
|
// select the deepest second level menu
|
||||||
|
handleSelectSecondLevelMenu(deepestLevelMenuKey);
|
||||||
|
}
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => route.name,
|
() => route.name,
|
||||||
() => {
|
() => {
|
||||||
getActiveFirstLevelMenuKey();
|
getActiveFirstLevelMenuKey();
|
||||||
|
// if there are child level menus, get the active second level menu key
|
||||||
|
if (hasChildLevelMenus.value) {
|
||||||
|
getActiveSecondLevelMenuKey();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{ immediate: true }
|
{ immediate: true }
|
||||||
);
|
);
|
||||||
@@ -121,7 +159,10 @@ function useMixMenu() {
|
|||||||
isActiveSecondLevelMenuHasChildren,
|
isActiveSecondLevelMenuHasChildren,
|
||||||
handleSelectSecondLevelMenu,
|
handleSelectSecondLevelMenu,
|
||||||
getActiveSecondLevelMenuKey,
|
getActiveSecondLevelMenuKey,
|
||||||
childLevelMenus
|
childLevelMenus,
|
||||||
|
hasChildLevelMenus,
|
||||||
|
getDeepestLevelMenuKey,
|
||||||
|
activeDeepestLevelMenuKey
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
import { ref, watch } from 'vue';
|
import { ref, watch } from 'vue';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
import { SimpleScrollbar } from '@sa/materials';
|
import { SimpleScrollbar } from '@sa/materials';
|
||||||
|
import type { RouteKey } from '@elegant-router/types';
|
||||||
import { GLOBAL_HEADER_MENU_ID, GLOBAL_SIDER_MENU_ID } from '@/constants/app';
|
import { GLOBAL_HEADER_MENU_ID, GLOBAL_SIDER_MENU_ID } from '@/constants/app';
|
||||||
import { useAppStore } from '@/store/modules/app';
|
import { useAppStore } from '@/store/modules/app';
|
||||||
import { useThemeStore } from '@/store/modules/theme';
|
import { useThemeStore } from '@/store/modules/theme';
|
||||||
@@ -18,12 +19,28 @@ const appStore = useAppStore();
|
|||||||
const themeStore = useThemeStore();
|
const themeStore = useThemeStore();
|
||||||
const routeStore = useRouteStore();
|
const routeStore = useRouteStore();
|
||||||
const { routerPushByKeyWithMetaQuery } = useRouterPush();
|
const { routerPushByKeyWithMetaQuery } = useRouterPush();
|
||||||
const { firstLevelMenus, secondLevelMenus, activeFirstLevelMenuKey, handleSelectFirstLevelMenu } =
|
const {
|
||||||
useMixMenuContext('TopHybridHeaderFirst');
|
firstLevelMenus,
|
||||||
|
secondLevelMenus,
|
||||||
|
activeFirstLevelMenuKey,
|
||||||
|
handleSelectFirstLevelMenu,
|
||||||
|
activeDeepestLevelMenuKey
|
||||||
|
} = useMixMenuContext('TopHybridHeaderFirst');
|
||||||
const { selectedKey } = useMenu();
|
const { selectedKey } = useMenu();
|
||||||
|
|
||||||
const expandedKeys = ref<string[]>([]);
|
const expandedKeys = ref<string[]>([]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle first level menu select
|
||||||
|
* @param key RouteKey
|
||||||
|
*/
|
||||||
|
function handleSelectMenu(key: RouteKey) {
|
||||||
|
handleSelectFirstLevelMenu(key);
|
||||||
|
|
||||||
|
// if there are second level menus, select the deepest one by default
|
||||||
|
activeDeepestLevelMenuKey();
|
||||||
|
}
|
||||||
|
|
||||||
function updateExpandedKeys() {
|
function updateExpandedKeys() {
|
||||||
if (appStore.siderCollapse || !selectedKey.value) {
|
if (appStore.siderCollapse || !selectedKey.value) {
|
||||||
expandedKeys.value = [];
|
expandedKeys.value = [];
|
||||||
@@ -49,7 +66,7 @@ watch(
|
|||||||
:options="firstLevelMenus"
|
:options="firstLevelMenus"
|
||||||
:indent="18"
|
:indent="18"
|
||||||
responsive
|
responsive
|
||||||
@update:value="handleSelectFirstLevelMenu"
|
@update:value="handleSelectMenu"
|
||||||
/>
|
/>
|
||||||
</Teleport>
|
</Teleport>
|
||||||
<Teleport :to="`#${GLOBAL_SIDER_MENU_ID}`">
|
<Teleport :to="`#${GLOBAL_SIDER_MENU_ID}`">
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import type { RouteKey } from '@elegant-router/types';
|
||||||
import { GLOBAL_HEADER_MENU_ID, GLOBAL_SIDER_MENU_ID } from '@/constants/app';
|
import { GLOBAL_HEADER_MENU_ID, GLOBAL_SIDER_MENU_ID } from '@/constants/app';
|
||||||
import { useAppStore } from '@/store/modules/app';
|
import { useAppStore } from '@/store/modules/app';
|
||||||
import { useThemeStore } from '@/store/modules/theme';
|
import { useThemeStore } from '@/store/modules/theme';
|
||||||
@@ -13,9 +14,25 @@ defineOptions({
|
|||||||
const appStore = useAppStore();
|
const appStore = useAppStore();
|
||||||
const themeStore = useThemeStore();
|
const themeStore = useThemeStore();
|
||||||
const { routerPushByKeyWithMetaQuery } = useRouterPush();
|
const { routerPushByKeyWithMetaQuery } = useRouterPush();
|
||||||
const { firstLevelMenus, secondLevelMenus, activeFirstLevelMenuKey, handleSelectFirstLevelMenu } =
|
const {
|
||||||
useMixMenuContext('TopHybridSidebarFirst');
|
firstLevelMenus,
|
||||||
|
secondLevelMenus,
|
||||||
|
activeFirstLevelMenuKey,
|
||||||
|
handleSelectFirstLevelMenu,
|
||||||
|
activeDeepestLevelMenuKey
|
||||||
|
} = useMixMenuContext('TopHybridSidebarFirst');
|
||||||
const { selectedKey } = useMenu();
|
const { selectedKey } = useMenu();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle first level menu select
|
||||||
|
* @param key RouteKey
|
||||||
|
*/
|
||||||
|
function handleSelectMenu(key: RouteKey) {
|
||||||
|
handleSelectFirstLevelMenu(key);
|
||||||
|
|
||||||
|
// if there are second level menus, select the deepest one by default
|
||||||
|
activeDeepestLevelMenuKey();
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -37,7 +54,7 @@ const { selectedKey } = useMenu();
|
|||||||
:sider-collapse="appStore.siderCollapse"
|
:sider-collapse="appStore.siderCollapse"
|
||||||
:dark-mode="themeStore.darkMode"
|
:dark-mode="themeStore.darkMode"
|
||||||
:theme-color="themeStore.themeColor"
|
:theme-color="themeStore.themeColor"
|
||||||
@select="handleSelectFirstLevelMenu"
|
@select="handleSelectMenu"
|
||||||
@toggle-sider-collapse="appStore.toggleSiderCollapse"
|
@toggle-sider-collapse="appStore.toggleSiderCollapse"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -33,15 +33,15 @@ const {
|
|||||||
isActiveSecondLevelMenuHasChildren,
|
isActiveSecondLevelMenuHasChildren,
|
||||||
handleSelectSecondLevelMenu,
|
handleSelectSecondLevelMenu,
|
||||||
getActiveSecondLevelMenuKey,
|
getActiveSecondLevelMenuKey,
|
||||||
childLevelMenus
|
childLevelMenus,
|
||||||
|
hasChildLevelMenus,
|
||||||
|
activeDeepestLevelMenuKey
|
||||||
} = useMixMenuContext('VerticalHybridHeaderFirst');
|
} = useMixMenuContext('VerticalHybridHeaderFirst');
|
||||||
const { selectedKey } = useMenu();
|
const { selectedKey } = useMenu();
|
||||||
|
|
||||||
const inverted = computed(() => !themeStore.darkMode && themeStore.sider.inverted);
|
const inverted = computed(() => !themeStore.darkMode && themeStore.sider.inverted);
|
||||||
|
|
||||||
const hasChildMenus = computed(() => childLevelMenus.value.length > 0);
|
const showDrawer = computed(() => hasChildLevelMenus.value && (drawerVisible.value || appStore.mixSiderFixed));
|
||||||
|
|
||||||
const showDrawer = computed(() => hasChildMenus.value && (drawerVisible.value || appStore.mixSiderFixed));
|
|
||||||
|
|
||||||
function handleSelectMixMenu(key: RouteKey) {
|
function handleSelectMixMenu(key: RouteKey) {
|
||||||
handleSelectSecondLevelMenu(key);
|
handleSelectSecondLevelMenu(key);
|
||||||
@@ -51,12 +51,33 @@ function handleSelectMixMenu(key: RouteKey) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle second level menu selection based on autoSelectFirstMenu setting:
|
||||||
|
* - When disabled: Activate first second-level menu for display only, expand third-level menu if exists
|
||||||
|
* - When enabled: Navigate to the deepest menu automatically
|
||||||
|
*/
|
||||||
function handleSelectMenu(key: RouteKey) {
|
function handleSelectMenu(key: RouteKey) {
|
||||||
handleSelectFirstLevelMenu(key);
|
handleSelectFirstLevelMenu(key);
|
||||||
|
|
||||||
if (secondLevelMenus.value.length > 0) {
|
if (secondLevelMenus.value.length === 0) return;
|
||||||
handleSelectMixMenu(secondLevelMenus.value[0].routeKey);
|
|
||||||
|
const secondFirstMenuKey = secondLevelMenus.value[0].routeKey;
|
||||||
|
|
||||||
|
// Case 1: autoSelectFirstMenu disabled - only activate menu for display
|
||||||
|
if (!themeStore.sider.autoSelectFirstMenu) {
|
||||||
|
// Check if there are third-level menus
|
||||||
|
const hasChildren = secondLevelMenus.value.find(menu => menu.key === secondFirstMenuKey)?.children?.length;
|
||||||
|
|
||||||
|
// If there are third-level menus, expand them
|
||||||
|
if (hasChildren) {
|
||||||
|
handleSelectMixMenu(secondFirstMenuKey);
|
||||||
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Case 2: autoSelectFirstMenu enabled - navigate to deepest menu
|
||||||
|
activeDeepestLevelMenuKey();
|
||||||
|
setDrawerVisible(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleResetActiveMenu() {
|
function handleResetActiveMenu() {
|
||||||
@@ -114,7 +135,9 @@ watch(
|
|||||||
</FirstLevelMenu>
|
</FirstLevelMenu>
|
||||||
<div
|
<div
|
||||||
class="relative h-full transition-width-300"
|
class="relative h-full transition-width-300"
|
||||||
:style="{ width: appStore.mixSiderFixed && hasChildMenus ? themeStore.sider.mixChildMenuWidth + 'px' : '0px' }"
|
:style="{
|
||||||
|
width: appStore.mixSiderFixed && hasChildLevelMenus ? themeStore.sider.mixChildMenuWidth + 'px' : '0px'
|
||||||
|
}"
|
||||||
>
|
>
|
||||||
<DarkModeContainer
|
<DarkModeContainer
|
||||||
class="absolute-lt h-full flex-col-stretch nowrap-hidden shadow-sm transition-all-300"
|
class="absolute-lt h-full flex-col-stretch nowrap-hidden shadow-sm transition-all-300"
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ const props = withDefaults(defineProps<Props>(), {
|
|||||||
|
|
||||||
const visible = defineModel<boolean>('visible');
|
const visible = defineModel<boolean>('visible');
|
||||||
|
|
||||||
const { removeTab, clearTabs, clearLeftTabs, clearRightTabs } = useTabStore();
|
const { removeTab, clearTabs, clearLeftTabs, clearRightTabs, fixTab, unfixTab, isTabRetain, homeTab } = useTabStore();
|
||||||
const { SvgIconVNode } = useSvgIcon();
|
const { SvgIconVNode } = useSvgIcon();
|
||||||
|
|
||||||
type DropdownOption = {
|
type DropdownOption = {
|
||||||
@@ -64,6 +64,23 @@ const options = computed(() => {
|
|||||||
icon: SvgIconVNode({ icon: 'ant-design:line-outlined', fontSize: 18 })
|
icon: SvgIconVNode({ icon: 'ant-design:line-outlined', fontSize: 18 })
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
if (props.tabId !== homeTab?.id) {
|
||||||
|
if (isTabRetain(props.tabId)) {
|
||||||
|
opts.push({
|
||||||
|
key: 'unpin',
|
||||||
|
label: $t('dropdown.unpin'),
|
||||||
|
icon: SvgIconVNode({ icon: 'mdi:pin-off-outline', fontSize: 18 })
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
opts.push({
|
||||||
|
key: 'pin',
|
||||||
|
label: $t('dropdown.pin'),
|
||||||
|
icon: SvgIconVNode({ icon: 'mdi:pin-outline', fontSize: 18 })
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const { excludeKeys, disabledKeys } = props;
|
const { excludeKeys, disabledKeys } = props;
|
||||||
|
|
||||||
const result = opts.filter(opt => !excludeKeys.includes(opt.key));
|
const result = opts.filter(opt => !excludeKeys.includes(opt.key));
|
||||||
@@ -98,6 +115,12 @@ const dropdownAction: Record<App.Global.DropdownKey, () => void> = {
|
|||||||
},
|
},
|
||||||
closeAll() {
|
closeAll() {
|
||||||
clearTabs();
|
clearTabs();
|
||||||
|
},
|
||||||
|
pin() {
|
||||||
|
fixTab(props.tabId);
|
||||||
|
},
|
||||||
|
unpin() {
|
||||||
|
unfixTab(props.tabId);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ const themeStore = useThemeStore();
|
|||||||
|
|
||||||
const layoutMode = computed(() => themeStore.layout.mode);
|
const layoutMode = computed(() => themeStore.layout.mode);
|
||||||
const isMixLayoutMode = computed(() => layoutMode.value.includes('mix') || layoutMode.value.includes('hybrid'));
|
const isMixLayoutMode = computed(() => layoutMode.value.includes('mix') || layoutMode.value.includes('hybrid'));
|
||||||
|
const isHybridLayoutMode = computed(() => layoutMode.value.includes('hybrid'));
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -32,6 +33,12 @@ const isMixLayoutMode = computed(() => layoutMode.value.includes('mix') || layou
|
|||||||
<SettingItem v-if="layoutMode === 'vertical-mix'" key="5" :label="$t('theme.layout.sider.mixChildMenuWidth')">
|
<SettingItem v-if="layoutMode === 'vertical-mix'" key="5" :label="$t('theme.layout.sider.mixChildMenuWidth')">
|
||||||
<NInputNumber v-model:value="themeStore.sider.mixChildMenuWidth" size="small" :step="1" class="w-120px" />
|
<NInputNumber v-model:value="themeStore.sider.mixChildMenuWidth" size="small" :step="1" class="w-120px" />
|
||||||
</SettingItem>
|
</SettingItem>
|
||||||
|
<SettingItem v-if="isHybridLayoutMode" key="6" :label="$t('theme.layout.sider.autoSelectFirstMenu')">
|
||||||
|
<template #suffix>
|
||||||
|
<IconTooltip :desc="$t('theme.layout.sider.autoSelectFirstMenuTip')" />
|
||||||
|
</template>
|
||||||
|
<NSwitch v-model:value="themeStore.sider.autoSelectFirstMenu" />
|
||||||
|
</SettingItem>
|
||||||
</TransitionGroup>
|
</TransitionGroup>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -160,7 +160,10 @@ const local: App.I18n.Schema = {
|
|||||||
collapsedWidth: 'Sider Collapsed Width',
|
collapsedWidth: 'Sider Collapsed Width',
|
||||||
mixWidth: 'Mix Sider Width',
|
mixWidth: 'Mix Sider Width',
|
||||||
mixCollapsedWidth: 'Mix Sider Collapse Width',
|
mixCollapsedWidth: 'Mix Sider Collapse Width',
|
||||||
mixChildMenuWidth: 'Mix Child Menu Width'
|
mixChildMenuWidth: 'Mix Child Menu Width',
|
||||||
|
autoSelectFirstMenu: 'Auto Select First Submenu',
|
||||||
|
autoSelectFirstMenuTip:
|
||||||
|
'When a first-level menu is clicked, the first submenu is automatically selected and navigated to the deepest level'
|
||||||
},
|
},
|
||||||
footer: {
|
footer: {
|
||||||
title: 'Footer Settings',
|
title: 'Footer Settings',
|
||||||
@@ -336,7 +339,9 @@ const local: App.I18n.Schema = {
|
|||||||
closeOther: 'Close Other',
|
closeOther: 'Close Other',
|
||||||
closeLeft: 'Close Left',
|
closeLeft: 'Close Left',
|
||||||
closeRight: 'Close Right',
|
closeRight: 'Close Right',
|
||||||
closeAll: 'Close All'
|
closeAll: 'Close All',
|
||||||
|
pin: 'Pin Tab',
|
||||||
|
unpin: 'Unpin Tab'
|
||||||
},
|
},
|
||||||
icon: {
|
icon: {
|
||||||
themeConfig: 'Theme Configuration',
|
themeConfig: 'Theme Configuration',
|
||||||
|
|||||||
@@ -157,7 +157,9 @@ const local: App.I18n.Schema = {
|
|||||||
collapsedWidth: '侧边栏折叠宽度',
|
collapsedWidth: '侧边栏折叠宽度',
|
||||||
mixWidth: '混合布局侧边栏宽度',
|
mixWidth: '混合布局侧边栏宽度',
|
||||||
mixCollapsedWidth: '混合布局侧边栏折叠宽度',
|
mixCollapsedWidth: '混合布局侧边栏折叠宽度',
|
||||||
mixChildMenuWidth: '混合布局子菜单宽度'
|
mixChildMenuWidth: '混合布局子菜单宽度',
|
||||||
|
autoSelectFirstMenu: '自动选择第一个子菜单',
|
||||||
|
autoSelectFirstMenuTip: '点击一级菜单时,自动选择并导航到第一个子菜单的最深层级'
|
||||||
},
|
},
|
||||||
footer: {
|
footer: {
|
||||||
title: '底部设置',
|
title: '底部设置',
|
||||||
@@ -333,7 +335,9 @@ const local: App.I18n.Schema = {
|
|||||||
closeOther: '关闭其它',
|
closeOther: '关闭其它',
|
||||||
closeLeft: '关闭左侧',
|
closeLeft: '关闭左侧',
|
||||||
closeRight: '关闭右侧',
|
closeRight: '关闭右侧',
|
||||||
closeAll: '关闭所有'
|
closeAll: '关闭所有',
|
||||||
|
pin: '固定标签',
|
||||||
|
unpin: '取消固定'
|
||||||
},
|
},
|
||||||
icon: {
|
icon: {
|
||||||
themeConfig: '主题配置',
|
themeConfig: '主题配置',
|
||||||
|
|||||||
@@ -1,18 +1,25 @@
|
|||||||
// @unocss-include
|
// @unocss-include
|
||||||
import { getRgb } from '@sa/color';
|
import { getColorPalette, getRgb } from '@sa/color';
|
||||||
import { DARK_CLASS } from '@/constants/app';
|
import { DARK_CLASS } from '@/constants/app';
|
||||||
import { localStg } from '@/utils/storage';
|
import { localStg } from '@/utils/storage';
|
||||||
import { toggleHtmlClass } from '@/utils/common';
|
import { toggleHtmlClass } from '@/utils/common';
|
||||||
import systemLogo from '@/assets/svg-icon/logo.svg?raw';
|
|
||||||
import { $t } from '@/locales';
|
import { $t } from '@/locales';
|
||||||
|
|
||||||
export function setupLoading() {
|
export function setupLoading() {
|
||||||
const themeColor = localStg.get('themeColor') || '#646cff';
|
const themeColor = localStg.get('themeColor') || '#646cff';
|
||||||
const darkMode = localStg.get('darkMode') || false;
|
const darkMode = localStg.get('darkMode') || false;
|
||||||
|
const palette = getColorPalette(themeColor);
|
||||||
|
|
||||||
const { r, g, b } = getRgb(themeColor);
|
const { r, g, b } = getRgb(themeColor);
|
||||||
|
|
||||||
const primaryColor = `--primary-color: ${r} ${g} ${b}`;
|
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) {
|
if (darkMode) {
|
||||||
toggleHtmlClass(DARK_CLASS).add();
|
toggleHtmlClass(DARK_CLASS).add();
|
||||||
}
|
}
|
||||||
@@ -24,8 +31,6 @@ export function setupLoading() {
|
|||||||
'right-0 bottom-0 animate-delay-1500'
|
'right-0 bottom-0 animate-delay-1500'
|
||||||
];
|
];
|
||||||
|
|
||||||
const logoWithClass = systemLogo.replace('<svg', `<svg class="size-128px text-primary"`);
|
|
||||||
|
|
||||||
const dot = loadingClasses
|
const dot = loadingClasses
|
||||||
.map(item => {
|
.map(item => {
|
||||||
return `<div class="absolute w-16px h-16px bg-primary rounded-8px animate-pulse ${item}"></div>`;
|
return `<div class="absolute w-16px h-16px bg-primary rounded-8px animate-pulse ${item}"></div>`;
|
||||||
@@ -33,8 +38,10 @@ export function setupLoading() {
|
|||||||
.join('\n');
|
.join('\n');
|
||||||
|
|
||||||
const loading = `
|
const loading = `
|
||||||
<div class="fixed-center flex-col bg-layout" style="${primaryColor}">
|
<div class="fixed-center flex-col bg-layout" style="${cssVars}">
|
||||||
${logoWithClass}
|
<div class="w-128px h-128px">
|
||||||
|
${getLogoSvg()}
|
||||||
|
</div>
|
||||||
<div class="w-56px h-56px my-36px">
|
<div class="w-56px h-56px my-36px">
|
||||||
<div class="relative h-full animate-spin">
|
<div class="relative h-full animate-spin">
|
||||||
${dot}
|
${dot}
|
||||||
@@ -49,3 +56,155 @@ export function setupLoading() {
|
|||||||
app.innerHTML = loading;
|
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;
|
||||||
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import {
|
|||||||
getTabByRoute,
|
getTabByRoute,
|
||||||
getTabIdByRoute,
|
getTabIdByRoute,
|
||||||
isTabInTabs,
|
isTabInTabs,
|
||||||
|
reorderFixedTabs,
|
||||||
updateTabByI18nKey,
|
updateTabByI18nKey,
|
||||||
updateTabsByI18nKey
|
updateTabsByI18nKey
|
||||||
} from './shared';
|
} from './shared';
|
||||||
@@ -248,6 +249,48 @@ export const useTabStore = defineStore(SetupStoreId.Tab, () => {
|
|||||||
await clearTabs(excludes);
|
await clearTabs(excludes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fix tab
|
||||||
|
*
|
||||||
|
* @param tabId
|
||||||
|
*/
|
||||||
|
function fixTab(tabId: string) {
|
||||||
|
const tabIndex = tabs.value.findIndex(t => t.id === tabId);
|
||||||
|
if (tabIndex === -1) return;
|
||||||
|
|
||||||
|
const tab = tabs.value[tabIndex];
|
||||||
|
const fixedCount = getFixedTabIds(tabs.value).length;
|
||||||
|
tab.fixedIndex = fixedCount;
|
||||||
|
|
||||||
|
if (tabIndex !== fixedCount) {
|
||||||
|
tabs.value.splice(tabIndex, 1);
|
||||||
|
tabs.value.splice(fixedCount, 0, tab);
|
||||||
|
}
|
||||||
|
|
||||||
|
reorderFixedTabs(tabs.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unfix tab
|
||||||
|
*
|
||||||
|
* @param tabId
|
||||||
|
*/
|
||||||
|
function unfixTab(tabId: string) {
|
||||||
|
const tabIndex = tabs.value.findIndex(t => t.id === tabId);
|
||||||
|
if (tabIndex === -1) return;
|
||||||
|
|
||||||
|
const tab = tabs.value[tabIndex];
|
||||||
|
tab.fixedIndex = undefined;
|
||||||
|
|
||||||
|
const fixedCount = getFixedTabIds(tabs.value).length;
|
||||||
|
if (tabIndex !== fixedCount) {
|
||||||
|
tabs.value.splice(tabIndex, 1);
|
||||||
|
tabs.value.splice(fixedCount, 0, tab);
|
||||||
|
}
|
||||||
|
|
||||||
|
reorderFixedTabs(tabs.value);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set new label of tab
|
* Set new label of tab
|
||||||
*
|
*
|
||||||
@@ -318,6 +361,7 @@ export const useTabStore = defineStore(SetupStoreId.Tab, () => {
|
|||||||
/** All tabs */
|
/** All tabs */
|
||||||
tabs: allTabs,
|
tabs: allTabs,
|
||||||
activeTabId,
|
activeTabId,
|
||||||
|
homeTab,
|
||||||
initHomeTab,
|
initHomeTab,
|
||||||
initTabStore,
|
initTabStore,
|
||||||
addTab,
|
addTab,
|
||||||
@@ -328,6 +372,8 @@ export const useTabStore = defineStore(SetupStoreId.Tab, () => {
|
|||||||
clearTabs,
|
clearTabs,
|
||||||
clearLeftTabs,
|
clearLeftTabs,
|
||||||
clearRightTabs,
|
clearRightTabs,
|
||||||
|
fixTab,
|
||||||
|
unfixTab,
|
||||||
switchRouteByTab,
|
switchRouteByTab,
|
||||||
setTabLabel,
|
setTabLabel,
|
||||||
resetTabLabel,
|
resetTabLabel,
|
||||||
|
|||||||
@@ -198,6 +198,18 @@ export function getFixedTabIds(tabs: App.Global.Tab[]) {
|
|||||||
return fixedTabs.map(tab => tab.id);
|
return fixedTabs.map(tab => tab.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reorder fixed tabs fixedIndex
|
||||||
|
*
|
||||||
|
* @param tabs
|
||||||
|
*/
|
||||||
|
export function reorderFixedTabs(tabs: App.Global.Tab[]) {
|
||||||
|
const fixedTabs = getFixedTabs(tabs);
|
||||||
|
fixedTabs.forEach((t, i) => {
|
||||||
|
t.fixedIndex = i;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update tabs label
|
* Update tabs label
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -48,7 +48,8 @@ export const themeSettings: App.Theme.ThemeSetting = {
|
|||||||
collapsedWidth: 64,
|
collapsedWidth: 64,
|
||||||
mixWidth: 90,
|
mixWidth: 90,
|
||||||
mixCollapsedWidth: 64,
|
mixCollapsedWidth: 64,
|
||||||
mixChildMenuWidth: 200
|
mixChildMenuWidth: 200,
|
||||||
|
autoSelectFirstMenu: false
|
||||||
},
|
},
|
||||||
footer: {
|
footer: {
|
||||||
visible: true,
|
visible: true,
|
||||||
|
|||||||
6
src/typings/app.d.ts
vendored
6
src/typings/app.d.ts
vendored
@@ -96,6 +96,8 @@ declare namespace App {
|
|||||||
mixCollapsedWidth: number;
|
mixCollapsedWidth: number;
|
||||||
/** Child menu width when the layout is 'vertical-mix', 'top-hybrid-sidebar-first', or 'top-hybrid-header-first' */
|
/** Child menu width when the layout is 'vertical-mix', 'top-hybrid-sidebar-first', or 'top-hybrid-header-first' */
|
||||||
mixChildMenuWidth: number;
|
mixChildMenuWidth: number;
|
||||||
|
/** Whether to auto select the first submenu */
|
||||||
|
autoSelectFirstMenu: boolean;
|
||||||
};
|
};
|
||||||
/** Footer */
|
/** Footer */
|
||||||
footer: {
|
footer: {
|
||||||
@@ -282,7 +284,7 @@ declare namespace App {
|
|||||||
type FormRule = import('naive-ui').FormItemRule;
|
type FormRule = import('naive-ui').FormItemRule;
|
||||||
|
|
||||||
/** The global dropdown key */
|
/** The global dropdown key */
|
||||||
type DropdownKey = 'closeCurrent' | 'closeOther' | 'closeLeft' | 'closeRight' | 'closeAll';
|
type DropdownKey = 'closeCurrent' | 'closeOther' | 'closeLeft' | 'closeRight' | 'closeAll' | 'pin' | 'unpin';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -429,6 +431,8 @@ declare namespace App {
|
|||||||
mixWidth: string;
|
mixWidth: string;
|
||||||
mixCollapsedWidth: string;
|
mixCollapsedWidth: string;
|
||||||
mixChildMenuWidth: string;
|
mixChildMenuWidth: string;
|
||||||
|
autoSelectFirstMenu: string;
|
||||||
|
autoSelectFirstMenuTip: string;
|
||||||
};
|
};
|
||||||
footer: {
|
footer: {
|
||||||
title: string;
|
title: string;
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ const bgColor = computed(() => {
|
|||||||
<NCard :bordered="false" class="relative z-4 w-auto rd-12px">
|
<NCard :bordered="false" class="relative z-4 w-auto rd-12px">
|
||||||
<div class="w-400px lt-sm:w-300px">
|
<div class="w-400px lt-sm:w-300px">
|
||||||
<header class="flex-y-center justify-between">
|
<header class="flex-y-center justify-between">
|
||||||
<SystemLogo class="text-64px text-primary lt-sm:text-48px" />
|
<SystemLogo class="size-64px lt-sm:size-48px" />
|
||||||
<h3 class="text-28px text-primary font-500 lt-sm:text-22px">{{ $t('system.title') }}</h3>
|
<h3 class="text-28px text-primary font-500 lt-sm:text-22px">{{ $t('system.title') }}</h3>
|
||||||
<div class="i-flex-col">
|
<div class="i-flex-col">
|
||||||
<ThemeSchemaSwitch
|
<ThemeSchemaSwitch
|
||||||
|
|||||||
Reference in New Issue
Block a user