Compare commits
42 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
c0066b22b0 | ||
|
aaef0bec27 | ||
|
912c3531c5 | ||
|
488e6e3204 | ||
|
f73e3f648d | ||
|
36e5feac98 | ||
|
cc13fcc8aa | ||
|
7f748f2a61 | ||
|
4a6fec8af0 | ||
|
e2b320ad27 | ||
|
21d5214247 | ||
|
44b544745d | ||
|
5499a559c8 | ||
|
ebe2c56348 | ||
|
8debfe7e95 | ||
|
1ef1b6bda9 | ||
|
fb46d7ec7c | ||
|
cea600f12c | ||
|
bf2f617255 | ||
|
cf8c7cb258 | ||
|
4e87f0b665 | ||
|
d8baba586b | ||
|
3cff2eb4ce | ||
|
f355a698ad | ||
|
c3d0b74c75 | ||
|
b0f98e4bfa | ||
|
506ffb8adf | ||
|
e1afc10b80 | ||
|
960b436c79 | ||
|
6059891556 | ||
|
3503dff663 | ||
|
61998886ac | ||
|
608d7fb34d | ||
|
6bb6d9f71e | ||
|
918894147a | ||
|
0b5afda287 | ||
|
a8a6ed97b9 | ||
|
919376b77c | ||
|
7e505f9b96 | ||
|
de517be613 | ||
|
bd5dd2cf28 | ||
|
da521b35e6 |
@@ -4,22 +4,13 @@ type ServiceEnv = Record<ServiceEnvType, ServiceEnvConfig>;
|
||||
/** 不同请求服务的环境配置 */
|
||||
const serviceEnv: ServiceEnv = {
|
||||
dev: {
|
||||
url: 'http://localhost:8080',
|
||||
urlPattern: '/url-pattern',
|
||||
secondUrl: 'http://localhost:8081',
|
||||
secondUrlPattern: '/second-url-pattern'
|
||||
url: 'http://localhost:8080'
|
||||
},
|
||||
test: {
|
||||
url: 'http://localhost:8080',
|
||||
urlPattern: '/url-pattern',
|
||||
secondUrl: 'http://localhost:8081',
|
||||
secondUrlPattern: '/second-url-pattern'
|
||||
url: 'http://localhost:8080'
|
||||
},
|
||||
prod: {
|
||||
url: 'http://localhost:8080',
|
||||
urlPattern: '/url-pattern',
|
||||
secondUrl: 'http://localhost:8081',
|
||||
secondUrlPattern: '/second-url-pattern'
|
||||
url: 'http://localhost:8080'
|
||||
}
|
||||
};
|
||||
|
||||
@@ -27,10 +18,13 @@ const serviceEnv: ServiceEnv = {
|
||||
* 获取当前环境模式下的请求服务的配置
|
||||
* @param env 环境
|
||||
*/
|
||||
export function getServiceEnvConfig(env: ImportMetaEnv) {
|
||||
export function getServiceEnvConfig(env: ImportMetaEnv): ServiceEnvConfigWithProxyPattern {
|
||||
const { VITE_SERVICE_ENV = 'dev' } = env;
|
||||
|
||||
const config = serviceEnv[VITE_SERVICE_ENV];
|
||||
|
||||
return config;
|
||||
return {
|
||||
...config,
|
||||
proxyPattern: '/proxy-pattern'
|
||||
};
|
||||
}
|
||||
|
@@ -1,3 +1,4 @@
|
||||
!.env-config.ts
|
||||
components.d.ts
|
||||
router-page.d.ts
|
||||
*.svg
|
||||
|
18
.eslintrc.js
@@ -1,11 +1,17 @@
|
||||
module.exports = {
|
||||
extends: ['soybeanjs-vue'],
|
||||
extends: ['soybeanjs/vue'],
|
||||
overrides: [
|
||||
{
|
||||
files: ['./scripts/*.ts'],
|
||||
rules: {
|
||||
'no-unused-expressions': 'off'
|
||||
}
|
||||
},
|
||||
{
|
||||
files: ['*.vue'],
|
||||
rules: {
|
||||
'no-undef': 'off' // use tsc to check the ts code of the vue
|
||||
}
|
||||
}
|
||||
],
|
||||
settings: {
|
||||
@@ -38,6 +44,11 @@ module.exports = {
|
||||
group: 'external',
|
||||
position: 'before'
|
||||
},
|
||||
{
|
||||
pattern: '@/constants',
|
||||
group: 'internal',
|
||||
position: 'before'
|
||||
},
|
||||
{
|
||||
pattern: '@/config',
|
||||
group: 'internal',
|
||||
@@ -48,11 +59,6 @@ module.exports = {
|
||||
group: 'internal',
|
||||
position: 'before'
|
||||
},
|
||||
{
|
||||
pattern: '@/enum',
|
||||
group: 'internal',
|
||||
position: 'before'
|
||||
},
|
||||
{
|
||||
pattern: '@/plugins',
|
||||
group: 'internal',
|
||||
|
90
.github/ISSUE_TEMPLATE/bug-report.yaml
vendored
Normal file
@@ -0,0 +1,90 @@
|
||||
name: Bug提交
|
||||
description: 在使用软件或功能的过程中遇到了错误
|
||||
title: '[Bug]: '
|
||||
labels: [ "bug?" ]
|
||||
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
## 请按照以下要求进行提交
|
||||
### 1. 提交后需要指定标签和截止时间。
|
||||
---
|
||||
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
## 环境信息
|
||||
请根据实际使用环境修改以下信息。
|
||||
|
||||
- type: input
|
||||
id: env-program-ver
|
||||
attributes:
|
||||
label: 软件版本
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: dropdown
|
||||
id: env-vm-ver
|
||||
attributes:
|
||||
label: 运行环境
|
||||
description: 选择运行软件的系统版本
|
||||
options:
|
||||
- Windows (64)
|
||||
- Windows (32/x84)
|
||||
- MacOS
|
||||
- Linux
|
||||
- Ubuntu
|
||||
- CentOS
|
||||
- ArchLinux
|
||||
- UNIX (Android)
|
||||
- 其它(请在下方说明)
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: dropdown
|
||||
id: env-vm-arch
|
||||
attributes:
|
||||
label: 运行架构
|
||||
description: (可选) 选择运行软件的系统架构
|
||||
options:
|
||||
- AMD64
|
||||
- x86
|
||||
- ARM [32] (别名:AArch32 / ARMv7)
|
||||
- ARM [64] (别名:AArch64 / ARMv8)
|
||||
- 其它
|
||||
|
||||
- type: textarea
|
||||
id: reproduce-steps
|
||||
attributes:
|
||||
label: 重现步骤
|
||||
description: |
|
||||
我们需要执行哪些操作才能让 bug 出现?
|
||||
简洁清晰的重现步骤能够帮助我们更迅速地定位问题所在。
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: expected
|
||||
attributes:
|
||||
label: 期望的结果是什么?
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: actual
|
||||
attributes:
|
||||
label: 实际的结果是什么?
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: logging
|
||||
attributes:
|
||||
label: 日志记录(可选)
|
||||
render: golang
|
||||
|
||||
- type: textarea
|
||||
id: extra-desc
|
||||
attributes:
|
||||
label: 补充说明(可选)
|
11
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
## Pull Request 详情
|
||||
|
||||
请根据实际使用情况修改以下信息。
|
||||
|
||||
## 版本信息
|
||||
|
||||
## 解决了哪些问题
|
||||
|
||||
## 是否关闭了某个 Issue
|
||||
|
||||
Closes #
|
30
.github/workflows/linter.yml
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
---
|
||||
name: Lint Code
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
name: Lint All Code
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Lint Code Base
|
||||
uses: github/super-linter@v4
|
||||
env:
|
||||
VALIDATE_ALL_CODEBASE: false
|
||||
DEFAULT_BRANCH: main
|
||||
# To change branch master or main
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
FILTER_REGEX_EXCLUDE: (docs|.github)
|
||||
VALIDATE_MARKDOWN: false
|
27
.github/workflows/release.yml
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
name: Release
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v*.**"
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
release:
|
||||
name: Build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16.x
|
||||
|
||||
- name: Create github releases
|
||||
run: npx changelogithub
|
||||
env:
|
||||
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
|
6
.vscode/extensions.json
vendored
@@ -8,17 +8,19 @@
|
||||
"eamodio.gitlens",
|
||||
"editorconfig.editorconfig",
|
||||
"esbenp.prettier-vscode",
|
||||
"formulahendry.auto-complete-tag",
|
||||
"formulahendry.auto-close-tag",
|
||||
"formulahendry.auto-complete-tag",
|
||||
"formulahendry.auto-rename-tag",
|
||||
"kisstkondoros.vscode-gutter-preview",
|
||||
"lokalise.i18n-ally",
|
||||
"mariusalchimavicius.json-to-ts",
|
||||
"mhutchie.git-graph",
|
||||
"mikestead.dotenv",
|
||||
"naumovs.color-highlight",
|
||||
"pkief.material-icon-theme",
|
||||
"steoates.autoimport",
|
||||
"sdras.vue-vscode-snippets",
|
||||
"vue.volar",
|
||||
"vue.vscode-typescript-vue-plugin",
|
||||
"whtouche.vscode-js-console-utils",
|
||||
"zhuangtongfa.material-theme"
|
||||
]
|
||||
|
17
.vscode/settings.json
vendored
@@ -9,21 +9,7 @@
|
||||
"strings": true
|
||||
},
|
||||
"editor.tabSize": 2,
|
||||
"eslint.alwaysShowStatus": true,
|
||||
"eslint.validate": [
|
||||
"javascript",
|
||||
"javascriptreact",
|
||||
"typescript",
|
||||
"typescriptreact",
|
||||
"vue",
|
||||
"html",
|
||||
"json",
|
||||
"jsonc",
|
||||
"json5",
|
||||
"yaml",
|
||||
"yml",
|
||||
"markdown"
|
||||
],
|
||||
"eslint.validate": ["javascript", "javascriptreact", "typescript", "typescriptreact", "vue", "json"],
|
||||
"files.associations": {
|
||||
"*.env.*": "dotenv"
|
||||
},
|
||||
@@ -33,7 +19,6 @@
|
||||
"@": "/src",
|
||||
"~@": "/src"
|
||||
},
|
||||
"i18n-ally.localesPaths": ["src/locales", "src/locales/lang"],
|
||||
"material-icon-theme.activeIconPack": "angular",
|
||||
"material-icon-theme.files.associations": {},
|
||||
"material-icon-theme.folders.associations": {
|
||||
|
23
CHANGELOG.md
@@ -2,6 +2,29 @@
|
||||
|
||||
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
||||
|
||||
### [0.9.9](https://github.com/honghuangdc/soybean-admin/compare/v0.9.8...v0.9.9) (2023-03-13)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **hooks:** add useNaiveTable ([cc13fcc](https://github.com/honghuangdc/soybean-admin/commit/cc13fcc8aaaf667902d69350ad0de3cc16c261ab))
|
||||
* **projects:** custom unocss colors support opacity ([488e6e3](https://github.com/honghuangdc/soybean-admin/commit/488e6e32045d995361b898ef3d384dafcb069008))
|
||||
* **projects:** new layout,tab and add update theme settings ([912c353](https://github.com/honghuangdc/soybean-admin/commit/912c3531c5d7a3ab30e15d39bed98ca9b20131ab))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **components:** 修复iconSelect选择器点击事件失效 ([7e505f9](https://github.com/honghuangdc/soybean-admin/commit/7e505f9b96f5380b6c27b4c2ee2ab0698c4eedc4))
|
||||
* **components:** 页面跳转被拦截, 则会出现 tab 页签与页面不一致的问题 ([bd5dd2c](https://github.com/honghuangdc/soybean-admin/commit/bd5dd2cf28a0943721c397d70c53fe3988a4f81a))
|
||||
* **components:** refresh cached routes ([b0f98e4](https://github.com/honghuangdc/soybean-admin/commit/b0f98e4bfac31751dd39a7dec203277db813694b))
|
||||
* **projects:** fix eslint svg cause incorrect icon render ([0b5afda](https://github.com/honghuangdc/soybean-admin/commit/0b5afda287a0eea57daa8d35409297e2cbf6d578))
|
||||
* **projects:** fix github bug-report ([f73e3f6](https://github.com/honghuangdc/soybean-admin/commit/f73e3f648decf5632fe5193e825b1f912c5f6153))
|
||||
* **projects:** fix pwa logo ([bf2f617](https://github.com/honghuangdc/soybean-admin/commit/bf2f6172554337450c4a300b8bdb580d3e25ad45))
|
||||
* **projects:** not only `/login` claim dynamic path scenario , but also others , eg:/user/1 ([6059891](https://github.com/honghuangdc/soybean-admin/commit/60598915561f1bad6ffba0dc102f0a776be52f0d))
|
||||
* **projects:** sortRoutes recursively ([9188941](https://github.com/honghuangdc/soybean-admin/commit/918894147ab739b4592e8c76378246e28c46491a))
|
||||
* **projects:** the length of routes children list should greater than 0 ([e1afc10](https://github.com/honghuangdc/soybean-admin/commit/e1afc10b80243a5d8d270a351a37a0a2d159f167))
|
||||
* **utils:** make AxiosRequestConfig optional for request.handleDelete() ([4a6fec8](https://github.com/honghuangdc/soybean-admin/commit/4a6fec8af0b44b546f81ec41d7a5947371e189b2))
|
||||
|
||||
### [0.9.8](https://github.com/honghuangdc/soybean-admin/compare/v0.9.7...v0.9.8) (2023-01-15)
|
||||
|
||||
|
||||
|
45
README.md
@@ -1,30 +1,31 @@
|
||||
<div align="center">
|
||||
<img src="./public/logo.png" style="width: 240px;"/>
|
||||
<img src="https://soybeanjs-1300612522.cos.ap-guangzhou.myqcloud.com/uPic/soybean.svg" style="width: 160px;"/>
|
||||
<h1>Soybean Admin</h1>
|
||||
</div>
|
||||
|
||||
[](./LICENSE)
|
||||
[](./LICENSE)  
|
||||
|
||||
## 简介
|
||||
|
||||
[Soybean Admin](https://github.com/honghuangdc/soybean-admin) 是一个基于 Vue3、Vite3、TypeScript、NaiveUI、Pinia 和 UnoCSS 的清新优雅的中后台模版,它使用了最新的前端技术栈,内置丰富的主题配置,有着极高的代码规范,基于 mock 实现的动态权限路由,开箱即用的中后台前端解决方案,也可用于学习参考。
|
||||
[Soybean Admin](https://github.com/honghuangdc/soybean-admin) 是一个基于 Vue3、Vite3、TypeScript、NaiveUI、Pinia 和 UnoCSS 的清新优雅的中后台模版,它使用了最新流行的前端技术栈,内置丰富的主题配置,有着极高的代码规范,基于文件的路由系统以及基于 Mock 的动态权限路由,开箱即用的中后台前端解决方案,也可用于学习参考。
|
||||
|
||||
## 特性
|
||||
|
||||
- **最新技术栈**:使用 Vue3/vite2 等前端前沿技术开发, 使用高效率的 npm 包管理器 pnpm
|
||||
- **最新流行技术栈**:使用 Vue3/Vite 等前端前沿技术开发, 使用高效率的 npm 包管理器 pnpm
|
||||
- **TypeScript**: 应用程序级 JavaScript 的语言
|
||||
- **主题**:丰富可配置的主题、暗黑模式,基于原子 css 框架 - UnoCss 的动态主题颜色
|
||||
- **代码规范**:丰富的规范插件及极高的代码规范
|
||||
- **权限路由**:基于文件的路由系统、基于 mock 的动态路由能快速实现后端动态路由
|
||||
- **请求函数**:基于 axios 的完善的请求函数封装,提供 Promise 和 hooks 两种请求函数,加入请求结果数据转换的适配器适配器
|
||||
- **文件路由系统**:基于文件的路由系统,根据页面文件自动生成路由声明、路由导入和路由模块
|
||||
- **权限路由**:提供前端静态和后端动态两种路由模式,基于 mock 的动态路由能快速实现后端动态路由
|
||||
- **请求函数**:基于 axios 的完善的请求函数封装,提供 Promise 和 hooks 两种请求函数,加入请求结果数据转换的适配器
|
||||
|
||||
## 预览
|
||||
## 在线预览
|
||||
|
||||
- [soybean-admin](https://soybean.pro/)
|
||||
- [Soybean Admin 预览地址](https://soybean.pro/)
|
||||
|
||||
## 文档
|
||||
|
||||
- [项目文档: docs.soybean.pro](https://docs.soybean.pro)
|
||||
- [项目文档预览地址](https://docs.soybean.pro)
|
||||
|
||||
## 代码仓库
|
||||
|
||||
@@ -42,7 +43,6 @@
|
||||
## 后端服务
|
||||
|
||||
- [soybean-admin-java](https://github.com/honghuangdc/soybean-admin-java)
|
||||
- [soybean-admin-go](https://github.com/honghuangdc/soybean-admin-go)
|
||||
|
||||
## 项目示例图
|
||||
|
||||
@@ -115,10 +115,13 @@ docker run --name soybean -p 80:80 -d soybeanjs/soybean-admin:v0.9.6
|
||||
|
||||
## Git 贡献提交规范
|
||||
|
||||
项目已经内置 angular 提交规范,直接执行 commit 命令即可。
|
||||
项目已经内置 Angular 提交规范,直接执行 commit 命令即可生成符合 Angular 提交规范的 commit。
|
||||
|
||||
项目已用 simple-git-hooks 代替了 husky, 旧版本用了 husky,执行 pnpm soy init-git-hooks 进行初始化配置
|
||||
|
||||
## 基于 SoybeanAdmin 二次开发的项目
|
||||
[electron-mock-admin](https://github.com/lixin59/electron-mock-api): 一个 Mock Api 管理系统,帮助前端开发伙伴快速实现接口的mock。
|
||||
|
||||
## 浏览器支持
|
||||
|
||||
本地开发推荐使用`Chrome 90+` 浏览器
|
||||
@@ -135,17 +138,17 @@ docker run --name soybean -p 80:80 -d soybeanjs/soybean-admin:v0.9.6
|
||||
|
||||
## 交流
|
||||
|
||||
`Soybean Admin` 是完全开源免费的项目,在帮助开发者更方便地进行中大型管理系统开发,同时也提供微信和 QQ 交流群,使用问题欢迎在群内提问。
|
||||
`Soybean Admin` 是完全开源免费的项目,在帮助开发者更方便地进行中大型管理系统开发,同时也提供微信和 QQ 交流群(人员已满),使用问题欢迎在群内提问。
|
||||
|
||||
- 微信交流群(添加本人微信拉进群),欢迎来技术交流,业务咨询。
|
||||
<div style="text-align:left">
|
||||
<img src="https://s2.loli.net/2022/05/16/3YGBgXnVPJdslk8.jpg" style="width:200px" />
|
||||
</div>
|
||||
|
||||
- QQ 交流群 `711301266`
|
||||
|
||||
<div style="text-align:left">
|
||||
<img src="https://i.loli.net/2021/11/24/1J6REWXiHomU2kM.jpg" style="width:200px" />
|
||||
<div style="display:flex;">
|
||||
<div style="padding-right:24px;">
|
||||
<p>微信交流群</p>
|
||||
<img src="https://soybeanjs-1300612522.cos.ap-guangzhou.myqcloud.com/uPic/soybeanjs-wechat2.jpeg" style="width:200px" />
|
||||
</div>
|
||||
<div>
|
||||
<p>添加本人微信,欢迎来技术交流,业务咨询</p>
|
||||
<img src="https://soybeanjs-1300612522.cos.ap-guangzhou.myqcloud.com/uPic/soybeanjs.jpeg" style="width:180px" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
## 捐赠
|
||||
|
@@ -5,19 +5,14 @@ import type { ProxyOptions } from 'vite';
|
||||
* @param isOpenProxy - 是否开启代理
|
||||
* @param envConfig - env环境配置
|
||||
*/
|
||||
export function createViteProxy(isOpenProxy: boolean, envConfig: ServiceEnvConfig) {
|
||||
export function createViteProxy(isOpenProxy: boolean, envConfig: ServiceEnvConfigWithProxyPattern) {
|
||||
if (!isOpenProxy) return undefined;
|
||||
|
||||
const proxy: Record<string, string | ProxyOptions> = {
|
||||
[envConfig.urlPattern]: {
|
||||
[envConfig.proxyPattern]: {
|
||||
target: envConfig.url,
|
||||
changeOrigin: true,
|
||||
rewrite: path => path.replace(new RegExp(`^${envConfig.urlPattern}`), '')
|
||||
},
|
||||
[envConfig.secondUrlPattern]: {
|
||||
target: envConfig.secondUrl,
|
||||
changeOrigin: true,
|
||||
rewrite: path => path.replace(new RegExp(`^${envConfig.secondUrlPattern}`), '')
|
||||
rewrite: path => path.replace(new RegExp(`^${envConfig.proxyPattern}`), '')
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -21,7 +21,9 @@ export default function unplugin(viteEnv: ImportMetaEnv) {
|
||||
Icons({
|
||||
compiler: 'vue3',
|
||||
customCollections: {
|
||||
[collectionName]: FileSystemIconLoader(localIconPath)
|
||||
[collectionName]: FileSystemIconLoader(localIconPath, svg =>
|
||||
svg.replace(/^<svg\s/, '<svg width="1em" height="1em" ')
|
||||
)
|
||||
},
|
||||
scale: 1,
|
||||
defaultClass: 'inline-block'
|
||||
|
21
changelogithub.config.json
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"types": {
|
||||
"feat": { "title": "🚀 Features" },
|
||||
"perf": { "title": "🔥 Performance" },
|
||||
"fix": { "title": "🩹 Fixes" },
|
||||
"refactor": { "title": "💅 Refactors" },
|
||||
"docs": { "title": "📖 Documentation" },
|
||||
"types": { "title": "🌊 Types" },
|
||||
"chore": { "title": "🏡 Chore" },
|
||||
"test": { "title": "🧪 Tests" },
|
||||
"style": { "title": "🎨 Styles" },
|
||||
"ci": { "title": "🤖 CI" }
|
||||
},
|
||||
"scopeMap": {},
|
||||
"titles": {
|
||||
"breakingChanges": "🚨 Breaking Changes"
|
||||
},
|
||||
"contributors": true,
|
||||
"capitalize": true,
|
||||
"group": true
|
||||
}
|
24
index.html
@@ -1,15 +1,15 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-cmn-Hans">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" href="/logo.png" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title><%= appName %></title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
<div id="appLoading"></div>
|
||||
</div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" href="/favicon.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title><%= appName %></title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
<div id="appLoading"></div>
|
||||
</div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
63
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "soybean-admin",
|
||||
"version": "0.9.8",
|
||||
"version": "0.9.9",
|
||||
"description": "A fresh and elegant admin template, based on Vue3、Vite3、TypeScript、NaiveUI and UnoCSS. 一个基于Vue3、Vite3、TypeScript、NaiveUI and UnoCSS的清新优雅的中后台模版。",
|
||||
"author": {
|
||||
"name": "Soybean",
|
||||
@@ -44,7 +44,8 @@
|
||||
"build:vercel": "cross-env VITE_HASH_ROUTE=Y VITE_VERCEL=Y vite build",
|
||||
"preview": "vite preview",
|
||||
"typecheck": "vue-tsc --noEmit --skipLibCheck",
|
||||
"lint": "eslint . --fix",
|
||||
"lint": "eslint . --fix --ext .js,.jsx,.mjs,.json,.ts,.tsx,.vue",
|
||||
"format": "soy prettier-format",
|
||||
"commit": "soy git-commit",
|
||||
"cleanup": "soy cleanup",
|
||||
"update-pkg": "soy update-pkg",
|
||||
@@ -52,15 +53,16 @@
|
||||
"logo": "tsx ./scripts/logo.ts",
|
||||
"changelog": "conventional-changelog -p angular -i CHANGELOG.md -s",
|
||||
"release": "standard-version",
|
||||
"prepare": "simple-git-hooks"
|
||||
"prepare": "soy init-git-hooks"
|
||||
},
|
||||
"dependencies": {
|
||||
"@antv/data-set": "^0.11.8",
|
||||
"@antv/g2": "^4.2.8",
|
||||
"@antv/g2": "^4.2.9",
|
||||
"@better-scroll/core": "^2.5.0",
|
||||
"@soybeanjs/vue-admin-layout": "^1.1.1",
|
||||
"@soybeanjs/vue-admin-tab": "^1.0.5",
|
||||
"@vueuse/core": "^9.10.0",
|
||||
"@soybeanjs/vue-materials": "^0.1.8",
|
||||
"@vueuse/core": "^9.13.0",
|
||||
"axios": "0.27.2",
|
||||
"clipboard": "^2.0.11",
|
||||
"colord": "^2.9.3",
|
||||
@@ -70,13 +72,13 @@
|
||||
"form-data": "^4.0.0",
|
||||
"lodash-es": "^4.17.21",
|
||||
"naive-ui": "2.34.3",
|
||||
"pinia": "^2.0.28",
|
||||
"pinia": "^2.0.33",
|
||||
"print-js": "^1.6.0",
|
||||
"qs": "^6.11.0",
|
||||
"swiper": "^8.4.5",
|
||||
"ua-parser-js": "^1.0.32",
|
||||
"qs": "^6.11.1",
|
||||
"swiper": "^9.1.0",
|
||||
"ua-parser-js": "^1.0.34",
|
||||
"vditor": "^3.9.0",
|
||||
"vue": "3.2.45",
|
||||
"vue": "3.2.47",
|
||||
"vue-i18n": "^9.2.2",
|
||||
"vue-router": "^4.1.6",
|
||||
"vuedraggable": "^4.1.0",
|
||||
@@ -84,45 +86,44 @@
|
||||
"xgplayer": "^2.32.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@amap/amap-jsapi-types": "^0.0.10",
|
||||
"@iconify/json": "^2.2.7",
|
||||
"@iconify/vue": "^4.0.2",
|
||||
"@soybeanjs/cli": "^0.1.6",
|
||||
"@amap/amap-jsapi-types": "^0.0.13",
|
||||
"@iconify/json": "^2.2.33",
|
||||
"@iconify/vue": "^4.1.0",
|
||||
"@soybeanjs/cli": "^0.1.7",
|
||||
"@soybeanjs/vite-plugin-vue-page-route": "^0.0.5",
|
||||
"@types/bmapgl": "^0.0.5",
|
||||
"@types/crypto-js": "^4.1.1",
|
||||
"@types/node": "18.11.18",
|
||||
"@types/node": "18.15.0",
|
||||
"@types/qs": "^6.9.7",
|
||||
"@types/ua-parser-js": "^0.7.36",
|
||||
"@unocss/preset-uno": "^0.48.4",
|
||||
"@unocss/vite": "^0.48.4",
|
||||
"@unocss/preset-uno": "^0.50.4",
|
||||
"@unocss/transformer-directives": "^0.50.4",
|
||||
"@unocss/vite": "^0.50.4",
|
||||
"@vitejs/plugin-vue": "^4.0.0",
|
||||
"@vitejs/plugin-vue-jsx": "^3.0.0",
|
||||
"conventional-changelog": "^3.1.25",
|
||||
"cross-env": "^7.0.3",
|
||||
"eslint": "^8.32.0",
|
||||
"eslint-config-soybeanjs-vue": "^0.2.2",
|
||||
"eslint": "^8.36.0",
|
||||
"eslint-config-soybeanjs": "^0.3.1",
|
||||
"lint-staged": "12.5.0",
|
||||
"mockjs": "^1.1.0",
|
||||
"node-html-to-image": "^3.2.4",
|
||||
"rollup-plugin-visualizer": "^5.9.0",
|
||||
"sass": "^1.57.1",
|
||||
"sass": "^1.59.2",
|
||||
"simple-git-hooks": "^2.8.1",
|
||||
"standard-version": "^9.5.0",
|
||||
"tsx": "^3.12.2",
|
||||
"typescript": "4.9.4",
|
||||
"unplugin-icons": "^0.15.1",
|
||||
"unplugin-vue-components": "0.22.12",
|
||||
"unplugin-vue-macros": "^1.3.3",
|
||||
"utility-types": "^3.10.0",
|
||||
"vite": "^4.0.4",
|
||||
"tsx": "^3.12.4",
|
||||
"typescript": "4.9.5",
|
||||
"unplugin-icons": "^0.15.3",
|
||||
"unplugin-vue-components": "0.24.1",
|
||||
"unplugin-vue-macros": "1.6.4",
|
||||
"vite": "^4.1.4",
|
||||
"vite-plugin-compression": "^0.5.1",
|
||||
"vite-plugin-html": "^3.2.0",
|
||||
"vite-plugin-mock": "^2.9.6",
|
||||
"vite-plugin-progress": "^0.0.6",
|
||||
"vite-plugin-pwa": "^0.14.1",
|
||||
"vite-plugin-pwa": "^0.14.4",
|
||||
"vite-plugin-svg-icons": "^2.0.1",
|
||||
"vue-tsc": "^1.0.24"
|
||||
"vue-tsc": "^1.2.0"
|
||||
},
|
||||
"pnpm": {
|
||||
"patchedDependencies": {
|
||||
@@ -134,6 +135,6 @@
|
||||
"pre-commit": "pnpm typecheck && pnpm lint-staged"
|
||||
},
|
||||
"lint-staged": {
|
||||
"*": "eslint . --fix"
|
||||
"*.{js,jsx,mjs,json,ts,tsx,vue}": "eslint . --fix"
|
||||
}
|
||||
}
|
||||
|
5123
pnpm-lock.yaml
generated
1
public/favicon.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg viewBox="0 0 160 160" xmlns="http://www.w3.org/2000/svg"><path d="M81.28 55.9c-.1-11.67-2.93-22.55-9.37-32.38-1-1.5-2.14-2.86-2.5-4.71a8.1 8.1 0 014-8.61 7.89 7.89 0 019.3 1.23 35.999 35.999 0 015.9 8.83 75.18 75.18 0 018.44 28.58 83.211 83.211 0 01-5.23 36.74 102.983 102.983 0 01-3 7.28 1.2 1.2 0 000 1.41c9.58 13.3 21.76 23 37.85 27.24a54.37 54.37 0 0019.68 1.57 7.72 7.72 0 018.36 6.9 7.903 7.903 0 01-6.7 9 64.744 64.744 0 01-23-1.33 77.68 77.68 0 01-36.93-19.88 93.628 93.628 0 01-11.91-13.71 2.18 2.18 0 00-2.3-1.06 72.744 72.744 0 00-27.38 7.55c-11.6 6-20.67 14.58-26.4 26.45a10.134 10.134 0 01-3.7 4.7 8 8 0 01-9.19-.7 7.86 7.86 0 01-2.36-9.28 60.324 60.324 0 018.72-14.52c12.2-15.43 28.21-24.59 47.32-28.57A85.085 85.085 0 0173.07 87c.524.015 1-.307 1.18-.8a76.06 76.06 0 006.53-22.3c.351-2.652.518-5.325.5-8z" fill="#1890ff"/><path d="M136.26 108.34a44.742 44.742 0 01-11.13-2.87 46.108 46.108 0 01-19.66-13.76 8 8 0 015.72-13.22 7.93 7.93 0 016.54 2.93 33.27 33.27 0 0018.87 10.75c1.546.155 3.058.553 4.48 1.18a8.08 8.08 0 013.84 9.21c-.92 3.52-4.13 5.81-8.66 5.78zm-80.6-75.02a7.61 7.61 0 016.64 5 49.139 49.139 0 013.64 17 46.33 46.33 0 01-2.46 17.28c-2 5.77-8.24 7.79-12.89 4.15a8.1 8.1 0 01-2.39-9 31.679 31.679 0 001.68-12.36 35.77 35.77 0 00-2.43-11c-2.1-5.45 1.75-11.07 8.21-11.07zm22.26 93.25a8 8 0 01-6.68 7.86 32.88 32.88 0 00-19.7 12.19 8.13 8.13 0 01-11.21 1.62 8 8 0 01-1.41-11.58A51.043 51.043 0 0154 123.81a45.842 45.842 0 0114-5.1c5.35-1.04 9.91 2.56 9.92 7.86z" fill="#1890ff"/></svg>
|
After Width: | Height: | Size: 1.5 KiB |
BIN
public/logo.png
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 23 KiB |
@@ -1,17 +1,12 @@
|
||||
import { readFile } from 'fs/promises';
|
||||
import nodeHtmlToImage from 'node-html-to-image';
|
||||
import { readFile, writeFile } from 'fs/promises';
|
||||
import themeSettings from '../src/settings/theme.json';
|
||||
|
||||
async function generatePngLogoFromSvg(svgPath: string, color: string) {
|
||||
async function updateFavicon(svgPath: string, color: string) {
|
||||
const svgStr = await readFile(svgPath, 'utf-8');
|
||||
|
||||
const svgStrWithColor = svgStr.replace(/currentColor/g, color);
|
||||
|
||||
await nodeHtmlToImage({
|
||||
output: './public/logo.png',
|
||||
html: svgStrWithColor,
|
||||
transparent: true
|
||||
});
|
||||
await writeFile('./public/favicon.svg', svgStrWithColor);
|
||||
}
|
||||
|
||||
generatePngLogoFromSvg('./src/assets/svg-icon/logo.svg', themeSettings.themeColor);
|
||||
updateFavicon('./src/assets/svg-icon/logo.svg', themeSettings.themeColor);
|
||||
|
@@ -1 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" class="feather feather-activity"><polyline points="22 12 18 12 15 21 9 3 6 12 2 12"></polyline></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M22 12h-4l-3 9L9 3l-3 9H2"/></svg>
|
||||
|
Before Width: | Height: | Size: 282 B After Width: | Height: | Size: 202 B |
@@ -1 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" class="feather feather-at-sign"><circle cx="12" cy="12" r="4"></circle><path d="M16 8v5a3 3 0 0 0 6 0v-1a10 10 0 1 0-3.92 7.94"></path></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" class="prefix__prefix__feather prefix__prefix__feather-at-sign"><circle cx="12" cy="12" r="4"/><path d="M16 8v5a3 3 0 006 0v-1a10 10 0 10-3.92 7.94"/></svg>
|
||||
|
Before Width: | Height: | Size: 322 B After Width: | Height: | Size: 315 B |
Before Width: | Height: | Size: 8.6 KiB After Width: | Height: | Size: 6.3 KiB |
@@ -1 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" class="feather feather-cast"><path d="M2 16.1A5 5 0 0 1 5.9 20M2 12.05A9 9 0 0 1 9.95 20M2 8V6a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2h-6"></path><line x1="2" y1="20" x2="2.01" y2="20"></line></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" class="prefix__prefix__feather prefix__prefix__feather-cast"><path d="M2 16.1A5 5 0 015.9 20M2 12.05A9 9 0 019.95 20M2 8V6a2 2 0 012-2h16a2 2 0 012 2v12a2 2 0 01-2 2h-6M2 20h.01"/></svg>
|
||||
|
Before Width: | Height: | Size: 387 B After Width: | Height: | Size: 345 B |
@@ -1 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" class="feather feather-chrome"><circle cx="12" cy="12" r="10"></circle><circle cx="12" cy="12" r="4"></circle><line x1="21.17" y1="8" x2="12" y2="8"></line><line x1="3.95" y1="6.06" x2="8.54" y2="14"></line><line x1="10.88" y1="21.94" x2="15.46" y2="14"></line></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><circle cx="12" cy="12" r="4"/><path d="M21.17 8H12M3.95 6.06L8.54 14m2.34 7.94L15.46 14"/></svg>
|
||||
|
Before Width: | Height: | Size: 448 B After Width: | Height: | Size: 288 B |
@@ -1 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" class="feather feather-copy"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1"/></svg>
|
||||
|
Before Width: | Height: | Size: 351 B After Width: | Height: | Size: 283 B |
@@ -1 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--mdi" width="32" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 24 24"><path fill="currentColor" d="M19 10c0 1.38-2.12 2.5-3.5 2.5s-2.75-1.12-2.75-2.5h-1.5c0 1.38-1.37 2.5-2.75 2.5S5 11.38 5 10h-.75c-.16.64-.25 1.31-.25 2a8 8 0 0 0 8 8a8 8 0 0 0 8-8c0-.69-.09-1.36-.25-2H19m-7-6C9.04 4 6.45 5.61 5.07 8h13.86C17.55 5.61 14.96 4 12 4m10 8a10 10 0 0 1-10 10A10 10 0 0 1 2 12A10 10 0 0 1 12 2a10 10 0 0 1 10 10m-10 5.23c-1.75 0-3.29-.73-4.19-1.81L9.23 14c.45.72 1.52 1.23 2.77 1.23s2.32-.51 2.77-1.23l1.42 1.42c-.9 1.08-2.44 1.81-4.19 1.81Z"></path></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" viewBox="0 0 24 24"><path fill="currentColor" d="M19 10c0 1.38-2.12 2.5-3.5 2.5s-2.75-1.12-2.75-2.5h-1.5c0 1.38-1.37 2.5-2.75 2.5S5 11.38 5 10h-.75c-.16.64-.25 1.31-.25 2a8 8 0 008 8 8 8 0 008-8c0-.69-.09-1.36-.25-2H19m-7-6C9.04 4 6.45 5.61 5.07 8h13.86C17.55 5.61 14.96 4 12 4m10 8a10 10 0 01-10 10A10 10 0 012 12 10 10 0 0112 2a10 10 0 0110 10m-10 5.23c-1.75 0-3.29-.73-4.19-1.81L9.23 14c.45.72 1.52 1.23 2.77 1.23s2.32-.51 2.77-1.23l1.42 1.42c-.9 1.08-2.44 1.81-4.19 1.81z"/></svg>
|
||||
|
Before Width: | Height: | Size: 702 B After Width: | Height: | Size: 544 B |
@@ -1 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" class="feather feather-heart"><path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"></path></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M20.84 4.61a5.5 5.5 0 00-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 00-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 000-7.78z"/></svg>
|
||||
|
Before Width: | Height: | Size: 371 B After Width: | Height: | Size: 309 B |
@@ -1 +1 @@
|
||||
<svg viewBox="0 0 158.88 158.88"><path d="M158.86.3v157.48c0 .9-.2 1.1-1.1 1.1H.24a2.61 2.61 0 01-.11-1.3V1.67C.14 0 0 .18 1.61.18h156a2.62 2.62 0 011.25.12z" fill="currentColor"/><path d="M158.86.3H2C0 .31.27 0 .27 2v156.85c-.07-.05-.25.12-.24-.12s0-.64 0-1Q0 79.46 0 1.14C0 .24.2 0 1.1 0h156.68c.35.08.81-.2 1.08.3z" fill="#fff"/><path d="M93.65 51.52a68.65 68.65 0 01-6.47 28.81 1.72 1.72 0 00.19 2c6.08 8.28 13.58 14.79 23.19 18.69a46.22 46.22 0 0017.15 3.39 28.87 28.87 0 003.34-.25 6.2 6.2 0 017 5.12 6.07 6.07 0 01-5.15 7.14 50.39 50.39 0 01-18.06-1c-15.85-3.66-28-12.75-37.44-25.7a2.15 2.15 0 00-2.23-1.09c-14 1.37-26.17 6.43-35.5 17.21a38.47 38.47 0 00-6.23 9.74 6.21 6.21 0 01-8.17 3.42 6.14 6.14 0 01-3.27-8.2 49.31 49.31 0 019.63-14.62c10.56-11.44 23.8-17.54 39.09-19.54a13.93 13.93 0 012.84-.34c1.61.14 2.18-.73 2.73-2A54.38 54.38 0 0081.12 51a44 44 0 00-8-25 6.11 6.11 0 01-.65-6.46A6 6 0 0177.75 16a6.34 6.34 0 015.66 3 53.61 53.61 0 017.17 14.28 59.33 59.33 0 013.07 18.24z" fill="#fff"/><path d="M46.92 118.63a6 6 0 011.35-3.88 37.89 37.89 0 0122.5-14 6.08 6.08 0 016.65 2.47 6.18 6.18 0 01-3.84 9.63 26.09 26.09 0 00-15.71 9.77 6.2 6.2 0 01-10.95-4zM124.3 92.8a34.66 34.66 0 01-9.82-2.48 35.46 35.46 0 01-14.65-10.45 6.19 6.19 0 012.84-9.93 5.79 5.79 0 016.44 1.73 26.79 26.79 0 0016.51 8.85 6 6 0 015 5.54 6.21 6.21 0 01-4.29 6.46 6.55 6.55 0 01-2.03.28zM69.32 53.27a33.46 33.46 0 01-2.27 12.52 6.21 6.21 0 01-10.94 1 6.09 6.09 0 01-.65-5.4 26 26 0 00-.53-18.25 6.21 6.21 0 0111.49-4.72 40.24 40.24 0 012.9 14.85z" fill="#fff"/></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg"><path d="M0 0h160v160H0V0z" fill="currentColor"/><path d="M94.322 51.888A69.12 69.12 0 0187.806 80.9a1.732 1.732 0 00.191 2.014c6.124 8.338 13.677 14.894 23.356 18.821a46.564 46.564 0 0017.273 3.414 29.101 29.101 0 003.364-.252 6.245 6.245 0 017.051 5.156 6.112 6.112 0 01-5.187 7.19 50.758 50.758 0 01-18.19-1.007c-15.964-3.686-28.2-12.84-37.709-25.88a2.165 2.165 0 00-2.246-1.098c-14.1 1.38-26.357 6.475-35.754 17.331a38.721 38.721 0 00-6.275 9.808 6.255 6.255 0 01-8.229 3.444 6.184 6.184 0 01-3.293-8.258 49.662 49.662 0 019.699-14.722c10.636-11.52 23.97-17.663 39.37-19.677a14.06 14.06 0 012.86-.342c1.622.14 2.197-.735 2.75-2.014a54.752 54.752 0 004.865-23.463 44.302 44.302 0 00-8.057-25.175 6.152 6.152 0 01-.655-6.506 6.043 6.043 0 015.318-3.564 6.386 6.386 0 015.7 3.02 53.98 53.98 0 017.222 14.38 59.734 59.734 0 013.092 18.368z" fill="#fff"/><path d="M47.257 119.468a6.04 6.04 0 011.36-3.907 38.165 38.165 0 0122.66-14.098 6.124 6.124 0 016.699 2.487 6.223 6.223 0 01-3.868 9.698 26.276 26.276 0 00-15.823 9.838 6.245 6.245 0 01-11.028-4.028v.01zm77.935-26.01a34.908 34.908 0 01-9.89-2.498 35.717 35.717 0 01-14.756-10.523 6.233 6.233 0 012.861-10 5.832 5.832 0 016.486 1.742 26.986 26.986 0 0016.628 8.912 6.042 6.042 0 015.036 5.58 6.253 6.253 0 01-4.32 6.504 6.588 6.588 0 01-2.045.282zM69.817 53.65a33.69 33.69 0 01-2.286 12.607 6.255 6.255 0 01-11.018 1.007 6.132 6.132 0 01-.655-5.438 26.178 26.178 0 00-.534-18.377 6.256 6.256 0 0111.572-4.753 40.515 40.515 0 012.921 14.954z" fill="#fff"/></svg>
|
||||
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
@@ -1 +1 @@
|
||||
<svg viewBox="0 0 158.88 158.88"><path d="M0 158.86V1.1C0 .2.2 0 1.1 0h156.68c.9 0 1.1.2 1.1 1.1v156.68c0 .9-.2 1.1-1.1 1.1Q78.9 158.83 0 158.86z" fill="#ffffff00"/><path d="M81.28 55.9c-.1-11.67-2.93-22.55-9.37-32.38-1-1.5-2.14-2.86-2.5-4.71a8.1 8.1 0 014-8.61 7.89 7.89 0 019.3 1.23 36 36 0 015.9 8.83 75.18 75.18 0 018.44 28.58 83.21 83.21 0 01-5.23 36.74 103 103 0 01-3 7.28 1.2 1.2 0 000 1.41c9.58 13.3 21.76 23 37.85 27.24a54.35 54.35 0 0019.68 1.57 7.72 7.72 0 018.36 6.9 7.9 7.9 0 01-6.7 9 64.74 64.74 0 01-23-1.33 77.68 77.68 0 01-36.93-19.88 93.64 93.64 0 01-11.91-13.71 2.18 2.18 0 00-2.3-1.06 72.75 72.75 0 00-27.38 7.55c-11.6 6-20.67 14.58-26.4 26.45a10.13 10.13 0 01-3.7 4.7 8 8 0 01-9.19-.7 7.86 7.86 0 01-2.36-9.28 60.32 60.32 0 018.72-14.52c12.2-15.43 28.21-24.59 47.32-28.57A85.08 85.08 0 0173.07 87a1.22 1.22 0 001.18-.8 76.06 76.06 0 006.53-22.3 57.87 57.87 0 00.5-8z" fill="currentColor"/><path d="M136.26 108.34a44.72 44.72 0 01-11.13-2.87 46.11 46.11 0 01-19.66-13.76 8 8 0 015.72-13.22 7.93 7.93 0 016.54 2.93 33.27 33.27 0 0018.87 10.75 14.76 14.76 0 014.48 1.18 8.08 8.08 0 013.84 9.21c-.92 3.52-4.13 5.81-8.66 5.78zM55.66 33.32a7.61 7.61 0 016.64 5 49.14 49.14 0 013.64 17 46.33 46.33 0 01-2.46 17.28c-2 5.77-8.24 7.79-12.89 4.15a8.1 8.1 0 01-2.39-9 31.68 31.68 0 001.68-12.36 35.77 35.77 0 00-2.43-11c-2.1-5.45 1.75-11.07 8.21-11.07zM77.92 126.57a8 8 0 01-6.68 7.86 32.88 32.88 0 00-19.7 12.19 8.13 8.13 0 01-11.21 1.62 8 8 0 01-1.41-11.58A51.05 51.05 0 0154 123.81a45.85 45.85 0 0114-5.1c5.35-1.04 9.91 2.56 9.92 7.86z" fill="currentColor"/></svg>
|
||||
<svg viewBox="0 0 160 160" xmlns="http://www.w3.org/2000/svg"><path d="M81.28 55.9c-.1-11.67-2.93-22.55-9.37-32.38-1-1.5-2.14-2.86-2.5-4.71a8.1 8.1 0 014-8.61 7.89 7.89 0 019.3 1.23 35.999 35.999 0 015.9 8.83 75.18 75.18 0 018.44 28.58 83.211 83.211 0 01-5.23 36.74 102.983 102.983 0 01-3 7.28 1.2 1.2 0 000 1.41c9.58 13.3 21.76 23 37.85 27.24a54.37 54.37 0 0019.68 1.57 7.72 7.72 0 018.36 6.9 7.903 7.903 0 01-6.7 9 64.744 64.744 0 01-23-1.33 77.68 77.68 0 01-36.93-19.88 93.628 93.628 0 01-11.91-13.71 2.18 2.18 0 00-2.3-1.06 72.744 72.744 0 00-27.38 7.55c-11.6 6-20.67 14.58-26.4 26.45a10.134 10.134 0 01-3.7 4.7 8 8 0 01-9.19-.7 7.86 7.86 0 01-2.36-9.28 60.324 60.324 0 018.72-14.52c12.2-15.43 28.21-24.59 47.32-28.57A85.085 85.085 0 0173.07 87c.524.015 1-.307 1.18-.8a76.06 76.06 0 006.53-22.3c.351-2.652.518-5.325.5-8z" fill="currentColor"/><path d="M136.26 108.34a44.742 44.742 0 01-11.13-2.87 46.108 46.108 0 01-19.66-13.76 8 8 0 015.72-13.22 7.93 7.93 0 016.54 2.93 33.27 33.27 0 0018.87 10.75c1.546.155 3.058.553 4.48 1.18a8.08 8.08 0 013.84 9.21c-.92 3.52-4.13 5.81-8.66 5.78zm-80.6-75.02a7.61 7.61 0 016.64 5 49.139 49.139 0 013.64 17 46.33 46.33 0 01-2.46 17.28c-2 5.77-8.24 7.79-12.89 4.15a8.1 8.1 0 01-2.39-9 31.679 31.679 0 001.68-12.36 35.77 35.77 0 00-2.43-11c-2.1-5.45 1.75-11.07 8.21-11.07zm22.26 93.25a8 8 0 01-6.68 7.86 32.88 32.88 0 00-19.7 12.19 8.13 8.13 0 01-11.21 1.62 8 8 0 01-1.41-11.58A51.043 51.043 0 0154 123.81a45.842 45.842 0 0114-5.1c5.35-1.04 9.91 2.56 9.92 7.86z" fill="currentColor"/></svg>
|
||||
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 8.1 KiB After Width: | Height: | Size: 8.1 KiB |
@@ -17,7 +17,8 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useAppInfo } from '@/composables';
|
||||
import { localStg } from '@/utils';
|
||||
import { localStg, getRgbOfColor } from '@/utils';
|
||||
import themeSettings from '@/settings/theme.json';
|
||||
|
||||
const { title } = useAppInfo();
|
||||
|
||||
@@ -29,9 +30,12 @@ const lodingClasses = [
|
||||
];
|
||||
|
||||
function addThemeColorCssVars() {
|
||||
const defaultColor = '#1890ff';
|
||||
const defaultColor = themeSettings.themeColor;
|
||||
const themeColor = localStg.get('themeColor') || defaultColor;
|
||||
const cssVars = `--primary-color: ${themeColor}`;
|
||||
|
||||
const { r, g, b } = getRgbOfColor(themeColor);
|
||||
|
||||
const cssVars = `--primary-color: ${r},${g},${b}`;
|
||||
document.documentElement.style.cssText = cssVars;
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div
|
||||
class="dark:bg-[#18181c] dark:text-white dark:text-opacity-82 transition-all duration-300 ease-in-out"
|
||||
class="dark:bg-[#18181c] dark:text-white dark:text-opacity-82 transition-all"
|
||||
:class="inverted ? 'bg-[#001428] text-white' : 'bg-white text-[#333639]'"
|
||||
>
|
||||
<slot></slot>
|
@@ -3,7 +3,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import WebSiteLink from './WebSiteLink.vue';
|
||||
import WebSiteLink from './web-site-link.vue';
|
||||
|
||||
defineOptions({ name: 'GithubLink' });
|
||||
|
@@ -11,14 +11,13 @@
|
||||
<n-input v-model:value="searchValue" placeholder="搜索图标"></n-input>
|
||||
</template>
|
||||
<div v-if="iconsList.length > 0" class="grid grid-cols-9 h-auto overflow-auto">
|
||||
<template v-for="iconItem in iconsList" :key="iconItem">
|
||||
<span v-for="iconItem in iconsList" :key="iconItem" @click="handleChange(iconItem)">
|
||||
<svg-icon
|
||||
:icon="iconItem"
|
||||
class="border-1px border-[#d9d9d9] text-30px m-2px p-5px"
|
||||
class="border-1px border-[#d9d9d9] text-30px m-2px p-5px cursor-pointer"
|
||||
:class="{ 'border-primary': modelValue === iconItem }"
|
||||
@click="handleChange(iconItem)"
|
||||
/>
|
||||
</template>
|
||||
</span>
|
||||
</div>
|
||||
<n-empty v-else class="w-306px" description="你什么也找不到" />
|
||||
</n-popover>
|
@@ -1,5 +1,5 @@
|
||||
import { h } from 'vue';
|
||||
import SvgIcon from '@/components/custom/SvgIcon.vue';
|
||||
import SvgIcon from '~/src/components/custom/svg-icon.vue';
|
||||
|
||||
/**
|
||||
* 图标渲染
|
||||
|
@@ -3,7 +3,7 @@ import { breakpointsTailwind, useBreakpoints } from '@vueuse/core';
|
||||
import { useAppStore, useThemeStore } from '@/store';
|
||||
|
||||
type LayoutMode = 'vertical' | 'horizontal';
|
||||
type LayoutHeaderProps = Record<EnumType.ThemeLayoutMode, App.GlobalHeaderProps>;
|
||||
type LayoutHeaderProps = Record<UnionKey.ThemeLayoutMode, App.GlobalHeaderProps>;
|
||||
|
||||
export function useBasicLayout() {
|
||||
const app = useAppStore();
|
||||
|
@@ -19,9 +19,9 @@ export function useRouterPush(inSetup = true) {
|
||||
if (newTab) {
|
||||
const routerData = router.resolve(to);
|
||||
window.open(routerData.href, '_blank');
|
||||
} else {
|
||||
router.push(to);
|
||||
return Promise.resolve();
|
||||
}
|
||||
return router.push(to);
|
||||
}
|
||||
|
||||
/** 返回上一级路由 */
|
||||
@@ -42,8 +42,8 @@ export function useRouterPush(inSetup = true) {
|
||||
* @param loginModule - 展示的登录模块
|
||||
* @param redirectUrl - 重定向地址(登录成功后跳转的地址),默认undefined表示取当前地址为重定向地址
|
||||
*/
|
||||
function toLogin(loginModule?: EnumType.LoginModuleKey, redirectUrl?: string) {
|
||||
const module: EnumType.LoginModuleKey = loginModule || 'pwd-login';
|
||||
function toLogin(loginModule?: UnionKey.LoginModule, redirectUrl?: string) {
|
||||
const module: UnionKey.LoginModule = loginModule || 'pwd-login';
|
||||
const routeLocation: RouteLocationRaw = {
|
||||
name: routeName('login'),
|
||||
params: { module }
|
||||
@@ -57,7 +57,7 @@ export function useRouterPush(inSetup = true) {
|
||||
* 登录页切换其他模块
|
||||
* @param module - 切换后的登录模块
|
||||
*/
|
||||
function toLoginModule(module: EnumType.LoginModuleKey) {
|
||||
function toLoginModule(module: UnionKey.LoginModule) {
|
||||
const { query } = route.value;
|
||||
routerPush({ name: routeName('login'), params: { module }, query });
|
||||
}
|
||||
|
@@ -1,10 +1,30 @@
|
||||
export const loginModuleLabels: Record<UnionKey.LoginModule, string> = {
|
||||
'pwd-login': '账密登录',
|
||||
'code-login': '手机验证码登录',
|
||||
register: '注册',
|
||||
'reset-pwd': '重置密码',
|
||||
'bind-wechat': '微信绑定'
|
||||
};
|
||||
|
||||
export const userRoleLabels: Record<Auth.RoleType, string> = {
|
||||
super: '超级管理员',
|
||||
admin: '管理员',
|
||||
user: '普通用户'
|
||||
};
|
||||
|
||||
export const userRoleOptions: Common.OptionWithKey<Auth.RoleType>[] = [
|
||||
{ value: 'super', label: userRoleLabels.super },
|
||||
{ value: 'admin', label: userRoleLabels.admin },
|
||||
{ value: 'user', label: userRoleLabels.user }
|
||||
];
|
||||
|
||||
/** 用户性别 */
|
||||
export const genderLabels: Record<UserManagement.GenderKey, string> = {
|
||||
0: '女',
|
||||
1: '男'
|
||||
};
|
||||
|
||||
export const genderOptions: { value: UserManagement.GenderKey; label: string }[] = [
|
||||
export const genderOptions: Common.OptionWithKey<UserManagement.GenderKey>[] = [
|
||||
{ value: '0', label: genderLabels['0'] },
|
||||
{ value: '1', label: genderLabels['1'] }
|
||||
];
|
||||
@@ -17,7 +37,7 @@ export const userStatusLabels: Record<UserManagement.UserStatusKey, string> = {
|
||||
4: '软删除'
|
||||
};
|
||||
|
||||
export const userStatusOptions: { value: UserManagement.UserStatusKey; label: string }[] = [
|
||||
export const userStatusOptions: Common.OptionWithKey<UserManagement.UserStatusKey>[] = [
|
||||
{ value: '1', label: userStatusLabels['1'] },
|
||||
{ value: '2', label: userStatusLabels['2'] },
|
||||
{ value: '3', label: userStatusLabels['3'] },
|
||||
|
18
src/constants/common.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
export const dataTypeLabels: { [K in TypeUtil.DataTypeStringKey]: TypeUtil.DataTypeString<K> } = {
|
||||
string: '[object String]',
|
||||
number: '[object Number]',
|
||||
boolean: '[object Boolean]',
|
||||
null: '[object Null]',
|
||||
undefined: '[object Undefined]',
|
||||
symbol: '[object Symbol]',
|
||||
bigInt: '[object BigInt]',
|
||||
object: '[object Object]',
|
||||
function: '[object Function]',
|
||||
array: '[object Array]',
|
||||
date: '[object Date]',
|
||||
regExp: '[object RegExp]',
|
||||
promise: '[object Promise]',
|
||||
set: '[object Set]',
|
||||
map: '[object Map]',
|
||||
file: '[object File]'
|
||||
};
|
@@ -1 +1,3 @@
|
||||
export * from './common';
|
||||
export * from './system';
|
||||
export * from './business';
|
||||
|
114
src/constants/system.ts
Normal file
@@ -0,0 +1,114 @@
|
||||
export const themeLayoutModeLabels: Record<UnionKey.ThemeLayoutMode, string> = {
|
||||
vertical: '左侧菜单模式',
|
||||
horizontal: '顶部菜单模式',
|
||||
'vertical-mix': '左侧菜单混合模式',
|
||||
'horizontal-mix': '顶部菜单混合模式'
|
||||
};
|
||||
|
||||
export const themeLayoutModeOptions: Common.OptionWithKey<UnionKey.ThemeLayoutMode>[] = [
|
||||
{
|
||||
value: 'vertical',
|
||||
label: themeLayoutModeLabels.vertical
|
||||
},
|
||||
{
|
||||
value: 'horizontal',
|
||||
label: themeLayoutModeLabels.horizontal
|
||||
},
|
||||
{
|
||||
value: 'vertical-mix',
|
||||
label: themeLayoutModeLabels['vertical-mix']
|
||||
},
|
||||
{
|
||||
value: 'horizontal-mix',
|
||||
label: themeLayoutModeLabels['horizontal-mix']
|
||||
}
|
||||
];
|
||||
|
||||
export const themeScrollModeLabels: Record<UnionKey.ThemeScrollMode, string> = {
|
||||
wrapper: '外层滚动',
|
||||
content: '主体滚动'
|
||||
};
|
||||
|
||||
export const themeScrollModeOptions: Common.OptionWithKey<UnionKey.ThemeScrollMode>[] = [
|
||||
{
|
||||
value: 'wrapper',
|
||||
label: themeScrollModeLabels.wrapper
|
||||
},
|
||||
{
|
||||
value: 'content',
|
||||
label: themeScrollModeLabels.content
|
||||
}
|
||||
];
|
||||
|
||||
export const themeTabModeLabels: Record<UnionKey.ThemeTabMode, string> = {
|
||||
chrome: '谷歌风格',
|
||||
button: '按钮风格'
|
||||
};
|
||||
|
||||
export const themeTabModeOptions: Common.OptionWithKey<UnionKey.ThemeTabMode>[] = [
|
||||
{
|
||||
value: 'chrome',
|
||||
label: themeTabModeLabels.chrome
|
||||
},
|
||||
{
|
||||
value: 'button',
|
||||
label: themeTabModeLabels.button
|
||||
}
|
||||
];
|
||||
|
||||
export const themeHorizontalMenuPositionLabels: Record<UnionKey.ThemeHorizontalMenuPosition, string> = {
|
||||
'flex-start': '居左',
|
||||
center: '居中',
|
||||
'flex-end': '居右'
|
||||
};
|
||||
|
||||
export const themeHorizontalMenuPositionOptions: Common.OptionWithKey<UnionKey.ThemeHorizontalMenuPosition>[] = [
|
||||
{
|
||||
value: 'flex-start',
|
||||
label: themeHorizontalMenuPositionLabels['flex-start']
|
||||
},
|
||||
{
|
||||
value: 'center',
|
||||
label: themeHorizontalMenuPositionLabels.center
|
||||
},
|
||||
{
|
||||
value: 'flex-end',
|
||||
label: themeHorizontalMenuPositionLabels['flex-end']
|
||||
}
|
||||
];
|
||||
|
||||
export const themeAnimateModeLabels: Record<UnionKey.ThemeAnimateMode, string> = {
|
||||
'zoom-fade': '渐变',
|
||||
'zoom-out': '闪现',
|
||||
'fade-slide': '滑动',
|
||||
fade: '消退',
|
||||
'fade-bottom': '底部消退',
|
||||
'fade-scale': '缩放消退'
|
||||
};
|
||||
|
||||
export const themeAnimateModeOptions: Common.OptionWithKey<UnionKey.ThemeAnimateMode>[] = [
|
||||
{
|
||||
value: 'zoom-fade',
|
||||
label: themeAnimateModeLabels['zoom-fade']
|
||||
},
|
||||
{
|
||||
value: 'zoom-out',
|
||||
label: themeAnimateModeLabels['zoom-out']
|
||||
},
|
||||
{
|
||||
value: 'fade-slide',
|
||||
label: themeAnimateModeLabels['fade-slide']
|
||||
},
|
||||
{
|
||||
value: 'fade',
|
||||
label: themeAnimateModeLabels.fade
|
||||
},
|
||||
{
|
||||
value: 'fade-bottom',
|
||||
label: themeAnimateModeLabels['fade-bottom']
|
||||
},
|
||||
{
|
||||
value: 'fade-scale',
|
||||
label: themeAnimateModeLabels['fade-scale']
|
||||
}
|
||||
];
|
@@ -1,15 +0,0 @@
|
||||
/** 用户角色 */
|
||||
export enum EnumUserRole {
|
||||
super = '超级管理员',
|
||||
admin = '管理员',
|
||||
user = '普通用户'
|
||||
}
|
||||
|
||||
/** 登录模块 */
|
||||
export enum EnumLoginModule {
|
||||
'pwd-login' = '账密登录',
|
||||
'code-login' = '手机验证码登录',
|
||||
'register' = '注册',
|
||||
'reset-pwd' = '重置密码',
|
||||
'bind-wechat' = '微信绑定'
|
||||
}
|
@@ -1,24 +0,0 @@
|
||||
/** http请求头的content-type类型 */
|
||||
export enum EnumContentType {
|
||||
json = 'application/json',
|
||||
formUrlencoded = 'application/x-www-form-urlencoded',
|
||||
formData = 'multipart/form-data'
|
||||
}
|
||||
|
||||
/** 数据类型 */
|
||||
export enum EnumDataType {
|
||||
number = '[object Number]',
|
||||
string = '[object String]',
|
||||
boolean = '[object Boolean]',
|
||||
null = '[object Null]',
|
||||
undefined = '[object Undefined]',
|
||||
object = '[object Object]',
|
||||
array = '[object Array]',
|
||||
function = '[object Function]',
|
||||
date = '[object Date]',
|
||||
regexp = '[object RegExp]',
|
||||
promise = '[object Promise]',
|
||||
set = '[object Set]',
|
||||
map = '[object Map]',
|
||||
file = '[object File]'
|
||||
}
|
@@ -1,3 +0,0 @@
|
||||
export * from './common';
|
||||
export * from './system';
|
||||
export * from './business';
|
@@ -1,36 +0,0 @@
|
||||
/** 布局组件的名称 */
|
||||
export enum EnumLayoutComponentName {
|
||||
basic = 'basic-layout',
|
||||
blank = 'blank-layout'
|
||||
}
|
||||
|
||||
/** 布局模式 */
|
||||
export enum EnumThemeLayoutMode {
|
||||
'vertical' = '左侧菜单模式',
|
||||
'horizontal' = '顶部菜单模式',
|
||||
'vertical-mix' = '左侧菜单混合模式',
|
||||
'horizontal-mix' = '顶部菜单混合模式'
|
||||
}
|
||||
|
||||
/** 多页签风格 */
|
||||
export enum EnumThemeTabMode {
|
||||
'chrome' = '谷歌风格',
|
||||
'button' = '按钮风格'
|
||||
}
|
||||
|
||||
/** 水平模式的菜单位置 */
|
||||
export enum EnumThemeHorizontalMenuPosition {
|
||||
'flex-start' = '居左',
|
||||
'center' = '居中',
|
||||
'flex-end' = '居右'
|
||||
}
|
||||
|
||||
/** 过渡动画类型 */
|
||||
export enum EnumThemeAnimateMode {
|
||||
'zoom-fade' = '渐变',
|
||||
'zoom-out' = '闪现',
|
||||
'fade-slide' = '滑动',
|
||||
'fade' = '消退',
|
||||
'fade-bottom' = '底部消退',
|
||||
'fade-scale' = '缩放消退'
|
||||
}
|
@@ -1,5 +1,5 @@
|
||||
import useCountDown from './useCountDown';
|
||||
import useSmsCode from './useSmsCode';
|
||||
import useImageVerify from './useImageVerify';
|
||||
import useCountDown from './use-count-down';
|
||||
import useSmsCode from './use-sms-code';
|
||||
import useImageVerify from './use-image-verify';
|
||||
|
||||
export { useCountDown, useSmsCode, useImageVerify };
|
||||
|
@@ -2,7 +2,7 @@ import { computed } from 'vue';
|
||||
import { REGEXP_PHONE } from '@/config';
|
||||
import { fetchSmsCode } from '@/service';
|
||||
import { useLoading } from '../common';
|
||||
import useCountDown from './useCountDown';
|
||||
import useCountDown from './use-count-down';
|
||||
|
||||
export default function useSmsCode() {
|
||||
const { loading, startLoading, endLoading } = useLoading();
|
89
src/hooks/business/use-table.ts
Normal file
@@ -0,0 +1,89 @@
|
||||
import { ref, reactive } from 'vue';
|
||||
import type { Ref } from 'vue';
|
||||
import type { DataTableBaseColumn, DataTableSelectionColumn, DataTableExpandColumn, PaginationProps } from 'naive-ui';
|
||||
import type { MaybeComputedRef } from '@vueuse/core';
|
||||
import type { TableColumnGroup, InternalRowData } from 'naive-ui/es/data-table/src/interface';
|
||||
import { useLoadingEmpty } from '../common';
|
||||
|
||||
/**
|
||||
* 表格的列
|
||||
*/
|
||||
type DataTableColumn<T = InternalRowData> =
|
||||
| (Omit<TableColumnGroup<T>, 'key'> & { key: keyof T })
|
||||
| (Omit<DataTableBaseColumn<T>, 'key'> & { key: keyof T })
|
||||
| DataTableSelectionColumn<T>
|
||||
| DataTableExpandColumn<T>;
|
||||
|
||||
/**
|
||||
* 表格分页参数
|
||||
*/
|
||||
type TablePaginationParams = Pick<PaginationProps, 'page' | 'pageSize'>;
|
||||
|
||||
/**
|
||||
* 表格接口的请求参数
|
||||
*/
|
||||
type TableApiParams = Record<string, unknown> & TablePaginationParams;
|
||||
|
||||
/**
|
||||
* 表格接口的请求数据
|
||||
*/
|
||||
type TableApiData<T = InternalRowData> = {
|
||||
data: T[];
|
||||
pageNum: number;
|
||||
pageSize: number;
|
||||
total: number;
|
||||
};
|
||||
|
||||
/**
|
||||
* 表格接口的请求函数
|
||||
*/
|
||||
type TableApiFn<P extends TableApiParams, T extends InternalRowData> = (
|
||||
params: P
|
||||
) => Promise<Service.SuccessResult<TableApiData<T>>>;
|
||||
|
||||
export function useNaiveTable<TableData extends InternalRowData, P extends TableApiParams>(
|
||||
apiFn: TableApiFn<P, TableData>,
|
||||
apiParams: P,
|
||||
columns: MaybeComputedRef<DataTableColumn<TableData>[]>
|
||||
) {
|
||||
const { loading, startLoading, endLoading, empty, setEmpty } = useLoadingEmpty();
|
||||
|
||||
const tableData: Ref<TableData[]> = ref([]);
|
||||
|
||||
async function getTableData(paginationParams?: TablePaginationParams) {
|
||||
startLoading();
|
||||
|
||||
const params = { ...apiParams, ...paginationParams };
|
||||
|
||||
const { data } = await apiFn(params);
|
||||
if (data) {
|
||||
tableData.value = data.data;
|
||||
|
||||
setEmpty(data.data.length === 0);
|
||||
}
|
||||
endLoading();
|
||||
}
|
||||
|
||||
const pagination: PaginationProps = reactive({
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
showSizePicker: true,
|
||||
pageSizes: [10, 15, 20, 25, 30],
|
||||
onChange: (page: number) => {
|
||||
pagination.page = page;
|
||||
},
|
||||
onUpdatePageSize: (pageSize: number) => {
|
||||
pagination.pageSize = pageSize;
|
||||
pagination.page = 1;
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
tableData,
|
||||
columns,
|
||||
loading,
|
||||
empty,
|
||||
pagination,
|
||||
start: getTableData
|
||||
};
|
||||
}
|
@@ -1 +0,0 @@
|
||||
export function useTable() {}
|
@@ -1,7 +1,7 @@
|
||||
import useContext from './useContext';
|
||||
import useBoolean from './useBoolean';
|
||||
import useLoading from './useLoading';
|
||||
import useLoadingEmpty from './useLoadingEmpty';
|
||||
import useReload from './useReload';
|
||||
import useContext from './use-context';
|
||||
import useBoolean from './use-boolean';
|
||||
import useLoading from './use-loading';
|
||||
import useLoadingEmpty from './use-loading-empty';
|
||||
import useReload from './use-reload';
|
||||
|
||||
export { useContext, useBoolean, useLoading, useLoadingEmpty, useReload };
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import useBoolean from './useBoolean';
|
||||
import useBoolean from './use-boolean';
|
||||
|
||||
export default function useLoadingEmpty(initLoading = false, initEmpty = false) {
|
||||
const { bool: loading, setTrue: startLoading, setFalse: endLoading } = useBoolean(initLoading);
|
@@ -1,4 +1,4 @@
|
||||
import useBoolean from './useBoolean';
|
||||
import useBoolean from './use-boolean';
|
||||
|
||||
export default function useLoading(initValue = false) {
|
||||
const { bool: loading, setTrue: startLoading, setFalse: endLoading } = useBoolean(initValue);
|
@@ -1,5 +1,5 @@
|
||||
import { nextTick } from 'vue';
|
||||
import useBoolean from './useBoolean';
|
||||
import useBoolean from './use-boolean';
|
||||
|
||||
/** 重载 */
|
||||
export default function useReload() {
|
@@ -1,18 +1,20 @@
|
||||
<template>
|
||||
<admin-layout
|
||||
:mode="mode"
|
||||
:is-mobile="isMobile"
|
||||
:fixed-header-and-tab="theme.fixedHeaderAndTab"
|
||||
:scroll-mode="theme.scrollMode"
|
||||
:scroll-el-id="app.scrollElId"
|
||||
:full-content="app.contentFull"
|
||||
:fixed-top="theme.fixedHeaderAndTab"
|
||||
:header-height="theme.header.height"
|
||||
:tab-visible="theme.tab.visible"
|
||||
:tab-height="theme.tab.height"
|
||||
:content-class="app.disableMainXScroll ? 'overflow-x-hidden' : ''"
|
||||
:sider-visible="siderVisible"
|
||||
:sider-collapse="app.siderCollapse"
|
||||
:sider-width="siderWidth"
|
||||
:sider-collapsed-width="siderCollapsedWidth"
|
||||
:sider-collapse="app.siderCollapse"
|
||||
:fixed-footer="theme.footer.fixed"
|
||||
:footer-visible="theme.footer.visible"
|
||||
@update:sider-collapse="app.setSiderCollapse"
|
||||
:fixed-footer="theme.footer.fixed"
|
||||
>
|
||||
<template #header>
|
||||
<global-header v-bind="headerProps" />
|
||||
@@ -33,7 +35,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import AdminLayout from '@soybeanjs/vue-admin-layout';
|
||||
import { AdminLayout } from '@soybeanjs/vue-materials';
|
||||
import { useAppStore, useThemeStore } from '@/store';
|
||||
import { useBasicLayout } from '@/composables';
|
||||
import {
|
||||
@@ -51,7 +53,7 @@ defineOptions({ name: 'BasicLayout' });
|
||||
const app = useAppStore();
|
||||
const theme = useThemeStore();
|
||||
|
||||
const { mode, isMobile, headerProps, siderVisible, siderWidth, siderCollapsedWidth } = useBasicLayout();
|
||||
const { mode, headerProps, siderVisible, siderWidth, siderCollapsedWidth } = useBasicLayout();
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
@@ -1,35 +0,0 @@
|
||||
<template>
|
||||
<div
|
||||
:class="{ 'p-16px': showPadding }"
|
||||
class="h-full bg-[#f6f9f8] dark:bg-[#101014] transition duration-300 ease-in-out"
|
||||
>
|
||||
<router-view v-slot="{ Component, route }">
|
||||
<transition :name="theme.pageAnimateMode" mode="out-in" :appear="true">
|
||||
<keep-alive :include="routeStore.cacheRoutes">
|
||||
<component :is="Component" v-if="app.reloadFlag" :key="route.fullPath" />
|
||||
</keep-alive>
|
||||
</transition>
|
||||
</router-view>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useAppStore, useRouteStore, useThemeStore } from '@/store';
|
||||
|
||||
defineOptions({ name: 'GlobalContent' });
|
||||
|
||||
interface Props {
|
||||
/** 显示padding */
|
||||
showPadding?: boolean;
|
||||
}
|
||||
|
||||
withDefaults(defineProps<Props>(), {
|
||||
showPadding: true
|
||||
});
|
||||
|
||||
const app = useAppStore();
|
||||
const theme = useThemeStore();
|
||||
const routeStore = useRouteStore();
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
@@ -1,21 +0,0 @@
|
||||
import MenuCollapse from './MenuCollapse.vue';
|
||||
import GlobalBreadcrumb from './GlobalBreadcrumb.vue';
|
||||
import HeaderMenu from './HeaderMenu.vue';
|
||||
import GithubSite from './GithubSite.vue';
|
||||
import FullScreen from './FullScreen.vue';
|
||||
import ThemeMode from './ThemeMode.vue';
|
||||
import UserAvatar from './UserAvatar.vue';
|
||||
import SystemMessage from './SystemMessage.vue';
|
||||
import SettingButton from './SettingButton.vue';
|
||||
|
||||
export {
|
||||
MenuCollapse,
|
||||
GlobalBreadcrumb,
|
||||
HeaderMenu,
|
||||
GithubSite,
|
||||
FullScreen,
|
||||
ThemeMode,
|
||||
UserAvatar,
|
||||
SystemMessage,
|
||||
SettingButton
|
||||
};
|
@@ -1,3 +0,0 @@
|
||||
import SearchModal from './SearchModal.vue';
|
||||
|
||||
export { SearchModal };
|
@@ -1,5 +0,0 @@
|
||||
import MixMenuDetail from './MixMenuDetail.vue';
|
||||
import MixMenuDrawer from './MixMenuDrawer.vue';
|
||||
import MixMenuCollapse from './MixMenuCollapse.vue';
|
||||
|
||||
export { MixMenuDetail, MixMenuDrawer, MixMenuCollapse };
|
@@ -1,3 +0,0 @@
|
||||
import VerticalMenu from './VerticalMenu.vue';
|
||||
|
||||
export { VerticalMenu };
|
@@ -1,4 +0,0 @@
|
||||
import VerticalSider from './VerticalSider/index.vue';
|
||||
import VerticalMixSider from './VerticalMixSider/index.vue';
|
||||
|
||||
export { VerticalSider, VerticalMixSider };
|
@@ -1,3 +0,0 @@
|
||||
import ContextMenu from './ContextMenu.vue';
|
||||
|
||||
export { ContextMenu };
|
@@ -1,4 +0,0 @@
|
||||
import TabDetail from './TabDetail/index.vue';
|
||||
import ReloadButton from './ReloadButton/index.vue';
|
||||
|
||||
export { TabDetail, ReloadButton };
|
@@ -1,3 +0,0 @@
|
||||
import LayoutCheckbox from './LayoutCheckbox.vue';
|
||||
|
||||
export { LayoutCheckbox };
|
@@ -1,24 +0,0 @@
|
||||
<template>
|
||||
<n-divider title-placement="center">布局模式</n-divider>
|
||||
<n-space justify="space-between">
|
||||
<layout-checkbox
|
||||
v-for="item in theme.layout.modeList"
|
||||
:key="item.value"
|
||||
:mode="item.value"
|
||||
:label="item.label"
|
||||
:checked="item.value === theme.layout.mode"
|
||||
@click="theme.setLayoutMode(item.value)"
|
||||
/>
|
||||
</n-space>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useThemeStore } from '@/store';
|
||||
import { LayoutCheckbox } from './components';
|
||||
|
||||
defineOptions({ name: 'LayoutMode' });
|
||||
|
||||
const theme = useThemeStore();
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
@@ -1,4 +0,0 @@
|
||||
import ColorCheckbox from './ColorCheckbox.vue';
|
||||
import ColorModal from './ColorModal.vue';
|
||||
|
||||
export { ColorCheckbox, ColorModal };
|
@@ -1,9 +0,0 @@
|
||||
import DrawerButton from './DrawerButton/index.vue';
|
||||
import DarkMode from './DarkMode/index.vue';
|
||||
import LayoutMode from './LayoutMode/index.vue';
|
||||
import ThemeColorSelect from './ThemeColorSelect/index.vue';
|
||||
import PageFunc from './PageFunc/index.vue';
|
||||
import PageView from './PageView/index.vue';
|
||||
import ThemeConfig from './ThemeConfig/index.vue';
|
||||
|
||||
export { DrawerButton, DarkMode, LayoutMode, ThemeColorSelect, PageFunc, PageView, ThemeConfig };
|
42
src/layouts/common/global-content/index.vue
Normal file
@@ -0,0 +1,42 @@
|
||||
<template>
|
||||
<router-view v-slot="{ Component, route }">
|
||||
<transition
|
||||
:name="theme.pageAnimateMode"
|
||||
mode="out-in"
|
||||
:appear="true"
|
||||
@before-leave="app.setDisableMainXScroll(true)"
|
||||
@after-enter="app.setDisableMainXScroll(false)"
|
||||
>
|
||||
<keep-alive :include="routeStore.cacheRoutes">
|
||||
<component
|
||||
:is="Component"
|
||||
v-if="app.reloadFlag"
|
||||
:key="route.fullPath"
|
||||
:class="{ 'p-16px': showPadding }"
|
||||
class="flex-grow bg-[#f6f9f8] dark:bg-[#101014] transition duration-300 ease-in-out"
|
||||
/>
|
||||
</keep-alive>
|
||||
</transition>
|
||||
</router-view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useAppStore, useRouteStore, useThemeStore } from '@/store';
|
||||
|
||||
defineOptions({ name: 'GlobalContent' });
|
||||
|
||||
interface Props {
|
||||
/** 显示padding */
|
||||
showPadding?: boolean;
|
||||
}
|
||||
|
||||
withDefaults(defineProps<Props>(), {
|
||||
showPadding: true
|
||||
});
|
||||
|
||||
const app = useAppStore();
|
||||
const theme = useThemeStore();
|
||||
const routeStore = useRouteStore();
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
21
src/layouts/common/global-header/components/index.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import MenuCollapse from './menu-collapse.vue';
|
||||
import GlobalBreadcrumb from './global-breadcrumb.vue';
|
||||
import HeaderMenu from './header-menu.vue';
|
||||
import GithubSite from './github-site.vue';
|
||||
import FullScreen from './full-screen.vue';
|
||||
import ThemeMode from './theme-mode.vue';
|
||||
import UserAvatar from './user-avatar.vue';
|
||||
import SystemMessage from './system-message.vue';
|
||||
import SettingButton from './setting-button.vue';
|
||||
|
||||
export {
|
||||
MenuCollapse,
|
||||
GlobalBreadcrumb,
|
||||
HeaderMenu,
|
||||
GithubSite,
|
||||
FullScreen,
|
||||
ThemeMode,
|
||||
UserAvatar,
|
||||
SystemMessage,
|
||||
SettingButton
|
||||
};
|
@@ -52,7 +52,7 @@ import { computed, ref } from 'vue';
|
||||
import { useThemeStore } from '@/store';
|
||||
import { useBasicLayout } from '@/composables';
|
||||
import { useBoolean } from '@/hooks';
|
||||
import MessageList from './MessageList.vue';
|
||||
import MessageList from './message-list.vue';
|
||||
|
||||
defineOptions({ name: 'SystemMessage' });
|
||||
|
@@ -21,8 +21,8 @@
|
||||
<script setup lang="ts">
|
||||
import { useThemeStore } from '@/store';
|
||||
import { useBasicLayout } from '@/composables';
|
||||
import GlobalLogo from '../GlobalLogo/index.vue';
|
||||
import GlobalSearch from '../GlobalSearch/index.vue';
|
||||
import GlobalLogo from '../global-logo/index.vue';
|
||||
import GlobalSearch from '../global-search/index.vue';
|
||||
import {
|
||||
FullScreen,
|
||||
GithubSite,
|