chore(projects): merge main to v1.1.0

This commit is contained in:
Soybean 2024-05-05 01:34:24 +08:00
commit ebe55af7d5
46 changed files with 1330 additions and 1108 deletions

1
.npmrc
View File

@ -1,3 +1,4 @@
registry=https://registry.npmmirror.com/ registry=https://registry.npmmirror.com/
shamefully-hoist=true shamefully-hoist=true
ignore-workspace-root-check=true ignore-workspace-root-check=true
link-workspace-packages=true

View File

@ -13,7 +13,6 @@
"i18n-ally.keystyle": "nested", "i18n-ally.keystyle": "nested",
"i18n-ally.localesPaths": ["src/locales/langs"], "i18n-ally.localesPaths": ["src/locales/langs"],
"prettier.enable": false, "prettier.enable": false,
"unocss.root": ["./"],
"typescript.tsdk": "node_modules/typescript/lib", "typescript.tsdk": "node_modules/typescript/lib",
"vue.server.hybridMode": true "unocss.root": ["./"]
} }

View File

@ -1,6 +1,113 @@
# Changelog # Changelog
## [v1.0.9](https://github.com/soybeanjs/soybean-admin/compare/v1.0.8...v1.0.9) (2024-05-05)
###    🚀 Features
- **packages**: @sa/scripts: add new commit type `optimize` and commit scope `packages` &nbsp;-&nbsp; by @honghuangdc [<samp>(fbc2e)</samp>](https://github.com/soybeanjs/soybean-admin/commit/fbc2e61)
### &nbsp;&nbsp;&nbsp;🐞 Bug Fixes
- **projects**: fix manage page drawer operate about data reset. fixed #415, fixed #417 &nbsp;-&nbsp; by @honghuangdc in https://github.com/soybeanjs/soybean-admin/issues/415 and https://github.com/soybeanjs/soybean-admin/issues/417 [<samp>(f4513)</samp>](https://github.com/soybeanjs/soybean-admin/commit/f4513e1)
### &nbsp;&nbsp;&nbsp;📖 Documentation
- **projects**:
- add ecosystem to README.md &nbsp;-&nbsp; by @honghuangdc [<samp>(d0f17)</samp>](https://github.com/soybeanjs/soybean-admin/commit/d0f17a4)
- add PanisAdmin to README &nbsp;-&nbsp; by **paynezhuang** [<samp>(ce2a7)</samp>](https://github.com/soybeanjs/soybean-admin/commit/ce2a75b)
### &nbsp;&nbsp;&nbsp;🏡 Chore
- **deps**:
- update deps &nbsp;-&nbsp; by @honghuangdc [<samp>(413a8)</samp>](https://github.com/soybeanjs/soybean-admin/commit/413a8b2)
- update deps &nbsp;-&nbsp; by @honghuangdc [<samp>(734ef)</samp>](https://github.com/soybeanjs/soybean-admin/commit/734ef98)
- **projects**:
- update .npmrc &nbsp;-&nbsp; by @honghuangdc [<samp>(52188)</samp>](https://github.com/soybeanjs/soybean-admin/commit/52188d8)
- update vscode settings &nbsp;-&nbsp; by @honghuangdc [<samp>(c137b)</samp>](https://github.com/soybeanjs/soybean-admin/commit/c137b97)
### &nbsp;&nbsp;&nbsp;❤️ Contributors
[![honghuangdc](https://github.com/honghuangdc.png?size=48)](https://github.com/honghuangdc)&nbsp;&nbsp;
[paynezhuang](mailto:paynezhuang@gmail.com)
## [v1.0.8](https://github.com/soybeanjs/soybean-admin/compare/v1.0.7...v1.0.8) (2024-04-27)
### &nbsp;&nbsp;&nbsp;🐞 Bug Fixes
- **components**:
- fix PinToggler label. fixed #407 &nbsp;-&nbsp; by @honghuangdc in https://github.com/soybeanjs/soybean-admin/issues/407 [<samp>(c0ed1)</samp>](https://github.com/soybeanjs/soybean-admin/commit/c0ed1f2)
- **projects**:
- text level low. #409 &nbsp;-&nbsp; by **alleycharming** in https://github.com/soybeanjs/soybean-admin/issues/409 [<samp>(3ddb1)</samp>](https://github.com/soybeanjs/soybean-admin/commit/3ddb17a)
- fix tab fixedIndex as null case &nbsp;-&nbsp; by **paynezhuang** [<samp>(4708e)</samp>](https://github.com/soybeanjs/soybean-admin/commit/4708ede)
- recovery the layout config before is mobile. fixed #408, fixed #361 &nbsp;-&nbsp; by @honghuangdc in https://github.com/soybeanjs/soybean-admin/issues/408 and https://github.com/soybeanjs/soybean-admin/issues/361 [<samp>(dae2a)</samp>](https://github.com/soybeanjs/soybean-admin/commit/dae2aa5)
### &nbsp;&nbsp;&nbsp;🔥 Performance
- **projects**: perf judgement the fixed tab &nbsp;-&nbsp; by @honghuangdc [<samp>(b3e9b)</samp>](https://github.com/soybeanjs/soybean-admin/commit/b3e9bba)
### &nbsp;&nbsp;&nbsp;💅 Refactors
- **projects**: `Soybean Admin` to `SoybeanAdmin` &nbsp;-&nbsp; by @honghuangdc [<samp>(a8dbc)</samp>](https://github.com/soybeanjs/soybean-admin/commit/a8dbc03)
### &nbsp;&nbsp;&nbsp;❤️ Contributors
[![honghuangdc](https://github.com/honghuangdc.png?size=48)](https://github.com/honghuangdc)&nbsp;&nbsp;
[paynezhuang](mailto:paynezhuang@gmail.com),&nbsp;[alleycharming](mailto:alleycharming@gmail.com)
## [v1.0.7](https://github.com/soybeanjs/soybean-admin/compare/v1.0.6...v1.0.7) (2024-04-25)
### &nbsp;&nbsp;&nbsp;🚀 Features
- **projects**: support iframe page with diffrent url of custom route &nbsp;-&nbsp; by @honghuangdc [<samp>(da12d)</samp>](https://github.com/soybeanjs/soybean-admin/commit/da12d4a)
### &nbsp;&nbsp;&nbsp;🏡 Chore
- **deps**: update deps &nbsp;-&nbsp; by @honghuangdc [<samp>(fbd80)</samp>](https://github.com/soybeanjs/soybean-admin/commit/fbd80c2)
### &nbsp;&nbsp;&nbsp;❤️ Contributors
[![honghuangdc](https://github.com/honghuangdc.png?size=48)](https://github.com/honghuangdc)&nbsp;&nbsp;
## [v1.0.6](https://github.com/soybeanjs/soybean-admin/compare/v1.0.5...v1.0.6) (2024-04-25)
### &nbsp;&nbsp;&nbsp;🚀 Features
- **hooks**: add state hooks: useRef, useState, useSignal &nbsp;-&nbsp; by @honghuangdc [<samp>(09f64)</samp>](https://github.com/soybeanjs/soybean-admin/commit/09f6464)
### &nbsp;&nbsp;&nbsp;🐞 Bug Fixes
- **projects**:
- added responseType judgment. #396 &nbsp;-&nbsp; by **alleycharming** in https://github.com/soybeanjs/soybean-admin/issues/396 [<samp>(82eab)</samp>](https://github.com/soybeanjs/soybean-admin/commit/82eabab)
- supply $t import statement &nbsp;-&nbsp; by @honghuangdc [<samp>(b2660)</samp>](https://github.com/soybeanjs/soybean-admin/commit/b266035)
- fix mix-menu blank. fixed #389 & cache mixMenuFixed &nbsp;-&nbsp; by @honghuangdc in https://github.com/soybeanjs/soybean-admin/issues/389 [<samp>(93c7f)</samp>](https://github.com/soybeanjs/soybean-admin/commit/93c7ff7)
### &nbsp;&nbsp;&nbsp;🔥 Performance
- **hooks**:
- perf useSignal &nbsp;-&nbsp; by @honghuangdc [<samp>(5d45c)</samp>](https://github.com/soybeanjs/soybean-admin/commit/5d45cef)
- **projects**:
- remove useless prop `title` of `NDrawer` &nbsp;-&nbsp; by @honghuangdc [<samp>(fdde6)</samp>](https://github.com/soybeanjs/soybean-admin/commit/fdde679)
- add tsconfig.json for @sa/color-palette &nbsp;-&nbsp; by @honghuangdc [<samp>(d460e)</samp>](https://github.com/soybeanjs/soybean-admin/commit/d460e5c)
### &nbsp;&nbsp;&nbsp;💅 Refactors
- **hooks**: refactor useSignal, useComputed &nbsp;-&nbsp; by @honghuangdc [<samp>(3b5e4)</samp>](https://github.com/soybeanjs/soybean-admin/commit/3b5e4b3)
- **projects**: useMixMenuContext replace useMixMenu &nbsp;-&nbsp; by @honghuangdc [<samp>(1e142)</samp>](https://github.com/soybeanjs/soybean-admin/commit/1e14293)
### &nbsp;&nbsp;&nbsp;🏡 Chore
- **deps**:
- update deps &nbsp;-&nbsp; by @honghuangdc [<samp>(e57bf)</samp>](https://github.com/soybeanjs/soybean-admin/commit/e57bf0b)
- **projects**:
- use `engines` replace `packageManager` &nbsp;-&nbsp; by @honghuangdc [<samp>(dcd51)</samp>](https://github.com/soybeanjs/soybean-admin/commit/dcd51f4)
- update pnpm version requirement &nbsp;-&nbsp; by @honghuangdc [<samp>(19e65)</samp>](https://github.com/soybeanjs/soybean-admin/commit/19e65c1)
### &nbsp;&nbsp;&nbsp;❤️ Contributors
[![honghuangdc](https://github.com/honghuangdc.png?size=48)](https://github.com/honghuangdc)&nbsp;&nbsp;
[alleycharming](mailto:alleycharming@gmail.com)
## [v1.0.5](https://github.com/honghuangdc/soybean-admin/compare/v1.0.4...v1.0.5) (2024-04-24) ## [v1.0.5](https://github.com/honghuangdc/soybean-admin/compare/v1.0.4...v1.0.5) (2024-04-24)
### &nbsp;&nbsp;&nbsp;📖 Documentation ### &nbsp;&nbsp;&nbsp;📖 Documentation

View File

@ -106,6 +106,15 @@ pnpm dev
pnpm build pnpm build
``` ```
## Ecosystem
- [electron-mock-admin](https://github.com/lixin59/electron-mock-api): A Mock Api management system that helps front-end developers quickly implement interface mocks.
- [T-Shell](https://github.com/TheBlindM/T-Shell): A terminal emulator and SSH client with configurable command prompts.
- [pea](https://github.com/haitang1894/pea) : Adopting SpringBoot3.2 + JDK21, MyBatis-Plus, SpringSecurity security framework, etc., suitable for the simple permission system developed by [soybean-admin](https://gitee.com/honghuangdc/soybean-admin).
- [MalusAdmin](https://github.com/pridejoy/MalusAdmin): A backend management framework developed based on Vue3/TypeScript/NaiveUI and NET7 & Sqlsugar. It is implemented in the most original and simplest way, with a fresh and elegant front-end, a clear and elegant backend structure, and powerful functions.
- [PanisAdmin](https://github.com/paynezhuang/panis-admin): Adopting SpringBoot 3, SaToken, MySQL and other frameworks to develop and modify [soybean-admin](https://github.com/soybeanjs/soybean-admin) for the second time, adapting dynamic menu/button-level authorization. Retaining the original flavor, fresh and elegant, high-value back-end management system scaffold.
## How to Contribute ## 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). 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).

View File

@ -105,6 +105,15 @@ pnpm dev
pnpm build pnpm build
``` ```
## 周边生态
- [electron-mock-admin](https://github.com/lixin59/electron-mock-api): 一个 Mock Api 管理系统,帮助前端开发伙伴快速实现接口的 mock。
- [T-Shell](https://github.com/TheBlindM/T-Shell): 是一个可配置命令提示的终端模拟器和 SSH 客户端。
- [pea](https://github.com/haitang1894/pea) : 采用SpringBoot3.2 + JDK21、MyBatis-Plus、SpringSecurity安全框架等适配 [soybean-admin](https://gitee.com/honghuangdc/soybean-admin) 开发的简单权限系统。
- [MalusAdmin](https://github.com/pridejoy/MalusAdmin): 基于 Vue3/TypeScript/NaiveUI 和 NET7 & Sqlsugar 开发的后台管理框架。采用最原生最简洁的方式来实现, 前端清新优雅高颜值,后端 结构清晰,优雅易懂,功能强大。
- [PanisAdmin](https://github.com/paynezhuang/panis-admin): 采用SpringBoot3、SaToken、MySQL等框架开发二次修改 [soybean-admin](https://github.com/soybeanjs/soybean-admin),适配动态菜单/按钮级别的鉴权,保留原汁原味、清新优雅、高颜值的后台管理系统脚手架。
## 如何贡献 ## 如何贡献
我们热烈欢迎并感谢所有形式的贡献。如果您有任何想法或建议,欢迎通过提交 [pull requests](https://github.com/soybeanjs/soybean-admin/pulls) 或创建 GitHub [issue](https://github.com/soybeanjs/soybean-admin/issues/new) 来分享。 我们热烈欢迎并感谢所有形式的贡献。如果您有任何想法或建议,欢迎通过提交 [pull requests](https://github.com/soybeanjs/soybean-admin/pulls) 或创建 GitHub [issue](https://github.com/soybeanjs/soybean-admin/issues/new) 来分享。
@ -126,6 +135,7 @@ pnpm build
[Soybean](https://github.com/honghuangdc) [Soybean](https://github.com/honghuangdc)
## 贡献者 ## 贡献者
感谢以下贡献者的贡献。如果您想为本项目做出贡献,请参考 [如何贡献](#如何贡献)。 感谢以下贡献者的贡献。如果您想为本项目做出贡献,请参考 [如何贡献](#如何贡献)。

View File

@ -9,7 +9,18 @@ export function setupElegantRouter() {
blank: 'src/layouts/blank-layout/index.vue' blank: 'src/layouts/blank-layout/index.vue'
}, },
customRoutes: { customRoutes: {
names: ['exception_403', 'exception_404', 'exception_500'] names: [
'exception_403',
'exception_404',
'exception_500',
'document_project',
'document_project-link',
'document_vue',
'document_vite',
'document_unocss',
'document_naive',
'document_antd'
]
}, },
routePathTransformer(routeName, routePath) { routePathTransformer(routeName, routePath) {
const key = routeName as RouteKey; const key = routeName as RouteKey;

View File

@ -7,7 +7,7 @@ export default defineConfig(
'vue/multi-word-component-names': [ 'vue/multi-word-component-names': [
'warn', 'warn',
{ {
ignores: ['index', 'App', '[id]'] ignores: ['index', 'App', '[id]', '[url]']
} }
], ],
'vue/component-name-in-template-casing': [ 'vue/component-name-in-template-casing': [

View File

@ -1,8 +1,7 @@
{ {
"name": "soybean-admin", "name": "soybean-admin",
"type": "module", "type": "module",
"version": "1.0.5", "version": "1.0.9",
"packageManager": "pnpm@9.0.5",
"description": "A fresh and elegant admin template, based on Vue3、Vite3、TypeScript、NaiveUI and UnoCSS. 一个基于Vue3、Vite3、TypeScript、NaiveUI and UnoCSS的清新优雅的中后台模版。", "description": "A fresh and elegant admin template, based on Vue3、Vite3、TypeScript、NaiveUI and UnoCSS. 一个基于Vue3、Vite3、TypeScript、NaiveUI and UnoCSS的清新优雅的中后台模版。",
"author": { "author": {
"name": "Soybean", "name": "Soybean",
@ -27,6 +26,10 @@
"ant-design-vue v4", "ant-design-vue v4",
"UnoCSS" "UnoCSS"
], ],
"engines": {
"node": ">=18.12.0",
"pnpm": ">=8.7.0"
},
"scripts": { "scripts": {
"build": "vite build --mode prod", "build": "vite build --mode prod",
"build:test": "vite build --mode test", "build:test": "vite build --mode test",
@ -52,25 +55,25 @@
"@sa/utils": "workspace:*", "@sa/utils": "workspace:*",
"@vueuse/core": "10.9.0", "@vueuse/core": "10.9.0",
"clipboard": "2.0.11", "clipboard": "2.0.11",
"dayjs": "1.11.10", "dayjs": "1.11.11",
"echarts": "5.5.0", "echarts": "5.5.0",
"lodash-es": "4.17.21", "lodash-es": "4.17.21",
"naive-ui": "2.38.1", "naive-ui": "2.38.2",
"nprogress": "0.2.0", "nprogress": "0.2.0",
"pinia": "2.1.7", "pinia": "2.1.7",
"vue": "3.4.25", "vue": "3.4.26",
"vue-draggable-plus": "0.4.0", "vue-draggable-plus": "0.4.0",
"vue-i18n": "9.13.1", "vue-i18n": "9.13.1",
"vue-router": "4.3.2" "vue-router": "4.3.2"
}, },
"devDependencies": { "devDependencies": {
"@elegant-router/vue": "0.3.6", "@elegant-router/vue": "0.3.6",
"@iconify/json": "2.2.204", "@iconify/json": "2.2.206",
"@sa/scripts": "workspace:*", "@sa/scripts": "workspace:*",
"@sa/uno-preset": "workspace:*", "@sa/uno-preset": "workspace:*",
"@soybeanjs/eslint-config": "1.3.2", "@soybeanjs/eslint-config": "1.3.4",
"@types/lodash-es": "4.17.12", "@types/lodash-es": "4.17.12",
"@types/node": "20.12.7", "@types/node": "20.12.8",
"@types/nprogress": "0.2.3", "@types/nprogress": "0.2.3",
"@unocss/eslint-config": "0.59.4", "@unocss/eslint-config": "0.59.4",
"@unocss/preset-icons": "0.59.4", "@unocss/preset-icons": "0.59.4",
@ -80,21 +83,21 @@
"@unocss/vite": "0.59.4", "@unocss/vite": "0.59.4",
"@vitejs/plugin-vue": "5.0.4", "@vitejs/plugin-vue": "5.0.4",
"@vitejs/plugin-vue-jsx": "3.1.0", "@vitejs/plugin-vue-jsx": "3.1.0",
"eslint": "9.1.1", "eslint": "9.2.0",
"eslint-plugin-vue": "9.25.0", "eslint-plugin-vue": "9.25.0",
"lint-staged": "15.2.2", "lint-staged": "15.2.2",
"sass": "1.75.0", "sass": "1.76.0",
"simple-git-hooks": "2.11.1", "simple-git-hooks": "2.11.1",
"tsx": "4.7.3", "tsx": "4.9.1",
"typescript": "5.4.5", "typescript": "5.4.5",
"unplugin-icons": "0.18.5", "unplugin-icons": "0.19.0",
"unplugin-vue-components": "0.26.0", "unplugin-vue-components": "0.27.0",
"vite": "5.2.10", "vite": "5.2.11",
"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": "7.1.2", "vite-plugin-vue-devtools": "7.1.3",
"vue-eslint-parser": "9.4.2", "vue-eslint-parser": "9.4.2",
"vue-tsc": "2.0.14" "vue-tsc": "2.0.16"
}, },
"simple-git-hooks": { "simple-git-hooks": {
"commit-msg": "pnpm sa git-commit-verify", "commit-msg": "pnpm sa git-commit-verify",

View File

@ -1,6 +1,6 @@
{ {
"name": "@sa/axios", "name": "@sa/axios",
"version": "1.0.5", "version": "1.0.9",
"exports": { "exports": {
".": "./src/index.ts" ".": "./src/index.ts"
}, },

View File

@ -48,7 +48,9 @@ function createCommonRequest<ResponseData = any>(
instance.interceptors.response.use( instance.interceptors.response.use(
async response => { async response => {
if (opts.isBackendSuccess(response)) { const responseType: ResponseType = (response.config?.responseType as ResponseType) || 'json';
if (responseType !== 'json' || opts.isBackendSuccess(response)) {
return Promise.resolve(response); return Promise.resolve(response);
} }

View File

@ -1,6 +1,6 @@
{ {
"name": "@sa/color", "name": "@sa/color",
"version": "1.0.5", "version": "1.0.9",
"exports": { "exports": {
".": "./src/index.ts" ".": "./src/index.ts"
}, },

View File

@ -1,6 +1,6 @@
{ {
"name": "@sa/hooks", "name": "@sa/hooks",
"version": "1.0.5", "version": "1.0.9",
"exports": { "exports": {
".": "./src/index.ts" ".": "./src/index.ts"
}, },

View File

@ -7,4 +7,5 @@ import useHookTable from './use-table';
export { useBoolean, useLoading, useCountDown, useContext, useSvgIconRender, useHookTable }; export { useBoolean, useLoading, useCountDown, useContext, useSvgIconRender, useHookTable };
export * from './use-signal';
export * from './use-table'; export * from './use-table';

View File

@ -0,0 +1,144 @@
import { computed, ref, shallowRef, triggerRef } from 'vue';
import type {
ComputedGetter,
DebuggerOptions,
Ref,
ShallowRef,
WritableComputedOptions,
WritableComputedRef
} from 'vue';
type Updater<T> = (value: T) => T;
type Mutator<T> = (value: T) => void;
/**
* Signal is a reactive value that can be set, updated or mutated
*
* @example
* ```ts
* const count = useSignal(0);
*
* // `watchEffect`
* watchEffect(() => {
* console.log(count());
* });
*
* // watch
* watch(count, value => {
* console.log(value);
* });
*
* // useComputed
* const double = useComputed(() => count() * 2);
* const writeableDouble = useComputed({
* get: () => count() * 2,
* set: value => count.set(value / 2)
* });
* ```
*/
export interface Signal<T> {
(): Readonly<T>;
/**
* Set the value of the signal
*
* It recommend use `set` for primitive values
*
* @param value
*/
set(value: T): void;
/**
* Update the value of the signal using an updater function
*
* It recommend use `update` for non-primitive values, only the first level of the object will be reactive.
*
* @param updater
*/
update(updater: Updater<T>): void;
/**
* Mutate the value of the signal using a mutator function
*
* this action will call `triggerRef`, so the value will be tracked on `watchEffect`.
*
* It recommend use `mutate` for non-primitive values, all levels of the object will be reactive.
*
* @param mutator
*/
mutate(mutator: Mutator<T>): void;
/**
* Get the reference of the signal
*
* Sometimes it can be useful to make `v-model` work with the signal
*
* ```vue
* <template>
* <input v-model="model.count" />
* </template>;
*
* <script setup lang="ts">
* const state = useSignal({ count: 0 }, { useRef: true });
*
* const model = state.getRef();
* </script>
* ```
*/
getRef(): Readonly<ShallowRef<Readonly<T>>>;
}
export interface ReadonlySignal<T> {
(): Readonly<T>;
}
export interface SignalOptions {
/**
* Whether to use `ref` to store the value
*
* @default false use `sharedRef` to store the value
*/
useRef?: boolean;
}
export function useSignal<T>(initialValue: T, options?: SignalOptions): Signal<T> {
const { useRef } = options || {};
const state = useRef ? (ref(initialValue) as Ref<T>) : shallowRef(initialValue);
return createSignal(state);
}
export function useComputed<T>(getter: ComputedGetter<T>, debugOptions?: DebuggerOptions): ReadonlySignal<T>;
export function useComputed<T>(options: WritableComputedOptions<T>, debugOptions?: DebuggerOptions): Signal<T>;
export function useComputed<T>(
getterOrOptions: ComputedGetter<T> | WritableComputedOptions<T>,
debugOptions?: DebuggerOptions
) {
const isGetter = typeof getterOrOptions === 'function';
const computedValue = computed(getterOrOptions as any, debugOptions);
if (isGetter) {
return () => computedValue.value as ReadonlySignal<T>;
}
return createSignal(computedValue);
}
function createSignal<T>(state: ShallowRef<T> | WritableComputedRef<T>): Signal<T> {
const signal = () => state.value;
signal.set = (value: T) => {
state.value = value;
};
signal.update = (updater: Updater<T>) => {
state.value = updater(state.value);
};
signal.mutate = (mutator: Mutator<T>) => {
mutator(state.value);
triggerRef(state);
};
signal.getRef = () => state as Readonly<ShallowRef<Readonly<T>>>;
return signal;
}

View File

@ -1,6 +1,6 @@
{ {
"name": "@sa/materials", "name": "@sa/materials",
"version": "1.0.5", "version": "1.0.9",
"exports": { "exports": {
".": "./src/index.ts" ".": "./src/index.ts"
}, },

View File

@ -1,6 +1,6 @@
{ {
"name": "@sa/fetch", "name": "@sa/fetch",
"version": "1.0.5", "version": "1.0.9",
"exports": { "exports": {
".": "./src/index.ts" ".": "./src/index.ts"
}, },

View File

@ -1,6 +1,6 @@
{ {
"name": "@sa/scripts", "name": "@sa/scripts",
"version": "1.0.5", "version": "1.0.9",
"bin": { "bin": {
"sa": "./bin.ts" "sa": "./bin.ts"
}, },
@ -13,15 +13,15 @@
} }
}, },
"devDependencies": { "devDependencies": {
"@soybeanjs/changelog": "0.3.22", "@soybeanjs/changelog": "0.3.23",
"bumpp": "9.4.0", "bumpp": "9.4.1",
"c12": "1.10.0", "c12": "1.10.0",
"cac": "6.7.14", "cac": "6.7.14",
"consola": "3.2.3", "consola": "3.2.3",
"enquirer": "2.4.1", "enquirer": "2.4.1",
"execa": "8.0.1", "execa": "8.0.1",
"kolorist": "1.8.0", "kolorist": "1.8.0",
"npm-check-updates": "16.14.19", "npm-check-updates": "16.14.20",
"rimraf": "5.0.5" "rimraf": "5.0.5"
} }
} }

View File

@ -19,6 +19,7 @@ const defaultOptions: CliOption = {
['style', 'Changes that do not affect the meaning of the code'], ['style', 'Changes that do not affect the meaning of the code'],
['refactor', 'A code change that neither fixes a bug nor adds a feature'], ['refactor', 'A code change that neither fixes a bug nor adds a feature'],
['perf', 'A code change that improves performance'], ['perf', 'A code change that improves performance'],
['optimize', 'A code change that optimizes code quality'],
['test', 'Adding missing tests or correcting existing tests'], ['test', 'Adding missing tests or correcting existing tests'],
['build', 'Changes that affect the build system or external dependencies'], ['build', 'Changes that affect the build system or external dependencies'],
['ci', 'Changes to our CI configuration files and scripts'], ['ci', 'Changes to our CI configuration files and scripts'],
@ -27,6 +28,7 @@ const defaultOptions: CliOption = {
], ],
gitCommitScopes: [ gitCommitScopes: [
['projects', 'project'], ['projects', 'project'],
['packages', 'packages'],
['components', 'components'], ['components', 'components'],
['hooks', 'hook functions'], ['hooks', 'hook functions'],
['utils', 'utils functions'], ['utils', 'utils functions'],

View File

@ -1,6 +1,6 @@
{ {
"name": "@sa/uno-preset", "name": "@sa/uno-preset",
"version": "1.0.5", "version": "1.0.9",
"exports": { "exports": {
".": "./src/index.ts" ".": "./src/index.ts"
}, },

View File

@ -1,6 +1,6 @@
{ {
"name": "@sa/utils", "name": "@sa/utils",
"version": "1.0.5", "version": "1.0.9",
"exports": { "exports": {
".": "./src/index.ts" ".": "./src/index.ts"
}, },

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { $t } from '@/locales';
defineOptions({ defineOptions({
name: 'TableHeaderOperation' name: 'TableHeaderOperation'
}); });

View File

@ -36,7 +36,11 @@ const icon = computed(() => {
</script> </script>
<template> <template>
<ButtonIcon :tooltip-content="collapsed ? $t('icon.expand') : $t('icon.collapse')" tooltip-placement="bottom-start"> <ButtonIcon
:tooltip-content="collapsed ? $t('icon.expand') : $t('icon.collapse')"
tooltip-placement="bottom-start"
:z-index="99"
>
<SvgIcon :icon="icon" /> <SvgIcon :icon="icon" />
</ButtonIcon> </ButtonIcon>
</template> </template>

View File

@ -15,7 +15,7 @@ const icon = computed(() => (props.pin ? 'mdi-pin-off' : 'mdi-pin'));
<template> <template>
<ButtonIcon <ButtonIcon
:tooltip-content="pin ? $t('icon.pin') : $t('icon.unpin')" :tooltip-content="pin ? $t('icon.unpin') : $t('icon.pin')"
tooltip-placement="bottom-start" tooltip-placement="bottom-start"
:z-index="100" :z-index="100"
> >

View File

@ -1,6 +1,7 @@
import { computed, effectScope, onScopeDispose, reactive, ref, watch } from 'vue'; import { computed, effectScope, onScopeDispose, reactive, ref, watch } from 'vue';
import type { Ref } from 'vue'; import type { Ref } from 'vue';
import type { PaginationProps } from 'naive-ui'; import type { PaginationProps } from 'naive-ui';
import { cloneDeep } from 'lodash-es';
import { useBoolean, useHookTable } from '@sa/hooks'; import { useBoolean, useHookTable } from '@sa/hooks';
import { useAppStore } from '@/store/modules/app'; import { useAppStore } from '@/store/modules/app';
import { $t } from '@/locales'; import { $t } from '@/locales';
@ -194,7 +195,8 @@ export function useTableOperate<T extends TableData = TableData>(data: Ref<T[]>,
function handleEdit(id: T['id']) { function handleEdit(id: T['id']) {
operateType.value = 'edit'; operateType.value = 'edit';
editingData.value = data.value.find(item => item.id === id) || null; const findItem = data.value.find(item => item.id === id) || null;
editingData.value = cloneDeep(findItem);
openDrawer(); openDrawer();
} }

View File

@ -18,6 +18,7 @@ defineOptions({
const appStore = useAppStore(); const appStore = useAppStore();
const themeStore = useThemeStore(); const themeStore = useThemeStore();
const { menus } = setupMixMenuContext();
const layoutMode = computed(() => { const layoutMode = computed(() => {
const vertical: LayoutMode = 'vertical'; const vertical: LayoutMode = 'vertical';
@ -65,7 +66,7 @@ function getSiderWidth() {
let w = isVerticalMix.value || isHorizontalMix.value ? mixWidth : width; let w = isVerticalMix.value || isHorizontalMix.value ? mixWidth : width;
if (isVerticalMix.value && appStore.mixSiderFixed) { if (isVerticalMix.value && appStore.mixSiderFixed && menus.value.length) {
w += mixChildMenuWidth; w += mixChildMenuWidth;
} }
@ -77,14 +78,12 @@ function getSiderCollapsedWidth() {
let w = isVerticalMix.value || isHorizontalMix.value ? mixCollapsedWidth : collapsedWidth; let w = isVerticalMix.value || isHorizontalMix.value ? mixCollapsedWidth : collapsedWidth;
if (isVerticalMix.value && appStore.mixSiderFixed) { if (isVerticalMix.value && appStore.mixSiderFixed && menus.value.length) {
w += mixChildMenuWidth; w += mixChildMenuWidth;
} }
return w; return w;
} }
setupMixMenuContext();
</script> </script>
<template> <template>

View File

@ -1,4 +1,47 @@
import { computed, ref, watch } from 'vue';
import { useRoute } from 'vue-router';
import { useContext } from '@sa/hooks'; import { useContext } from '@sa/hooks';
import { useMixMenu } from '../hooks'; import { useRouteStore } from '@/store/modules/route';
export const { setupStore: setupMixMenuContext, useStore: useMixMenuContext } = useContext('mix-menu', useMixMenu); export const { setupStore: setupMixMenuContext, useStore: useMixMenuContext } = useContext('mix-menu', useMixMenu);
function useMixMenu() {
const route = useRoute();
const routeStore = useRouteStore();
const activeFirstLevelMenuKey = ref('');
function setActiveFirstLevelMenuKey(key: string) {
activeFirstLevelMenuKey.value = key;
}
function getActiveFirstLevelMenuKey() {
const { hideInMenu, activeMenu } = route.meta;
const name = route.name as string;
const routeName = (hideInMenu ? activeMenu : name) || name;
const [firstLevelRouteName] = routeName.split('_');
setActiveFirstLevelMenuKey(firstLevelRouteName);
}
const menus = computed(
() => routeStore.menus.find(menu => menu.key === activeFirstLevelMenuKey.value)?.children || []
);
watch(
() => route.name,
() => {
getActiveFirstLevelMenuKey();
},
{ immediate: true }
);
return {
activeFirstLevelMenuKey,
setActiveFirstLevelMenuKey,
getActiveFirstLevelMenuKey,
menus
};
}

View File

@ -1,44 +0,0 @@
import { computed, ref, watch } from 'vue';
import { useRoute } from 'vue-router';
import { useRouteStore } from '@/store/modules/route';
export function useMixMenu() {
const route = useRoute();
const routeStore = useRouteStore();
const activeFirstLevelMenuKey = ref('');
function setActiveFirstLevelMenuKey(key: string) {
activeFirstLevelMenuKey.value = key;
}
function getActiveFirstLevelMenuKey() {
const { hideInMenu, activeMenu } = route.meta;
const name = route.name as string;
const routeName = (hideInMenu ? activeMenu : name) || name;
const [firstLevelRouteName] = routeName.split('_');
setActiveFirstLevelMenuKey(firstLevelRouteName);
}
const menus = computed(
() => routeStore.menus.find(menu => menu.key === activeFirstLevelMenuKey.value)?.children || []
);
watch(
() => route.name,
() => {
getActiveFirstLevelMenuKey();
},
{ immediate: true }
);
return {
activeFirstLevelMenuKey,
setActiveFirstLevelMenuKey,
getActiveFirstLevelMenuKey,
menus
};
}

View File

@ -2,10 +2,10 @@
import { computed } from 'vue'; import { computed } from 'vue';
import { useBoolean } from '@sa/hooks'; import { useBoolean } from '@sa/hooks';
import { useAppStore } from '@/store/modules/app'; import { useAppStore } from '@/store/modules/app';
import { useRouteStore } from '@/store/modules/route';
import { useThemeStore } from '@/store/modules/theme'; import { useThemeStore } from '@/store/modules/theme';
import { useRouterPush } from '@/hooks/common/router'; import { useRouterPush } from '@/hooks/common/router';
import { useMixMenu } from '../../hooks'; import { $t } from '@/locales';
import { useMixMenuContext } from '../../context';
import FirstLevelMenu from './first-level-menu.vue'; import FirstLevelMenu from './first-level-menu.vue';
import BaseMenu from './base-menu.vue'; import BaseMenu from './base-menu.vue';
@ -15,16 +15,15 @@ defineOptions({
const appStore = useAppStore(); const appStore = useAppStore();
const themeStore = useThemeStore(); const themeStore = useThemeStore();
const routeStore = useRouteStore();
const { routerPushByKey } = useRouterPush(); const { routerPushByKey } = useRouterPush();
const { bool: drawerVisible, setBool: setDrawerVisible } = useBoolean(); const { bool: drawerVisible, setBool: setDrawerVisible } = useBoolean();
const { activeFirstLevelMenuKey, setActiveFirstLevelMenuKey, getActiveFirstLevelMenuKey } = useMixMenu(); const { menus, activeFirstLevelMenuKey, setActiveFirstLevelMenuKey, getActiveFirstLevelMenuKey } = useMixMenuContext();
const siderInverted = computed(() => !themeStore.darkMode && themeStore.sider.inverted); const siderInverted = computed(() => !themeStore.darkMode && themeStore.sider.inverted);
const menus = computed(() => routeStore.menus.find(menu => menu.key === activeFirstLevelMenuKey.value)?.children || []); const hasMenus = computed(() => menus.value.length > 0);
const showDrawer = computed(() => (drawerVisible.value && menus.value.length) || appStore.mixSiderFixed); const showDrawer = computed(() => hasMenus.value && (drawerVisible.value || appStore.mixSiderFixed));
function handleSelectMixMenu(menu: App.Global.Menu) { function handleSelectMixMenu(menu: App.Global.Menu) {
setActiveFirstLevelMenuKey(menu.key); setActiveFirstLevelMenuKey(menu.key);
@ -49,7 +48,7 @@ function handleResetActiveMenu() {
</FirstLevelMenu> </FirstLevelMenu>
<div <div
class="relative h-full transition-width-300" class="relative h-full transition-width-300"
:style="{ width: appStore.mixSiderFixed ? themeStore.sider.mixChildMenuWidth + 'px' : '0px' }" :style="{ width: appStore.mixSiderFixed && hasMenus ? 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"

View File

@ -140,7 +140,16 @@ const local: App.I18n.Schema = {
403: 'No Permission', 403: 'No Permission',
404: 'Page Not Found', 404: 'Page Not Found',
500: 'Server Error', 500: 'Server Error',
'iframe-page': 'Iframe',
home: 'Home', home: 'Home',
document: 'Document',
document_project: 'Project Document',
'document_project-link': 'Project Document(External Link)',
document_vue: 'Vue Document',
document_vite: 'Vite Document',
document_unocss: 'UnoCSS Document',
document_naive: 'Naive UI Document',
document_antd: 'Ant Design Vue Document',
'user-center': 'User Center', 'user-center': 'User Center',
about: 'About', about: 'About',
function: 'System Function', function: 'System Function',

View File

@ -140,7 +140,16 @@ const local: App.I18n.Schema = {
403: '无权限', 403: '无权限',
404: '页面不存在', 404: '页面不存在',
500: '服务器错误', 500: '服务器错误',
'iframe-page': '外链页面',
home: '首页', home: '首页',
document: '文档',
document_project: '项目文档',
'document_project-link': '项目文档(外链)',
document_vue: 'Vue文档',
document_vite: 'Vite文档',
document_unocss: 'UnoCSS文档',
document_naive: 'Naive UI文档',
document_antd: 'Ant Design Vue文档',
'user-center': '个人中心', 'user-center': '个人中心',
about: '关于', about: '关于',
function: '系统功能', function: '系统功能',

View File

@ -18,6 +18,7 @@ export const views: Record<LastLevelRouteKey, RouteComponent | (() => Promise<Ro
403: () => import("@/views/_builtin/403/index.vue"), 403: () => import("@/views/_builtin/403/index.vue"),
404: () => import("@/views/_builtin/404/index.vue"), 404: () => import("@/views/_builtin/404/index.vue"),
500: () => import("@/views/_builtin/500/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"), login: () => import("@/views/_builtin/login/index.vue"),
about: () => import("@/views/about/index.vue"), about: () => import("@/views/about/index.vue"),
"function_hide-child_one": () => import("@/views/function/hide-child/one/index.vue"), "function_hide-child_one": () => import("@/views/function/hide-child/one/index.vue"),

View File

@ -179,6 +179,19 @@ export const generatedRoutes: GeneratedRoute[] = [
order: 1 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', name: 'login',
path: '/login/:module(pwd-login|code-login|register|reset-pwd|bind-wechat)?', path: '/login/:module(pwd-login|code-login|register|reset-pwd|bind-wechat)?',

View File

@ -147,6 +147,14 @@ const routeMap: RouteMap = {
"exception_403": "/exception/403", "exception_403": "/exception/403",
"exception_404": "/exception/404", "exception_404": "/exception/404",
"exception_500": "/exception/500", "exception_500": "/exception/500",
"document": "/document",
"document_project": "/document/project",
"document_project-link": "/document/project-link",
"document_vue": "/document/vue",
"document_vite": "/document/vite",
"document_unocss": "/document/unocss",
"document_naive": "/document/naive",
"document_antd": "/document/antd",
"403": "/403", "403": "/403",
"404": "/404", "404": "/404",
"500": "/500", "500": "/500",
@ -162,6 +170,7 @@ const routeMap: RouteMap = {
"function_tab": "/function/tab", "function_tab": "/function/tab",
"function_toggle-auth": "/function/toggle-auth", "function_toggle-auth": "/function/toggle-auth",
"home": "/home", "home": "/home",
"iframe-page": "/iframe-page/:url",
"login": "/login/:module(pwd-login|code-login|register|reset-pwd|bind-wechat)?", "login": "/login/:module(pwd-login|code-login|register|reset-pwd|bind-wechat)?",
"manage": "/manage", "manage": "/manage",
"manage_menu": "/manage/menu", "manage_menu": "/manage/menu",

View File

@ -51,6 +51,115 @@ const customRoutes: CustomRoute[] = [
} }
} }
] ]
},
{
name: 'document',
path: '/document',
component: 'layout.base',
meta: {
title: 'document',
i18nKey: 'route.document',
order: 2,
icon: 'mdi:file-document-multiple-outline'
},
children: [
{
name: 'document_antd',
path: '/document/antd',
component: 'view.iframe-page',
props: {
url: 'https://antdv.com/components/overview-cn'
},
meta: {
title: 'document_antd',
i18nKey: 'route.document_antd',
order: 7,
icon: 'logos:ant-design'
}
},
{
name: 'document_naive',
path: '/document/naive',
component: 'view.iframe-page',
props: {
url: 'https://www.naiveui.com/zh-CN/os-theme/docs/introduction'
},
meta: {
title: 'document_naive',
i18nKey: 'route.document_naive',
order: 6,
icon: 'logos:naiveui'
}
},
{
name: 'document_project',
path: '/document/project',
component: 'view.iframe-page',
props: {
url: 'https://docs.soybeanjs.cn/zh'
},
meta: {
title: 'document_project',
i18nKey: 'route.document_project',
order: 1,
localIcon: 'logo'
}
},
{
name: 'document_project-link',
path: '/document/project-link',
component: 'view.iframe-page',
meta: {
title: 'document_project-link',
i18nKey: 'route.document_project-link',
order: 2,
localIcon: 'logo',
href: 'https://docs.soybeanjs.cn/zh'
}
},
{
name: 'document_unocss',
path: '/document/unocss',
component: 'view.iframe-page',
props: {
url: 'https://unocss.dev/'
},
meta: {
title: 'document_unocss',
i18nKey: 'route.document_unocss',
order: 5,
icon: 'logos:unocss'
}
},
{
name: 'document_vite',
path: '/document/vite',
component: 'view.iframe-page',
props: {
url: 'https://cn.vitejs.dev/'
},
meta: {
title: 'document_vite',
i18nKey: 'route.document_vite',
order: 4,
icon: 'logos:vitejs'
}
},
{
name: 'document_vue',
path: '/document/vue',
component: 'view.iframe-page',
props: {
url: 'https://cn.vuejs.org/'
},
meta: {
title: 'document_vue',
i18nKey: 'route.document_vue',
order: 3,
icon: 'logos:vue'
}
}
]
} }
]; ];

View File

@ -1,6 +1,6 @@
import { effectScope, onScopeDispose, ref, watch } from 'vue'; import { effectScope, nextTick, onScopeDispose, ref, watch } from 'vue';
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
import { breakpointsTailwind, useBreakpoints, useTitle } from '@vueuse/core'; import { breakpointsTailwind, useBreakpoints, useEventListener, useTitle } from '@vueuse/core';
import { useBoolean } from '@sa/hooks'; import { useBoolean } from '@sa/hooks';
import { SetupStoreId } from '@/enum'; import { SetupStoreId } from '@/enum';
import { router } from '@/router'; import { router } from '@/router';
@ -22,7 +22,11 @@ export const useAppStore = defineStore(SetupStoreId.App, () => {
const { bool: fullContent, toggle: toggleFullContent } = useBoolean(); const { bool: fullContent, toggle: toggleFullContent } = useBoolean();
const { bool: contentXScrollable, setBool: setContentXScrollable } = useBoolean(); const { bool: contentXScrollable, setBool: setContentXScrollable } = useBoolean();
const { bool: siderCollapse, setBool: setSiderCollapse, toggle: toggleSiderCollapse } = useBoolean(); const { bool: siderCollapse, setBool: setSiderCollapse, toggle: toggleSiderCollapse } = useBoolean();
const { bool: mixSiderFixed, setBool: setMixSiderFixed, toggle: toggleMixSiderFixed } = useBoolean(); const {
bool: mixSiderFixed,
setBool: setMixSiderFixed,
toggle: toggleMixSiderFixed
} = useBoolean(localStg.get('mixSiderFixed') === 'Y');
/** Is mobile layout */ /** Is mobile layout */
const isMobile = breakpoints.smaller('sm'); const isMobile = breakpoints.smaller('sm');
@ -83,9 +87,26 @@ export const useAppStore = defineStore(SetupStoreId.App, () => {
isMobile, isMobile,
newValue => { newValue => {
if (newValue) { if (newValue) {
setSiderCollapse(true); // backup theme setting before is mobile
localStg.set('backupThemeSettingBeforeIsMobile', {
layout: themeStore.layout.mode,
siderCollapse: siderCollapse.value
});
themeStore.setThemeLayout('vertical'); themeStore.setThemeLayout('vertical');
setSiderCollapse(true);
} else {
// when is not mobile, recover the backup theme setting
const backup = localStg.get('backupThemeSettingBeforeIsMobile');
if (backup) {
nextTick(() => {
themeStore.setThemeLayout(backup.layout);
setSiderCollapse(backup.siderCollapse);
localStg.remove('backupThemeSettingBeforeIsMobile');
});
}
} }
}, },
{ immediate: true } { immediate: true }
@ -107,6 +128,11 @@ export const useAppStore = defineStore(SetupStoreId.App, () => {
}); });
}); });
// cache mixSiderFixed
useEventListener(window, 'beforeunload', () => {
localStg.set('mixSiderFixed', mixSiderFixed.value ? 'Y' : 'N');
});
/** On scope dispose */ /** On scope dispose */
onScopeDispose(() => { onScopeDispose(() => {
scope.stop(); scope.stop();

View File

@ -16,17 +16,24 @@ export function getAllTabs(tabs: App.Global.Tab[], homeTab?: App.Global.Tab) {
const filterHomeTabs = tabs.filter(tab => tab.id !== homeTab.id); const filterHomeTabs = tabs.filter(tab => tab.id !== homeTab.id);
const fixedTabs = filterHomeTabs const fixedTabs = filterHomeTabs.filter(isFixedTab).sort((a, b) => a.fixedIndex! - b.fixedIndex!);
.filter(tab => tab.fixedIndex !== undefined)
.sort((a, b) => a.fixedIndex! - b.fixedIndex!);
const remainTabs = filterHomeTabs.filter(tab => tab.fixedIndex === undefined); const remainTabs = filterHomeTabs.filter(tab => !isFixedTab(tab));
const allTabs = [homeTab, ...fixedTabs, ...remainTabs]; const allTabs = [homeTab, ...fixedTabs, ...remainTabs];
return updateTabsLabel(allTabs); return updateTabsLabel(allTabs);
} }
/**
* Is fixed tab
*
* @param tab
*/
function isFixedTab(tab: App.Global.Tab) {
return tab.fixedIndex !== undefined && tab.fixedIndex !== null;
}
/** /**
* Get tab id by route * Get tab id by route
* *
@ -177,7 +184,7 @@ export function extractTabsByAllRoutes(router: Router, tabs: App.Global.Tab[]) {
* @param tabs * @param tabs
*/ */
export function getFixedTabs(tabs: App.Global.Tab[]) { export function getFixedTabs(tabs: App.Global.Tab[]) {
return tabs.filter(tab => tab.fixedIndex !== undefined); return tabs.filter(isFixedTab);
} }
/** /**

View File

@ -202,7 +202,7 @@ declare namespace App {
/** The tab route full path */ /** The tab route full path */
fullPath: string; fullPath: string;
/** The tab fixed index */ /** The tab fixed index */
fixedIndex?: number; fixedIndex?: number | null;
/** /**
* Tab icon * Tab icon
* *

View File

@ -1,10 +1,10 @@
/* eslint-disable */ /* eslint-disable */
/* prettier-ignore */
// @ts-nocheck // @ts-nocheck
// Generated by unplugin-vue-components // Generated by unplugin-vue-components
// Read more: https://github.com/vuejs/core/pull/3399 // Read more: https://github.com/vuejs/core/pull/3399
export {} export {}
/* prettier-ignore */
declare module 'vue' { declare module 'vue' {
export interface GlobalComponents { export interface GlobalComponents {
AppProvider: typeof import('./../components/common/app-provider.vue')['default'] AppProvider: typeof import('./../components/common/app-provider.vue')['default']

View File

@ -21,6 +21,14 @@ declare module "@elegant-router/types" {
"exception_403": "/exception/403"; "exception_403": "/exception/403";
"exception_404": "/exception/404"; "exception_404": "/exception/404";
"exception_500": "/exception/500"; "exception_500": "/exception/500";
"document": "/document";
"document_project": "/document/project";
"document_project-link": "/document/project-link";
"document_vue": "/document/vue";
"document_vite": "/document/vite";
"document_unocss": "/document/unocss";
"document_naive": "/document/naive";
"document_antd": "/document/antd";
"403": "/403"; "403": "/403";
"404": "/404"; "404": "/404";
"500": "/500"; "500": "/500";
@ -36,6 +44,7 @@ declare module "@elegant-router/types" {
"function_tab": "/function/tab"; "function_tab": "/function/tab";
"function_toggle-auth": "/function/toggle-auth"; "function_toggle-auth": "/function/toggle-auth";
"home": "/home"; "home": "/home";
"iframe-page": "/iframe-page/:url";
"login": "/login/:module(pwd-login|code-login|register|reset-pwd|bind-wechat)?"; "login": "/login/:module(pwd-login|code-login|register|reset-pwd|bind-wechat)?";
"manage": "/manage"; "manage": "/manage";
"manage_menu": "/manage/menu"; "manage_menu": "/manage/menu";
@ -72,6 +81,14 @@ declare module "@elegant-router/types" {
| "exception_403" | "exception_403"
| "exception_404" | "exception_404"
| "exception_500" | "exception_500"
| "document"
| "document_project"
| "document_project-link"
| "document_vue"
| "document_vite"
| "document_unocss"
| "document_naive"
| "document_antd"
>; >;
/** /**
@ -90,6 +107,7 @@ declare module "@elegant-router/types" {
| "about" | "about"
| "function" | "function"
| "home" | "home"
| "iframe-page"
| "login" | "login"
| "manage" | "manage"
| "multi-menu" | "multi-menu"
@ -104,6 +122,7 @@ declare module "@elegant-router/types" {
| "root" | "root"
| "not-found" | "not-found"
| "exception" | "exception"
| "document"
>; >;
/** /**
@ -114,6 +133,7 @@ declare module "@elegant-router/types" {
| "403" | "403"
| "404" | "404"
| "500" | "500"
| "iframe-page"
| "login" | "login"
| "about" | "about"
| "function_hide-child_one" | "function_hide-child_one"
@ -144,6 +164,13 @@ declare module "@elegant-router/types" {
| "exception_403" | "exception_403"
| "exception_404" | "exception_404"
| "exception_500" | "exception_500"
| "document_project"
| "document_project-link"
| "document_vue"
| "document_vite"
| "document_unocss"
| "document_naive"
| "document_antd"
>; >;
/** /**

View File

@ -58,7 +58,7 @@ declare module 'vue-router' {
/** By default, the same route path will use one tab, if set to true, it will use multiple tabs */ /** By default, the same route path will use one tab, if set to true, it will use multiple tabs */
multiTab?: boolean; multiTab?: boolean;
/** If set, the route will be fixed in tabs, and the value is the order of fixed tabs */ /** If set, the route will be fixed in tabs, and the value is the order of fixed tabs */
fixedIndexInTab?: number; fixedIndexInTab?: number | null;
/** if set query parameters, it will be automatically carried when entering the route */ /** if set query parameters, it will be automatically carried when entering the route */
query?: Record<string, string>; query?: Record<string, string>;
} }

View File

@ -14,6 +14,8 @@ declare namespace StorageType {
lang: App.I18n.LangType; lang: App.I18n.LangType;
/** The token */ /** The token */
token: string; token: string;
/** Fixed sider with mix-menu */
mixSiderFixed: CommonType.YesOrNo;
/** The refresh token */ /** The refresh token */
refreshToken: string; refreshToken: string;
/** The user info */ /** The user info */
@ -30,5 +32,10 @@ declare namespace StorageType {
overrideThemeFlag: string; overrideThemeFlag: string;
/** The global tabs */ /** The global tabs */
globalTabs: App.Global.Tab[]; globalTabs: App.Global.Tab[];
/** The backup theme setting before is mobile */
backupThemeSettingBeforeIsMobile: {
layout: UnionKey.ThemeLayoutMode;
siderCollapse: boolean;
};
} }
} }

View File

@ -0,0 +1,25 @@
<script setup lang="ts">
import { onActivated, onMounted } from 'vue';
interface Props {
url: string;
}
defineProps<Props>();
onMounted(() => {
console.log('mounted');
});
onActivated(() => {
console.log('activated');
});
</script>
<template>
<div class="h-full">
<iframe id="iframePage" class="size-full" :src="url"></iframe>
</div>
</template>
<style scoped></style>

View File

@ -187,20 +187,18 @@ async function getRoleOptions() {
} }
} }
function handleUpdateModel() { function handleInitModel() {
if (props.operateType === 'add') {
Object.assign(model, createDefaultModel()); Object.assign(model, createDefaultModel());
return; if (!props.rowData) return;
}
if (props.operateType === 'addChild' && props.rowData) { if (props.operateType === 'addChild') {
const { id } = props.rowData; const { id } = props.rowData;
Object.assign(model, createDefaultModel(), { parentId: id }); Object.assign(model, { parentId: id });
} }
if (props.operateType === 'edit' && props.rowData) { if (props.operateType === 'edit') {
const { component, query, ...rest } = props.rowData; const { component, query, ...rest } = props.rowData;
const { layout, page } = getLayoutAndPage(component); const { layout, page } = getLayoutAndPage(component);
@ -233,7 +231,7 @@ async function handleSubmit() {
watch(visible, () => { watch(visible, () => {
if (visible.value) { if (visible.value) {
handleUpdateModel(); handleInitModel();
restoreValidation(); restoreValidation();
getRoleOptions(); getRoleOptions();
} }
@ -241,9 +239,9 @@ watch(visible, () => {
</script> </script>
<template> <template>
<NDrawer v-model:show="visible" display-directive="show" :width="400"> <NModal v-model:show="visible" :title="title" preset="card" class="w-720px">
<NDrawerContent :title="title" :native-scrollbar="false" closable> <NScrollbar class="h-400px">
<NForm ref="formRef" :model="model" :rules="rules" label-placement="left" :label-width="80"> <NForm ref="formRef" :model="model" :rules="rules" label-placement="left" :label-width="100">
<NGrid> <NGrid>
<NFormItemGi span="12" :label="$t('page.manage.menu.menuType')" path="menuType"> <NFormItemGi span="12" :label="$t('page.manage.menu.menuType')" path="menuType">
<NRadioGroup v-model:value="model.menuType" :disabled="disabledMenuType"> <NRadioGroup v-model:value="model.menuType" :disabled="disabledMenuType">
@ -384,14 +382,14 @@ watch(visible, () => {
</NFormItemGi> </NFormItemGi>
</NGrid> </NGrid>
</NForm> </NForm>
</NScrollbar>
<template #footer> <template #footer>
<NSpace :size="16"> <NSpace justify="end" :size="16">
<NButton @click="closeDrawer">{{ $t('common.cancel') }}</NButton> <NButton @click="closeDrawer">{{ $t('common.cancel') }}</NButton>
<NButton type="primary" @click="handleSubmit">{{ $t('common.confirm') }}</NButton> <NButton type="primary" @click="handleSubmit">{{ $t('common.confirm') }}</NButton>
</NSpace> </NSpace>
</template> </template>
</NDrawerContent> </NModal>
</NDrawer>
</template> </template>
<style scoped></style> <style scoped></style>

View File

@ -68,11 +68,8 @@ const roleId = computed(() => props.rowData?.id || -1);
const isEdit = computed(() => props.operateType === 'edit'); const isEdit = computed(() => props.operateType === 'edit');
function handleUpdateModelWhenEdit() { function handleInitModel() {
if (props.operateType === 'add') {
Object.assign(model, createDefaultModel()); Object.assign(model, createDefaultModel());
return;
}
if (props.operateType === 'edit' && props.rowData) { if (props.operateType === 'edit' && props.rowData) {
Object.assign(model, props.rowData); Object.assign(model, props.rowData);
@ -93,14 +90,14 @@ async function handleSubmit() {
watch(visible, () => { watch(visible, () => {
if (visible.value) { if (visible.value) {
handleUpdateModelWhenEdit(); handleInitModel();
restoreValidation(); restoreValidation();
} }
}); });
</script> </script>
<template> <template>
<NDrawer v-model:show="visible" :title="title" display-directive="show" :width="360"> <NDrawer v-model:show="visible" display-directive="show" :width="360">
<NDrawerContent :title="title" :native-scrollbar="false" closable> <NDrawerContent :title="title" :native-scrollbar="false" closable>
<NForm ref="formRef" :model="model" :rules="rules"> <NForm ref="formRef" :model="model" :rules="rules">
<NFormItem :label="$t('page.manage.role.roleName')" path="roleName"> <NFormItem :label="$t('page.manage.role.roleName')" path="roleName">

View File

@ -89,11 +89,8 @@ async function getRoleOptions() {
} }
} }
function handleUpdateModelWhenEdit() { function handleInitModel() {
if (props.operateType === 'add') {
Object.assign(model, createDefaultModel()); Object.assign(model, createDefaultModel());
return;
}
if (props.operateType === 'edit' && props.rowData) { if (props.operateType === 'edit' && props.rowData) {
Object.assign(model, props.rowData); Object.assign(model, props.rowData);
@ -114,7 +111,7 @@ async function handleSubmit() {
watch(visible, () => { watch(visible, () => {
if (visible.value) { if (visible.value) {
handleUpdateModelWhenEdit(); handleInitModel();
restoreValidation(); restoreValidation();
getRoleOptions(); getRoleOptions();
} }
@ -122,7 +119,7 @@ watch(visible, () => {
</script> </script>
<template> <template>
<NDrawer v-model:show="visible" :title="title" display-directive="show" :width="360"> <NDrawer v-model:show="visible" display-directive="show" :width="360">
<NDrawerContent :title="title" :native-scrollbar="false" closable> <NDrawerContent :title="title" :native-scrollbar="false" closable>
<NForm ref="formRef" :model="model" :rules="rules"> <NForm ref="formRef" :model="model" :rules="rules">
<NFormItem :label="$t('page.manage.user.userName')" path="userName"> <NFormItem :label="$t('page.manage.user.userName')" path="userName">