Merge remote-tracking branch 'soybeanjs/main' into ruoyi

# Conflicts:
#	CHANGELOG.md
#	README.md
#	build/config/proxy.ts
#	build/plugins/index.ts
#	package.json
#	src/plugins/loading.ts
#	src/service/request/index.ts
#	src/store/modules/auth/index.ts
#	src/store/modules/route/index.ts
#	src/typings/vite-env.d.ts
#	src/views/_builtin/login/modules/pwd-login.vue
This commit is contained in:
xlsea
2025-04-23 15:18:24 +08:00
70 changed files with 1652 additions and 2152 deletions

7
.env
View File

@ -51,3 +51,10 @@ VITE_STORAGE_PREFIX=ry_
# used to control whether the program automatically detects updates
VITE_AUTOMATICALLY_DETECT_UPDATE=Y
# show proxy url log in terminal
VITE_PROXY_LOG=Y
# used to control whether to launch editor
# by the way, this plugin is only available in dev mode, not in build mode
VITE_DEVTOOLS_LAUNCH_EDITOR=code

View File

@ -1,5 +1,5 @@
# backend service base url, test environment
VITE_SERVICE_BASE_URL=http://192.168.0.52:18181
VITE_SERVICE_BASE_URL=http://127.0.0.1:8080
VITE_APP_BASE_API=/dev-api

4
.vscode/launch.json vendored
View File

@ -14,7 +14,9 @@
"name": "TS Debugger",
"runtimeExecutable": "tsx",
"skipFiles": ["<node_internals>/**", "${workspaceFolder}/node_modules/**"],
"program": "${file}"
"program": "${file}",
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen"
}
]
}

View File

@ -3,7 +3,6 @@
"source.fixAll.eslint": "explicit",
"source.organizeImports": "never"
},
"eslint.useFlatConfig": true,
"editor.formatOnSave": false,
"eslint.validate": ["html", "css", "scss", "json", "jsonc"],
"i18n-ally.displayLanguage": "zh-cn",

51
.vscode/vue3.code-snippets vendored Normal file
View File

@ -0,0 +1,51 @@
{
"Print soy Vue3 SFC page": {
"scope": "vue",
"prefix": ["v3","page","view"],
"body": [
"<script lang=\"ts\" setup>",
"//$1",
"</script>\n",
"<template>",
" <div class=\"\">",
" <!-- page only one root element -->",
" $2",
" </div>",
"</template>\n",
],
},
"Print soy Vue3 SFC Component": {
"scope": "vue",
"prefix": ["component","comp"],
"body": [
"<script lang=\"ts\" setup>",
"//$1",
"</script>\n",
"<template>",
" <div class=\"\">",
" $2",
" </div>",
"</template>\n",
],
},
"Print soy style": {
"scope": "vue",
"prefix": "st",
"body": ["<style scoped>", "//", "</style>\n"],
},
"Print soy script": {
"scope": "vue",
"prefix": "sc",
"body": ["<script lang=\"ts\" setup>", "//$3", "</script>\n"],
},
"Print soy template": {
"scope": "vue",
"prefix": "te",
"body": [
"<template>",
" <div class=\"\">$1</div>",
"</template>\n",
],
},
}

View File

@ -1,184 +0,0 @@
<div align="center">
<img src="./public/favicon.svg" width="160" />
<h1>SoybeanAdmin</h1>
<span><a href="./README.md">中文</a> | English</span>
</div>
---
[![license](https://img.shields.io/badge/license-MIT-green.svg)](./LICENSE)
[![github stars](https://img.shields.io/github/stars/soybeanjs/soybean-admin)](https://github.com/soybeanjs/soybean-admin)
[![github forks](https://img.shields.io/github/forks/soybeanjs/soybean-admin)](https://github.com/soybeanjs/soybean-admin)
[![gitee stars](https://gitee.com/honghuangdc/soybean-admin/badge/star.svg)](https://gitee.com/honghuangdc/soybean-admin)
<a href="https://hellogithub.com/repository/1298f27d5fe54959a16cf9686516ddb3" target="_blank"><img src="https://abroad.hellogithub.com/v1/widgets/recommend.svg?rid=1298f27d5fe54959a16cf9686516ddb3&claim_uid=IiDXWmP4TEntjbV" alt="FeaturedHelloGitHub" style="width: 250px; height: 54px;" width="250" height="54" /></a>
> [!NOTE]
> If you think `SoybeanAdmin` is helpful to you, or you like our project, please give us a ⭐️ on GitHub. Your support is the driving force for us to continue to improve and add new features! Thank you for your support!
## Introduction
[`SoybeanAdmin`](https://github.com/soybeanjs/soybean-admin) is a clean, elegant, beautiful and powerful admin template, based on the latest front-end technology stack, including Vue3, Vite5, TypeScript, Pinia and UnoCSS. It has built-in rich theme configuration and components, strict code specifications, and an automated file routing system. In addition, it also uses the online mock data solution based on ApiFox. `SoybeanAdmin` provides you with a one-stop admin solution, no additional configuration, and out of the box. It is also a best practice for learning cutting-edge technologies quickly.
## Features
- **Cutting-edge technology application**: using the latest popular technology stack such as Vue3, Vite5, TypeScript, Pinia and UnoCSS.
- **Clear project architecture**: using pnpm monorepo architecture, clear structure, elegant and easy to understand.
- **Strict code specifications**: follow the [SoybeanJS specification](https://docs.soybeanjs.cn/standard), integrate eslint, prettier and simple-git-hooks to ensure the code is standardized.
- **TypeScript**: support strict type checking to improve code maintainability.
- **Rich theme configuration**: built-in a variety of theme configurations, perfectly integrated with UnoCSS.
- **Built-in internationalization solution**: easily realize multi-language support.
- **Automated file routing system**: automatically generate route import, declaration and type. For more details, please refer to [Elegant Router](https://github.com/soybeanjs/elegant-router).
- **Flexible permission routing**: support both front-end static routing and back-end dynamic routing.
- **Rich page components**: built-in a variety of pages and components, including 403, 404, 500 pages, as well as layout components, tag components, theme configuration components, etc.
- **Command line tool**: built-in efficient command line tool, git commit, delete file, release, etc.
- **Mobile adaptation**: perfectly support mobile terminal to realize adaptive layout.
## Version
- **NaiveUI Version:**
- [Preview Link](https://naive.soybeanjs.cn/)
- [Github Repository](https://github.com/soybeanjs/soybean-admin)
- [Gitee Repository](https://gitee.com/honghuangdc/soybean-admin)
- **AntDesignVue Version:**
- [Preview Link](https://antd.soybeanjs.cn/)
- [Github Repository](https://github.com/soybeanjs/soybean-admin-antd)
- [Gitee Repository](https://gitee.com/honghuangdc/soybean-admin-antd)
- **ElementPlus Version:**
- [Preview Link](https://elp.soybeanjs.cn/)
- [Github Repository](https://github.com/soybeanjs/soybean-admin-element-plus)
- **Legacy Version:**
- [Preview Link](https://legacy.soybeanjs.cn/)
- [Github Repository](https://github.com/soybeanjs/soybean-admin/tree/legacy)
## Documentation
- [Link](https://docs.soybeanjs.cn)
- [Legacy Docs](https://legacy-docs.soybeanjs.cn)
## Example Images
![](https://soybeanjs-1300612522.cos.ap-guangzhou.myqcloud.com/uPic/soybean-admin-v1-01.png)
![](https://soybeanjs-1300612522.cos.ap-guangzhou.myqcloud.com/uPic/soybean-admin-v1-02.png)
![](https://soybeanjs-1300612522.cos.ap-guangzhou.myqcloud.com/uPic/soybean-admin-v1-03.png)
![](https://soybeanjs-1300612522.cos.ap-guangzhou.myqcloud.com/uPic/soybean-admin-v1-04.png)
![](https://soybeanjs-1300612522.cos.ap-guangzhou.myqcloud.com/uPic/soybean-admin-v1-05.png)
![](https://soybeanjs-1300612522.cos.ap-guangzhou.myqcloud.com/uPic/soybean-admin-v1-06.png)
![](https://soybeanjs-1300612522.cos.ap-guangzhou.myqcloud.com/uPic/soybean-admin-v1-07.png)
![](https://soybeanjs-1300612522.cos.ap-guangzhou.myqcloud.com/uPic/soybean-admin-v1-08.png)
![](https://soybeanjs-1300612522.cos.ap-guangzhou.myqcloud.com/uPic/soybean-admin-v1-09.png)
![](https://soybeanjs-1300612522.cos.ap-guangzhou.myqcloud.com/uPic/soybean-admin-v1-10.png)
![](https://soybeanjs-1300612522.cos.ap-guangzhou.myqcloud.com/uPic/soybean-admin-v1-mobile.png)
## Usage
**Environment Preparation**
Make sure your environment meets the following requirements:
- **git**: you need git to clone and manage project versions.
- **NodeJS**: >=18.12.0, recommended 18.19.0 or higher.
- **pnpm**: >= 8.7.0, recommended 8.14.0 or higher.
**Clone Project**
```bash
git clone https://github.com/soybeanjs/soybean-admin.git
```
**Install Dependencies**
```bash
pnpm i
```
> Since this project uses the pnpm monorepo management method, please do not use npm or yarn to install dependencies.
**Start Project**
```bash
pnpm dev
```
**Build Project**
```bash
pnpm build
```
**Code Synchronization**
Refer to the [Code Synchronization](https://docs.soybeanjs.cn/guide/sync) document.
## Ecosystem
- [react-soybean-admin](https://github.com/mufeng889/react-soybean-admin): SoybeanAdmin based version of React.
- [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.
- [snail-job](https://github.com/aizuda/snail-job): A distributed task retry and task scheduling platform with "high performance, high value and high activity".
- [SuperApi](https://github.com/TmmTop/SuperApi): Quickly turn your idea into an online stable product! Entity-less library and table building, add, delete, change and check entity-less library table, support 15 kinds of condition query, as well as paging, list, unlimited tree list and other functions of the API deployment! With interface documentation, Auth authorisation, interface flow restriction, access to the client's real IP, advanced server caching components, dynamic APIs and other features, we look forward to your experience!
- [FastSoyAdmin](https://github.com/sleep1223/fast-soy-admin): A modern Management Platform based on FastAPI+Vue3+Naive UI.
## 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).
## Git Commit Guidelines
This project has built-in `commit` command, you can execute `pnpm commit` to generate commit information that conforms to [Conventional Commits](https://www.conventionalcommits.org/) specification. When submitting PR, please be sure to use `commit` command to create commit information to ensure the standardization of information.
## Browser Support
It is recommended to use the latest version of Chrome in development for a better experience.
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/archive/internet-explorer_9-11/internet-explorer_9-11_48x48.png" alt="IE" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/) | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt=" Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/) | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/) | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/) | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/) |
| --- | --- | --- | --- | --- |
| not support | last 2 versions | last 2 versions | last 2 versions | last 2 versions |
## OpenSource Author
[Soybean](https://github.com/honghuangdc)
## Contributors
Thanks the following people for their contributions. If you want to contribute to this project, please refer to [How to Contribute](#how-to-contribute).
<a href="https://github.com/soybeanjs/soybean-admin/graphs/contributors">
<img src="https://contrib.rocks/image?repo=soybeanjs/soybean-admin" />
</a>
## Communication
`SoybeanAdmin` is a completely open source and free project, helping developers to develop medium and large-scale management systems more conveniently. It also provides WeChat and QQ communication groups. If you have any questions, please feel free to ask in the group.
<div>
<p>QQ Group</p>
<img src="https://soybeanjs-1300612522.cos.ap-guangzhou.myqcloud.com/uPic/qq-soybean-admin-3.jpg" style="width:200px" />
</div>
<!-- <div>
<p>WeChat Group</p>
<img src="https://soybeanjs-1300612522.cos.ap-guangzhou.myqcloud.com/picgo/soybean-admin-wechat-0620.jpg" style="width:200px" />
</div> -->
<div>
<p>Add the following WeChat to invite to the WeChat group</p>
<img src="https://soybeanjs-1300612522.cos.ap-guangzhou.myqcloud.com/uPic/wechat-soybeanjs.jpg" style="width:200px" />
</div>
## Star Trend
[![Star History Chart](https://api.star-history.com/svg?repos=soybeanjs/soybean-admin&type=Date)](https://star-history.com/#soybeanjs/soybean-admin&Date)
## License
This project is based on the [MIT © 2021 Soybean](./LICENSE) protocol, for learning purposes only, please retain the author's copyright information for commercial use, the author does not guarantee and is not responsible for the software.

View File

@ -1,4 +1,6 @@
import type { ProxyOptions } from 'vite';
import type { HttpProxy, ProxyOptions } from 'vite';
import { bgRed, bgYellow, green, lightBlue } from 'kolorist';
import { consola } from 'consola';
import { createServiceConfig } from '../../src/utils/service';
/**
@ -12,24 +14,41 @@ export function createViteProxy(env: Env.ImportMeta, enable: boolean) {
if (!isEnableHttpProxy) return undefined;
const isEnableProxyLog = env.VITE_PROXY_LOG === 'Y';
const { baseURL, proxyPattern, ws, other } = createServiceConfig(env);
const proxy: Record<string, ProxyOptions> = createProxyItem({ baseURL, ws, proxyPattern });
const proxy: Record<string, ProxyOptions> = createProxyItem({ baseURL, ws, proxyPattern }, isEnableProxyLog);
other.forEach(item => {
Object.assign(proxy, createProxyItem(item));
Object.assign(proxy, createProxyItem(item, isEnableProxyLog));
});
return proxy;
}
function createProxyItem(item: App.Service.ServiceConfigItem) {
function createProxyItem(item: App.Service.ServiceConfigItem, enableLog: boolean) {
const proxy: Record<string, ProxyOptions> = {};
proxy[item.proxyPattern] = {
target: item.baseURL,
changeOrigin: true,
ws: item.ws,
configure: (_proxy: HttpProxy.Server, options: ProxyOptions) => {
_proxy.on('proxyReq', (_proxyReq, req, _res) => {
if (!enableLog) return;
const requestUrl = `${lightBlue('[proxy url]')}: ${bgYellow(` ${req.method} `)} ${green(`${item.proxyPattern}${req.url}`)}`;
const proxyUrl = `${lightBlue('[real request url]')}: ${green(`${options.target}${req.url}`)}`;
consola.log(`${requestUrl}\n${proxyUrl}`);
});
_proxy.on('error', (_err, req, _res) => {
if (!enableLog) return;
consola.log(bgRed(`Error: ${req.method} `), green(`${options.target}${req.url}`));
});
},
rewrite: path => path.replace(new RegExp(`^${item.proxyPattern}`), '')
};

View File

@ -0,0 +1,9 @@
import VueDevtools from 'vite-plugin-vue-devtools';
export function setupDevtoolsPlugin(viteEnv: Env.ImportMeta) {
const { VITE_DEVTOOLS_LAUNCH_EDITOR } = viteEnv;
return VueDevtools({
launchEditor: VITE_DEVTOOLS_LAUNCH_EDITOR
});
}

View File

@ -1,19 +1,19 @@
import type { PluginOption } from 'vite';
import vue from '@vitejs/plugin-vue';
import vueJsx from '@vitejs/plugin-vue-jsx';
import VueDevtools from 'vite-plugin-vue-devtools';
import progress from 'vite-plugin-progress';
import { setupElegantRouter } from './router';
import { setupUnocss } from './unocss';
import { setupUnplugin } from './unplugin';
import { setupHtmlPlugin } from './html';
import { setupDevtoolsPlugin } from './devtools';
import { setupMonacoEditorPlugin } from './monaco-editor';
export function setupVitePlugins(viteEnv: Env.ImportMeta, buildTime: string) {
const plugins: PluginOption = [
vue(),
vueJsx(),
VueDevtools(),
setupDevtoolsPlugin(viteEnv),
setupElegantRouter(),
setupUnocss(viteEnv),
...setupUnplugin(viteEnv),

View File

@ -1,12 +1,12 @@
import process from 'node:process';
import path from 'node:path';
import type { PluginOption } from 'vite';
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons';
import Icons from 'unplugin-icons/vite';
import IconsResolver from 'unplugin-icons/resolver';
import Components from 'unplugin-vue-components/vite';
import { NaiveUiResolver } from 'unplugin-vue-components/resolvers';
import { FileSystemIconLoader } from 'unplugin-icons/loaders';
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons';
export function setupUnplugin(viteEnv: Env.ImportMeta) {
const { VITE_ICON_PREFIX, VITE_ICON_LOCAL_PREFIX } = viteEnv;

View File

@ -1,7 +1,7 @@
{
"name": "ruoyi-vue-plus",
"type": "module",
"version": "1.3.11",
"version": "1.3.13",
"description": "RuoYi-Vue-Plus多租户管理系统",
"author": {
"name": "xlsea",
@ -10,18 +10,24 @@
},
"license": "MIT",
"homepage": "https://gitee.com/xlsea/ruoyi-plus-soybean",
"repository": {
"url": "https://gitee.com/xlsea/ruoyi-plus-soybean.git"
},
"bugs": {
"url": "https://gitee.com/xlsea/ruoyi-plus-soybean/issues"
},
"keywords": [
"RuoYi-Vue-Plus",
"Vue3 admin ",
"vue-admin-template",
"Vite5",
"Vite6",
"TypeScript",
"naive-ui",
"naive-ui-admin",
"UnoCSS"
],
"engines": {
"node": ">=18.12.0",
"node": ">=18.20.0",
"pnpm": ">=8.7.0"
},
"scripts": {
@ -51,7 +57,7 @@
"@sa/materials": "workspace:*",
"@sa/utils": "workspace:*",
"@tinymce/tinymce-vue": "^6.1.0",
"@vueuse/core": "12.5.0",
"@vueuse/core": "13.0.0",
"clipboard": "2.0.11",
"dayjs": "1.11.13",
"defu": "6.1.4",
@ -61,47 +67,49 @@
"monaco-editor": "^0.52.0",
"naive-ui": "2.41.0",
"nprogress": "0.2.0",
"pinia": "3.0.0",
"tailwind-merge": "3.0.1",
"pinia": "3.0.1",
"tailwind-merge": "3.0.2",
"tinymce": "^7",
"vue": "3.5.13",
"vue-draggable-plus": "0.6.0",
"vue-i18n": "11.1.1",
"vue-i18n": "11.1.2",
"vue-json-pretty": "^2.4.0",
"vue-router": "4.5.0"
},
"devDependencies": {
"@elegant-router/vue": "0.3.8",
"@iconify/json": "2.2.305",
"@iconify/json": "2.2.318",
"@sa/scripts": "workspace:*",
"@sa/uno-preset": "workspace:*",
"@soybeanjs/eslint-config": "1.4.4",
"@types/node": "22.13.1",
"@soybeanjs/eslint-config": "1.6.0",
"@types/node": "22.13.10",
"@types/nprogress": "0.2.3",
"@unocss/eslint-config": "65.4.3",
"@unocss/preset-icons": "65.4.3",
"@unocss/preset-uno": "65.4.3",
"@unocss/transformer-directives": "65.4.3",
"@unocss/transformer-variant-group": "65.4.3",
"@unocss/vite": "65.4.3",
"@vitejs/plugin-vue": "5.2.1",
"@vitejs/plugin-vue-jsx": "4.1.1",
"eslint": "9.20.0",
"eslint-plugin-vue": "9.32.0",
"lint-staged": "15.4.3",
"sass": "1.84.0",
"@unocss/eslint-config": "66.0.0",
"@unocss/preset-icons": "66.0.0",
"@unocss/preset-uno": "66.0.0",
"@unocss/transformer-directives": "66.0.0",
"@unocss/transformer-variant-group": "66.0.0",
"@unocss/vite": "66.0.0",
"@vitejs/plugin-vue": "5.2.3",
"@vitejs/plugin-vue-jsx": "4.1.2",
"consola": "3.4.2",
"eslint": "9.22.0",
"eslint-plugin-vue": "10.0.0",
"kolorist": "1.8.0",
"lint-staged": "15.5.0",
"sass": "1.86.0",
"simple-git-hooks": "2.11.1",
"tsx": "4.19.2",
"typescript": "5.7.3",
"unplugin-icons": "22.0.0",
"unplugin-vue-components": "28.0.0",
"vite": "6.1.0",
"tsx": "4.19.3",
"typescript": "5.8.2",
"unplugin-icons": "22.1.0",
"unplugin-vue-components": "28.4.1",
"vite": "6.2.2",
"vite-plugin-monaco-editor": "^1.1.0",
"vite-plugin-progress": "0.0.7",
"vite-plugin-svg-icons": "2.0.1",
"vite-plugin-vue-devtools": "7.7.1",
"vue-eslint-parser": "9.4.3",
"vue-tsc": "2.2.0"
"vite-plugin-vue-devtools": "7.7.2",
"vue-eslint-parser": "10.1.1",
"vue-tsc": "2.2.8"
},
"simple-git-hooks": {
"commit-msg": "pnpm sa git-commit-verify",

View File

@ -1,6 +1,6 @@
{
"name": "@sa/alova",
"version": "1.3.11",
"version": "1.3.13",
"exports": {
".": "./src/index.ts",
"./fetch": "./src/fetch.ts",
@ -13,8 +13,8 @@
}
},
"dependencies": {
"@alova/mock": "2.0.11",
"@alova/mock": "2.0.12",
"@sa/utils": "workspace:*",
"alova": "3.2.8"
"alova": "3.2.10"
}
}

View File

@ -1,6 +1,6 @@
{
"name": "@sa/axios",
"version": "1.3.11",
"version": "1.3.13",
"exports": {
".": "./src/index.ts"
},
@ -11,7 +11,7 @@
},
"dependencies": {
"@sa/utils": "workspace:*",
"axios": "1.7.9",
"axios": "1.8.3",
"axios-retry": "4.5.0",
"qs": "6.14.0"
},

View File

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

View File

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

View File

@ -1,5 +1,5 @@
import { computed, reactive, ref } from 'vue';
import type { Ref } from 'vue';
import type { Ref, VNodeChild } from 'vue';
import { jsonClone } from '@sa/utils';
import useBoolean from './use-boolean';
import useLoading from './use-loading';
@ -8,9 +8,11 @@ export type MaybePromise<T> = T | Promise<T>;
export type ApiFn = (args: any) => Promise<unknown>;
export type TableColumnCheckTitle = string | ((...args: any) => VNodeChild);
export type TableColumnCheck = {
key: string;
title: string;
title: TableColumnCheckTitle;
checked: boolean;
};

View File

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

View File

@ -63,7 +63,7 @@ function handleClose() {
<slot></slot>
<template #suffix>
<slot name="suffix">
<SvgClose v-if="closable" :class="[style['svg-close']]" @click.stop="handleClose" />
<SvgClose v-if="closable" :class="[style['svg-close']]" @pointerdown.stop="handleClose" />
</slot>
</template>
</component>

View File

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

View File

@ -1,6 +1,6 @@
{
"name": "@sa/scripts",
"version": "1.3.11",
"version": "1.3.13",
"bin": {
"sa": "./bin.ts"
},
@ -14,14 +14,14 @@
},
"devDependencies": {
"@soybeanjs/changelog": "0.3.24",
"bumpp": "10.0.3",
"c12": "2.0.2",
"bumpp": "10.1.0",
"c12": "3.0.2",
"cac": "6.7.14",
"consola": "3.4.0",
"consola": "3.4.2",
"enquirer": "2.4.1",
"execa": "9.5.2",
"kolorist": "1.8.0",
"npm-check-updates": "17.1.14",
"npm-check-updates": "17.1.15",
"rimraf": "6.0.1"
}
}

View File

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

View File

@ -1,6 +1,6 @@
{
"name": "@sa/utils",
"version": "1.3.11",
"version": "1.3.13",
"exports": {
".": "./src/index.ts"
},
@ -14,7 +14,7 @@
"crypto-js": "4.2.0",
"klona": "2.0.6",
"localforage": "1.10.0",
"nanoid": "5.0.9"
"nanoid": "5.1.5"
},
"devDependencies": {
"@types/crypto-js": "4.2.2"

3145
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@ -25,7 +25,10 @@ const columns = defineModel<NaiveUI.TableColumnCheck[]>('columns', {
<div v-for="item in columns" :key="item.key" class="h-36px flex-y-center rd-4px hover:(bg-primary bg-opacity-20)">
<icon-mdi-drag class="mr-8px h-full cursor-move text-icon" />
<NCheckbox v-model:checked="item.checked" class="none_draggable flex-1">
{{ item.title }}
<template v-if="typeof item.title === 'function'">
<component :is="item.title" />
</template>
<template v-else>{{ item.title }}</template>
</NCheckbox>
</div>
</VueDraggable>

View File

@ -1,7 +1,7 @@
<script lang="ts" setup>
import { computed } from 'vue';
import { $t } from '@/locales';
import { useRouterPush } from '@/hooks/common/router';
import { $t } from '@/locales';
defineOptions({ name: 'ExceptionBase' });

View File

@ -1,7 +1,7 @@
import { computed } from 'vue';
import { useCountDown, useLoading } from '@sa/hooks';
import { $t } from '@/locales';
import { REG_PHONE } from '@/constants/reg';
import { $t } from '@/locales';
export function useCaptcha() {
const { loading, startLoading, endLoading } = useLoading();

View File

@ -1,4 +1,5 @@
import { computed, effectScope, nextTick, onScopeDispose, ref, watch } from 'vue';
import { useElementSize } from '@vueuse/core';
import * as echarts from 'echarts/core';
import { BarChart, GaugeChart, LineChart, PictorialBarChart, PieChart, RadarChart, ScatterChart } from 'echarts/charts';
import type {
@ -29,7 +30,6 @@ import type {
} from 'echarts/components';
import { LabelLayout, UniversalTransition } from 'echarts/features';
import { CanvasRenderer } from 'echarts/renderers';
import { useElementSize } from '@vueuse/core';
import { useThemeStore } from '@/store/modules/theme';
export type ECOption = echarts.ComposeOption<

View File

@ -18,12 +18,7 @@ export function useRouterPush(inSetup = true) {
const routerBack = router.back;
interface RouterPushOptions {
query?: Record<string, string>;
params?: Record<string, string>;
}
async function routerPushByKey(key: RouteKey, options?: RouterPushOptions) {
async function routerPushByKey(key: RouteKey, options?: App.Global.RouterPushOptions) {
const { query, params } = options || {};
const routeLocation: RouteLocationRaw = {
@ -67,7 +62,7 @@ export function useRouterPush(inSetup = true) {
async function toLogin(loginModule?: UnionKey.LoginModule, redirectUrl?: string) {
const module = loginModule || 'pwd-login';
const options: RouterPushOptions = {
const options: App.Global.RouterPushOptions = {
params: {
module
}

View File

@ -67,7 +67,7 @@ export function useTable<A extends NaiveUI.TableApiFn>(config: NaiveUI.NaiveTabl
if (isTableColumnHasKey(column)) {
checks.push({
key: column.key as string,
title: column.title as string,
title: column.title!,
checked: true
});
} else if (column.type === 'selection') {

View File

@ -1,8 +1,8 @@
<script setup lang="ts">
import { useFullscreen } from '@vueuse/core';
import { GLOBAL_HEADER_MENU_ID } from '@/constants/app';
import { useAppStore } from '@/store/modules/app';
import { useThemeStore } from '@/store/modules/theme';
import { GLOBAL_HEADER_MENU_ID } from '@/constants/app';
import GlobalLogo from '../global-logo/index.vue';
import GlobalBreadcrumb from '../global-breadcrumb/index.vue';
import GlobalSearch from '../global-search/index.vue';

View File

@ -2,11 +2,11 @@
import { computed, ref, watch } from 'vue';
import { useRoute } from 'vue-router';
import { SimpleScrollbar } from '@sa/materials';
import { GLOBAL_SIDER_MENU_ID } from '@/constants/app';
import { useAppStore } from '@/store/modules/app';
import { useThemeStore } from '@/store/modules/theme';
import { useRouteStore } from '@/store/modules/route';
import { useRouterPush } from '@/hooks/common/router';
import { GLOBAL_SIDER_MENU_ID } from '@/constants/app';
import { useMenu } from '../../../context';
defineOptions({

View File

@ -3,12 +3,12 @@ import { computed, ref, watch } from 'vue';
import { useRoute } from 'vue-router';
import { SimpleScrollbar } from '@sa/materials';
import { useBoolean } from '@sa/hooks';
import { GLOBAL_SIDER_MENU_ID } from '@/constants/app';
import { useAppStore } from '@/store/modules/app';
import { useThemeStore } from '@/store/modules/theme';
import { useRouteStore } from '@/store/modules/route';
import { useRouterPush } from '@/hooks/common/router';
import { $t } from '@/locales';
import { GLOBAL_SIDER_MENU_ID } from '@/constants/app';
import { useMenu, useMixMenuContext } from '../../../context';
import FirstLevelMenu from '../components/first-level-menu.vue';
import GlobalLogo from '../../global-logo/index.vue';

View File

@ -1,8 +1,8 @@
<script setup lang="ts">
import { computed } from 'vue';
import { GLOBAL_SIDER_MENU_ID } from '@/constants/app';
import { useAppStore } from '@/store/modules/app';
import { useThemeStore } from '@/store/modules/theme';
import { GLOBAL_SIDER_MENU_ID } from '@/constants/app';
import GlobalLogo from '../global-logo/index.vue';
defineOptions({

View File

@ -1,9 +1,9 @@
<script setup lang="ts">
import { computed } from 'vue';
import type { VNode } from 'vue';
import { $t } from '@/locales';
import { useTabStore } from '@/store/modules/tab';
import { useSvgIcon } from '@/hooks/common/icon';
import { $t } from '@/locales';
defineOptions({
name: 'ContextMenu'

View File

@ -3,12 +3,12 @@ import { nextTick, reactive, ref, watch } from 'vue';
import { useRoute } from 'vue-router';
import { useElementBounding } from '@vueuse/core';
import { PageTab } from '@sa/materials';
import BetterScroll from '@/components/custom/better-scroll.vue';
import { useAppStore } from '@/store/modules/app';
import { useThemeStore } from '@/store/modules/theme';
import { useRouteStore } from '@/store/modules/route';
import { useTabStore } from '@/store/modules/tab';
import { isPC } from '@/utils/agent';
import BetterScroll from '@/components/custom/better-scroll.vue';
import ContextMenu from './context-menu.vue';
defineOptions({
@ -114,7 +114,7 @@ function setDropdown(config: Partial<DropdownConfig>) {
let isClickContextMenu = false;
function handleDropdownVisible(visible: boolean) {
function handleDropdownVisible(visible: boolean | undefined) {
if (!isClickContextMenu) {
setDropdown({ visible });
}

View File

@ -1,8 +1,8 @@
<script setup lang="ts">
import { computed, onMounted, ref } from 'vue';
import Clipboard from 'clipboard';
import { $t } from '@/locales';
import { useThemeStore } from '@/store/modules/theme';
import { $t } from '@/locales';
defineOptions({
name: 'ConfigOperation'

View File

@ -1,14 +1,14 @@
<script setup lang="ts">
import { computed } from 'vue';
import { $t } from '@/locales';
import { useThemeStore } from '@/store/modules/theme';
import {
resetCacheStrategyOptions,
themePageAnimationModeOptions,
themeScrollModeOptions,
themeTabModeOptions
} from '@/constants/app';
import { useThemeStore } from '@/store/modules/theme';
import { translateOptions } from '@/utils/common';
import { $t } from '@/locales';
import SettingItem from '../components/setting-item.vue';
defineOptions({

View File

@ -179,7 +179,9 @@ const local: App.I18n.Schema = {
system_post: 'Post Management',
monitor: 'Monitor Management',
'monitor_login-infor': 'Login Log',
'monitor_oper-log': 'Operate Log'
'monitor_oper-log': 'Operate Log',
system_client: 'Client Management',
system_notice: 'Notice Management'
},
page: {
login: {

View File

@ -179,7 +179,9 @@ const local: App.I18n.Schema = {
system_post: '岗位管理',
monitor: '系统监控',
'monitor_login-infor': '登录日志',
'monitor_oper-log': '操作日志'
'monitor_oper-log': '操作日志',
system_client: '客户端管理',
system_notice: '通知公告'
},
page: {
login: {

View File

@ -1,4 +1,4 @@
import { addAPIProvider, disableCache } from '@iconify/vue';
import { addAPIProvider } from '@iconify/vue';
/** Setup the iconify offline */
export function setupIconifyOffline() {
@ -6,7 +6,5 @@ export function setupIconifyOffline() {
if (VITE_ICONIFY_URL) {
addAPIProvider('', { resources: [VITE_ICONIFY_URL] });
disableCache('all');
}
}

View File

@ -1,21 +1,43 @@
// @unocss-include
import { getRgb } from '@sa/color';
import { $t } from '@/locales';
import { DARK_CLASS } from '@/constants/app';
import { localStg } from '@/utils/storage';
import SystemLogo from '@/assets/imgs/logo.png';
import { toggleHtmlClass } from '@/utils/common';
import systemLogo from '@/assets/imgs/logo.png';
import { $t } from '@/locales';
export function setupLoading() {
const themeColor = localStg.get('themeColor') || '#2080f0';
const darkMode = localStg.get('darkMode') || false;
const { r, g, b } = getRgb(themeColor);
const primaryColor = `--primary-color: ${r} ${g} ${b}`;
if (darkMode) {
toggleHtmlClass(DARK_CLASS).add();
}
const loadingClasses = [
'left-0 top-0',
'left-0 bottom-0 animate-delay-500',
'right-0 top-0 animate-delay-1000',
'right-0 bottom-0 animate-delay-1500'
];
const logoWithClass = systemLogo.replace('<svg', `<svg class="size-128px text-primary"`);
const dot = loadingClasses
.map(item => {
return `<div class="absolute w-16px h-16px bg-primary rounded-8px animate-pulse ${item}"></div>`;
})
.join('\n');
const loading = `
<div class="fixed-center flex-col" style="${primaryColor}">
<div class="fixed-center flex-col bg-layout" style="${primaryColor}">
${logoWithClass}
<div class="w-120px h-120px my-36px">
<div class="relative h-full animate-spin">
<img src="${SystemLogo}" width="120" />
${dot}
</div>
</div>
<h2 class="text-28px font-500 text-#646464">${$t('system.title')}</h2>

View File

@ -131,18 +131,7 @@ export const generatedRoutes: GeneratedRoute[] = [
meta: {
title: 'system_config',
i18nKey: 'route.system_config'
},
children: [
{
name: 'system_config_notice',
path: '/system/config/notice',
component: 'view.system_config_notice',
meta: {
title: 'system_config_notice',
i18nKey: 'route.system_config_notice'
}
}
]
},
{
name: 'system_dept',

View File

@ -6,10 +6,10 @@ import type {
Router
} from 'vue-router';
import type { RouteKey, RoutePath } from '@elegant-router/types';
import { getRouteName } from '@/router/elegant/transform';
import { useAuthStore } from '@/store/modules/auth';
import { useRouteStore } from '@/store/modules/route';
import { localStg } from '@/utils/storage';
import { getRouteName } from '@/router/elegant/transform';
/**
* create route guard

View File

@ -1,5 +1,5 @@
import { useTitle } from '@vueuse/core';
import type { Router } from 'vue-router';
import { useTitle } from '@vueuse/core';
import { $t } from '@/locales';
export function createDocumentTitleGuard(router: Router) {

View File

@ -9,24 +9,6 @@ export function fetchGetLoginInforList(params?: Api.Monitor.LoginInforSearchPara
});
}
/** 新增系统访问记录 */
export function fetchCreateLoginInfor(data: Api.Monitor.LoginInforOperateParams) {
return request<boolean>({
url: '/monitor/logininfor',
method: 'post',
data
});
}
/** 修改系统访问记录 */
export function fetchUpdateLoginInfor(data: Api.Monitor.LoginInforOperateParams) {
return request<boolean>({
url: '/monitor/logininfor',
method: 'put',
data
});
}
/** 批量删除系统访问记录 */
export function fetchBatchDeleteLoginInfor(infoIds: CommonType.IdType[]) {
return request<boolean>({

View File

@ -1,12 +1,12 @@
import { effectScope, nextTick, onScopeDispose, ref, watch } from 'vue';
import { defineStore } from 'pinia';
import { breakpointsTailwind, useBreakpoints, useEventListener, useTitle } from '@vueuse/core';
import { defineStore } from 'pinia';
import { useBoolean } from '@sa/hooks';
import { SetupStoreId } from '@/enum';
import { router } from '@/router';
import { localStg } from '@/utils/storage';
import { SetupStoreId } from '@/enum';
import { $t, setLocale } from '@/locales';
import { setDayjsLocale } from '@/locales/dayjs';
import { localStg } from '@/utils/storage';
import { useRouteStore } from '../route';
import { useTabStore } from '../tab';
import { useThemeStore } from '../theme';

View File

@ -2,10 +2,10 @@ import { computed, reactive, ref } from 'vue';
import { useRoute } from 'vue-router';
import { defineStore } from 'pinia';
import { useLoading } from '@sa/hooks';
import { SetupStoreId } from '@/enum';
import { useRouterPush } from '@/hooks/common/router';
import { fetchGetUserInfo, fetchLogin, fetchLogout } from '@/service/api';
import { useRouterPush } from '@/hooks/common/router';
import { localStg } from '@/utils/storage';
import { SetupStoreId } from '@/enum';
import { $t } from '@/locales';
import { useRouteStore } from '../route';
import { useTabStore } from '../tab';

View File

@ -3,13 +3,13 @@ import type { RouteRecordRaw } from 'vue-router';
import { defineStore } from 'pinia';
import { useBoolean } from '@sa/hooks';
import type { CustomRoute, ElegantConstRoute, LastLevelRouteKey, RouteKey, RouteMap } from '@elegant-router/types';
import { SetupStoreId } from '@/enum';
import { router } from '@/router';
import { fetchGetRoutes } from '@/service/api';
import { humpToLine } from '@/utils/common';
import { SetupStoreId } from '@/enum';
import { createDynamicRoutes, createStaticRoutes, getAuthVueRoutes } from '@/router/routes';
import { ROOT_ROUTE } from '@/router/routes/builtin';
import { getRouteName, getRoutePath } from '@/router/elegant/transform';
import { fetchGetRoutes } from '@/service/api';
import { humpToLine } from '@/utils/common';
import { useAuthStore } from '../auth';
import { useTabStore } from '../tab';
import {

View File

@ -1,7 +1,7 @@
import type { RouteLocationNormalizedLoaded, RouteRecordRaw, _RouteRecordBase } from 'vue-router';
import type { ElegantConstRoute, LastLevelRouteKey, RouteKey, RouteMap } from '@elegant-router/types';
import { $t } from '@/locales';
import { useSvgIcon } from '@/hooks/common/icon';
import { $t } from '@/locales';
/**
* Filter auth routes by roles

View File

@ -1,16 +1,15 @@
import { computed, ref } from 'vue';
import { defineStore } from 'pinia';
import { useEventListener } from '@vueuse/core';
import { defineStore } from 'pinia';
import type { RouteKey } from '@elegant-router/types';
import { router } from '@/router';
import { SetupStoreId } from '@/enum';
import { useRouteStore } from '@/store/modules/route';
import { useRouterPush } from '@/hooks/common/router';
import { localStg } from '@/utils/storage';
import { useRouteStore } from '@/store/modules/route';
import { SetupStoreId } from '@/enum';
import { useThemeStore } from '../theme';
import {
extractTabsByAllRoutes,
filterTabsById,
filterTabsByIds,
findTabByRouteName,
getAllTabs,
@ -96,23 +95,15 @@ export const useTabStore = defineStore(SetupStoreId.Tab, () => {
* @param tabId Tab id
*/
async function removeTab(tabId: string) {
const removeTabIndex = tabs.value.findIndex(tab => tab.id === tabId);
if (removeTabIndex === -1) return;
const isRemoveActiveTab = activeTabId.value === tabId;
const updatedTabs = filterTabsById(tabId, tabs.value);
const nextTab = tabs.value[removeTabIndex + 1] || homeTab.value;
function update() {
tabs.value = updatedTabs;
}
if (!isRemoveActiveTab) {
update();
return;
}
const activeTab = updatedTabs.at(-1) || homeTab.value;
if (activeTab) {
await switchRouteByTab(activeTab);
update();
tabs.value.splice(removeTabIndex, 1);
if (isRemoveActiveTab && nextTab) {
await switchRouteByTab(nextTab);
}
}
@ -160,6 +151,25 @@ export const useTabStore = defineStore(SetupStoreId.Tab, () => {
update();
}
const { routerPushByKey } = useRouterPush();
/**
* Replace tab
*
* @param key Route key
* @param options Router push options
*/
async function replaceTab(key: RouteKey, options?: App.Global.RouterPushOptions) {
const oldTabId = activeTabId.value;
// push new route
await routerPushByKey(key, options);
// remove old tab (exclude fixed tab)
if (!isTabRetain(oldTabId)) {
await removeTab(oldTabId);
}
}
/**
* Switch route by tab
*
@ -282,6 +292,7 @@ export const useTabStore = defineStore(SetupStoreId.Tab, () => {
removeTab,
removeActiveTab,
removeTabByRouteName,
replaceTab,
clearTabs,
clearLeftTabs,
clearRightTabs,

View File

@ -1,10 +1,10 @@
import { computed, effectScope, onScopeDispose, ref, toRefs, watch } from 'vue';
import type { Ref } from 'vue';
import { defineStore } from 'pinia';
import { useEventListener, usePreferredColorScheme } from '@vueuse/core';
import { defineStore } from 'pinia';
import { getPaletteColorByNumber } from '@sa/color';
import { SetupStoreId } from '@/enum';
import { localStg } from '@/utils/storage';
import { SetupStoreId } from '@/enum';
import {
addThemeVarsToGlobal,
createThemeToken,

View File

@ -1,11 +1,11 @@
import type { GlobalThemeOverrides } from 'naive-ui';
import { defu } from 'defu';
import { addColorAlpha, getColorPalette, getPaletteColorByNumber, getRgb } from '@sa/color';
import { overrideThemeSettings, themeSettings } from '@/theme/settings';
import { themeVars } from '@/theme/vars';
import { DARK_CLASS } from '@/constants/app';
import { toggleHtmlClass } from '@/utils/common';
import { localStg } from '@/utils/storage';
import { DARK_CLASS } from '@/constants/app';
import { overrideThemeSettings, themeSettings } from '@/theme/settings';
import { themeVars } from '@/theme/vars';
/** Init theme settings */
export function initThemeSettings() {

View File

@ -113,7 +113,8 @@ code,
kbd,
samp,
pre {
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace; /* 1 */
font-family:
ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace; /* 1 */
font-size: 1em; /* 2 */
}

View File

@ -175,6 +175,12 @@ declare namespace App {
type RoutePath = import('@elegant-router/types').RoutePath;
type LastLevelRouteKey = import('@elegant-router/types').LastLevelRouteKey;
/** The router push options */
type RouterPushOptions = {
query?: Record<string, string>;
params?: Record<string, string>;
};
/** The global header props */
interface HeaderProps {
/** Whether to show the logo */

View File

@ -2,6 +2,7 @@
// @ts-nocheck
// Generated by unplugin-vue-components
// Read more: https://github.com/vuejs/core/pull/3399
// biome-ignore lint: disable
export {}
/* prettier-ignore */

View File

@ -8,6 +8,7 @@ declare namespace Env {
type RouterHistoryMode = 'hash' | 'history' | 'memory';
/** Interface for import.meta */
// eslint-disable-next-line @typescript-eslint/no-shadow
interface ImportMeta extends ImportMetaEnv {
/** The base url of the application */
readonly VITE_BASE_URL: string;
@ -105,6 +106,10 @@ declare namespace Env {
readonly VITE_STORAGE_PREFIX?: string;
/** Whether to automatically detect updates after configuring application packaging */
readonly VITE_AUTOMATICALLY_DETECT_UPDATE?: CommonType.YesOrNo;
/** show proxy url log in terminal */
readonly VITE_PROXY_LOG?: CommonType.YesOrNo;
/** The launch editor */
readonly VITE_DEVTOOLS_LAUNCH_EDITOR?: import('vite-plugin-vue-devtools').VitePluginVueDevToolsOptions['launchEditor'];
readonly VITE_APP_CLIENT_ID?: string;
readonly VITE_APP_ENCRYPT?: CommonType.YesOrNo;
readonly VITE_APP_RSA_PUBLIC_KEY?: string;

View File

@ -2,10 +2,10 @@
import { computed } from 'vue';
import type { Component } from 'vue';
import { getPaletteColorByNumber, mixColor } from '@sa/color';
import { $t } from '@/locales';
import { loginModuleRecord } from '@/constants/app';
import { useAppStore } from '@/store/modules/app';
import { useThemeStore } from '@/store/modules/theme';
import { loginModuleRecord } from '@/constants/app';
import { $t } from '@/locales';
import PwdLogin from './modules/pwd-login.vue';
import CodeLogin from './modules/code-login.vue';
import Register from './modules/register.vue';

View File

@ -1,9 +1,9 @@
<script setup lang="ts">
import { computed, reactive } from 'vue';
import { $t } from '@/locales';
import { useRouterPush } from '@/hooks/common/router';
import { useFormRules, useNaiveForm } from '@/hooks/common/form';
import { useCaptcha } from '@/hooks/business/captcha';
import { $t } from '@/locales';
defineOptions({
name: 'CodeLogin'

View File

@ -1,9 +1,9 @@
<script setup lang="ts">
import { computed, reactive } from 'vue';
import { $t } from '@/locales';
import { useRouterPush } from '@/hooks/common/router';
import { useFormRules, useNaiveForm } from '@/hooks/common/form';
import { useCaptcha } from '@/hooks/business/captcha';
import { $t } from '@/locales';
defineOptions({
name: 'Register'

View File

@ -1,8 +1,8 @@
<script setup lang="ts">
import { computed, reactive } from 'vue';
import { $t } from '@/locales';
import { useRouterPush } from '@/hooks/common/router';
import { useFormRules, useNaiveForm } from '@/hooks/common/form';
import { $t } from '@/locales';
defineOptions({
name: 'ResetPwd'

View File

@ -1,8 +1,8 @@
<script setup lang="ts">
import { computed } from 'vue';
import { $t } from '@/locales';
import { useAppStore } from '@/store/modules/app';
import { useAuthStore } from '@/store/modules/auth';
import { $t } from '@/locales';
defineOptions({
name: 'HeaderBanner'

View File

@ -1,8 +1,8 @@
<script setup lang="ts">
import { watch } from 'vue';
import { $t } from '@/locales';
import { useAppStore } from '@/store/modules/app';
import { useEcharts } from '@/hooks/common/echarts';
import { $t } from '@/locales';
defineOptions({
name: 'LineChart'

View File

@ -1,8 +1,8 @@
<script setup lang="ts">
import { watch } from 'vue';
import { $t } from '@/locales';
import { useAppStore } from '@/store/modules/app';
import { useEcharts } from '@/hooks/common/echarts';
import { $t } from '@/locales';
defineOptions({
name: 'PieChart'

View File

@ -1,17 +1,18 @@
<script setup lang="tsx">
import { NButton } from 'naive-ui';
import { fetchBatchDeleteLoginInfor, fetchGetLoginInforList } from '@/service/api/monitor/login-infor';
import { $t } from '@/locales';
import { useAuth } from '@/hooks/business/auth';
import { useAppStore } from '@/store/modules/app';
import { useAuth } from '@/hooks/business/auth';
import { useDownload } from '@/hooks/business/download';
import { useTable, useTableOperate } from '@/hooks/common/table';
import { useDict } from '@/hooks/business/dict';
import { getBrowserIcon, getOsIcon } from '@/utils/format';
import DictTag from '@/components/custom/dict-tag.vue';
import SvgIcon from '@/components/custom/svg-icon.vue';
import { getBrowserIcon, getOsIcon } from '@/utils/format';
import { $t } from '@/locales';
import LoginInforSearch from './modules/login-infor-search.vue';
import LoginInforViewDrawer from './modules/login-infor-view-drawer.vue';
defineOptions({
name: 'LoginInforList'
});

View File

@ -1,7 +1,8 @@
<script setup lang="ts">
import { $t } from '@/locales';
import { useNaiveForm } from '@/hooks/common/form';
import { useDict } from '@/hooks/business/dict';
import { $t } from '@/locales';
defineOptions({
name: 'LoginInforSearch'
});

View File

@ -1,7 +1,7 @@
<script setup lang="ts">
import { $t } from '@/locales';
import { useDict } from '@/hooks/business/dict';
import { getBrowserIcon, getOsIcon } from '@/utils/format';
import { $t } from '@/locales';
defineOptions({
name: 'LoginInforViewDrawer'
});

View File

@ -1,15 +1,16 @@
<script setup lang="tsx">
import { NButton } from 'naive-ui';
import { fetchBatchDeleteOperLog, fetchCleanOperLog, fetchGetOperLogList } from '@/service/api/monitor/oper-log';
import { $t } from '@/locales';
import { useAuth } from '@/hooks/business/auth';
import { useAppStore } from '@/store/modules/app';
import { useAuth } from '@/hooks/business/auth';
import { useDownload } from '@/hooks/business/download';
import { useTable, useTableOperate } from '@/hooks/common/table';
import DictTag from '@/components/custom/dict-tag.vue';
import { useDict } from '@/hooks/business/dict';
import DictTag from '@/components/custom/dict-tag.vue';
import { $t } from '@/locales';
import OperLogViewDrawer from './modules/oper-log-view-drawer.vue';
import OperLogSearch from './modules/oper-log-search.vue';
defineOptions({
name: 'OperLogList'
});

View File

@ -1,7 +1,8 @@
<script setup lang="ts">
import { $t } from '@/locales';
import { useNaiveForm } from '@/hooks/common/form';
import { useDict } from '@/hooks/business/dict';
import { $t } from '@/locales';
defineOptions({
name: 'OperLogSearch'
});

View File

@ -1,8 +1,9 @@
<script setup lang="tsx">
import { NDescriptions, NDescriptionsItem, NTag } from 'naive-ui';
import { getRequestMethodTagType } from '@/utils/format';
import { $t } from '@/locales';
import DictTag from '@/components/custom/dict-tag.vue';
import { getRequestMethodTagType } from '@/utils/format';
defineOptions({
name: 'OperLogViewDrawer'
});

View File

@ -1,7 +1,7 @@
import { defineConfig } from '@unocss/vite';
import transformerDirectives from '@unocss/transformer-directives';
import transformerVariantGroup from '@unocss/transformer-variant-group';
import presetUno from '@unocss/preset-uno';
import presetWind3 from '@unocss/preset-wind3';
import type { Theme } from '@unocss/preset-uno';
import { presetSoybeanAdmin } from '@sa/uno-preset';
import { themeVars } from './src/theme/vars';
@ -26,5 +26,5 @@ export default defineConfig<Theme>({
'card-wrapper': 'rd-8px shadow-sm'
},
transformers: [transformerDirectives(), transformerVariantGroup()],
presets: [presetUno({ dark: 'class' }), presetSoybeanAdmin()]
presets: [presetWind3({ dark: 'class' }), presetSoybeanAdmin()]
});