Compare commits

..

84 Commits

Author SHA1 Message Date
Soybean
db3c25ea14 chore(release): 0.1.1 精简版发布 2022-01-20 21:32:16 +08:00
Soybean
5eddb4910c docs(projects): update README.md 2022-01-20 21:29:30 +08:00
Soybean
ce531ce5dd feat(projects): 细节完善、迁移页面 2022-01-20 21:24:01 +08:00
Soybean
28efbdbc70 feat(projects): 迁移多页签 2022-01-20 02:59:29 +08:00
Soybean
cc290accc2 feat(projects): 细节完善 2022-01-19 00:36:53 +08:00
Soybean
579e07400e fix(projects): 修复vertical-mix布局、重构初始化的loading 2022-01-18 03:21:02 +08:00
Soybean
b2a4ddf5e3 refactor(projects): 恢复pinia默认写法 2022-01-17 03:42:16 +08:00
Soybean
28b5d22401 fix(projects): 修复面包屑数据 2022-01-14 14:17:34 +08:00
Soybean
839b82ba8b feat(projects): 请求拦截器添加刷新token 2022-01-12 19:53:45 +08:00
Soybean
09c7658c21 feat(projects): 面包屑 2022-01-11 19:03:42 +08:00
Soybean
e25afe2fad feat(projects): 添加侧边菜单 2022-01-11 08:22:31 +08:00
Soybean
371fad4f26 build(projects): 添加vercel打包的环境 2022-01-10 19:24:13 +08:00
Soybean
a090d398fc feat(projects): 添加头部折叠按钮 2022-01-10 12:43:04 +08:00
Soybean
6d132c5977 feat(projects): 主题配置抽屉: 迁移其他功能 2022-01-09 13:25:42 +08:00
Soybean
912bfdf439 feat(projects): 主题配置抽屉:迁移暗黑模式、布局模式、添加颜色选择面板 2022-01-09 12:24:39 +08:00
Soybean
bf020a8258 feat(projects): theme store完成 2022-01-08 20:49:21 +08:00
Soybean
10e4d81bd6 feat(projects): 添加抽屉 2022-01-07 18:51:06 +08:00
Soybean
0653fb144f feat(projects): 创建自定义布局组件SoybeanLayout 2022-01-07 15:44:28 +08:00
Soybean
006467a062 feat(projects): 新增BasicLayout布局 2022-01-07 02:50:50 +08:00
Soybean
0c5770dfd2 build(projects): 修改vscode配置 2022-01-06 14:40:07 +08:00
Soybean
0e783bcf7b fix(projects): 去除Layout组件冗余代码 2022-01-06 11:38:46 +08:00
Soybean
e5793e1c8d style(projects): 路由相关文件夹简化 2022-01-06 11:37:06 +08:00
Soybean
85b55bb37a feat(projects): 多级路由的所有子路由转换成二级路由 2022-01-06 11:30:02 +08:00
Soybean
b36a62b150 refactor(projects): 单独路由逻辑重构、路由转换函数优化 2022-01-06 02:42:00 +08:00
Soybean
c804b21ceb feat(projects): 添加NaiveProvider组件 2022-01-05 19:06:23 +08:00
Soybean
5bfb8199b4 fix(projects): 修复redirect-not-found子路由 2022-01-05 13:49:42 +08:00
Soybean
ab9a6a2f39 refactor(projects): 单独一级路由相关逻辑重构 2022-01-05 11:56:28 +08:00
Soybean
b93b80cb4b feat(projects): 迁移登录完成 2022-01-05 01:36:16 +08:00
Soybean
f5a36a05cb feat(projects): 登录页面开始迁移 2022-01-04 19:09:00 +08:00
Soybean
035fa114c9 feat(projects): 初始化加载效果:应用主题颜色 2022-01-04 14:05:18 +08:00
Soybean
2c196841bd feat(projects): 集成naiveUI主题配置,将css vars添加至html 2022-01-04 02:20:32 +08:00
Soybean
0d2a5629e8 feat(projects): 路由页面跳转权限完成 2022-01-04 00:00:48 +08:00
Soybean
de2057f141 refactor(projects): 精简版+动态路由权限初步 2022-01-03 22:20:10 +08:00
Soybean
7a0648dba5 feat(projects): 添加cryptojs,对本地缓存数据进行加密 2022-01-01 22:52:05 +08:00
Soybean
25d3404c9c Merge pull request #31 from yanbowe/main
feat(projects): 菜单搜索增加大小写转换
2021-12-31 17:58:49 +08:00
Yanbowen
29078689b0 feat(projects): 菜单搜索增加大小写转换 2021-12-31 17:27:07 +08:00
Soybean
078433da43 Merge pull request #30 from yanbowe/main
feat(projects): 增加全局搜索菜单功能
2021-12-29 17:06:45 +08:00
Yanbowen
b9ce69130b feat(projects): 增加全局搜索菜单功能 2021-12-29 16:50:08 +08:00
Soybean
90ddf9837c docs(projects): update README.md 2021-12-29 09:45:45 +08:00
Soybean
777cf8e06a build(deps): 升级依赖 2021-12-25 01:35:39 +08:00
Soybean
9bc682dae8 feat(projects): 引入mockjs 2021-12-25 01:30:45 +08:00
Soybean
c9c5ca9989 fix(deps): 降低vite版本 2021-12-24 11:03:38 +08:00
Soybean
e776df49e4 build(deps): 升级依赖 2021-12-24 11:00:10 +08:00
Soybean
659e460653 docs(projects): update README.md 2021-12-21 13:52:11 +08:00
Soybean
186f53f634 Merge pull request #28 from yanbowe/main
增加项目文档(外链方式)
2021-12-20 14:47:36 +08:00
Yanbowen
5aac013597 Merge branch 'main' of https://github.com/yanbowe/soybean-admin into main 2021-12-20 14:11:06 +08:00
Yanbowen
1901a0bfb7 feat(projects): 增加项目文档外链 2021-12-20 14:04:11 +08:00
Soybean
25bead0039 Merge pull request #27 from yanbowe/main 2021-12-18 22:31:02 +08:00
Yanbowen
041012b3ee feat(projects): 图标选择器增加扩展树形 2021-12-18 16:50:20 +08:00
Yanbowen
9472b51811 feat(projects): 增加Icon选择器组件 2021-12-18 16:34:25 +08:00
Soybean
f3c86efbe5 build(deps): 升级依赖 2021-12-15 13:48:15 +08:00
Soybean
51c744c8e2 feat(projects): 添加表格页面示例 2021-12-12 21:43:26 +08:00
Soybean
230a50a4cf feat(projects): 添加常用组件、composables函数 2021-12-12 17:28:39 +08:00
Soybean
e755caabf2 build(deps): 升级依赖 2021-12-04 22:46:49 +08:00
Soybean
ae7ec99a98 build(deps): 升级依赖 2021-11-30 23:28:11 +08:00
Soybean
987cef3363 feat(projects): 添加路由跳转浏览器新标签 2021-11-30 22:00:59 +08:00
Soybean
2ad1ad32b8 fix(projects): 请求相关细节修复 2021-11-30 20:49:00 +08:00
Soybean
ff9216b621 fix(projects): 修复网络请求错误空信息的提示 2021-11-30 14:04:39 +08:00
Soybean
225c4fe022 refactor(projects): 登录模块由query变更为动态路由params 2021-11-29 20:34:56 +08:00
Soybean
f29106e480 refactor(styles): 样式调整 2021-11-29 10:58:27 +08:00
Soybean
21c2f5a857 build(projects): 环境变量获取方式变更 2021-11-29 09:19:15 +08:00
Soybean
e53e7936df chore(release): 0.0.5 2021-11-28 19:51:15 +08:00
Soybean
bdc39aff1b feat(projects): 新增组件页面:按钮、卡片示例 2021-11-28 15:29:53 +08:00
Soybean
0b10b5056e refactor(projects): 优化路由导入页面写法,页面路由调整 2021-11-28 12:19:00 +08:00
Soybean
d683894beb refactor(projects): 重构路由类型和路由元数据类型,重构多级菜单路由写法 2021-11-28 12:17:48 +08:00
Soybean
9fb641f71e fix(components): 修复HorizontalLayout布局 2021-11-28 12:16:48 +08:00
Soybean
a6bdc380a8 build(deps): 升级依赖 2021-11-28 00:06:11 +08:00
Soybean
8b27fc8bb8 chore(release): 0.0.4 2021-11-25 22:44:19 +08:00
Soybean
738964a769 fix(projects): 添加西瓜视频实例在onUnMounted的销毁,多页签居中距离精确 2021-11-25 22:16:34 +08:00
Soybean
c429cd0293 fix(components): 修复多页签按钮风格的tab滚动问题 2021-11-25 22:02:28 +08:00
Soybean
20aa39f14e fix(components): 修复多页签Tab自动滚动问题 2021-11-25 21:50:20 +08:00
Soybean
93f9aa9584 fix(projects): 修复打包构建时图标错误 2021-11-25 01:18:51 +08:00
Soybean
8ce627a397 feat(components): 添加多页签Tab点击后自动往中间滚动 2021-11-25 00:50:55 +08:00
Soybean
1ffb75afce refactor(components): blankLayout引入GlobalContent 2021-11-24 23:54:10 +08:00
Soybean
32aa5ee75a feat(projects): 新增网址导航页面 2021-11-24 19:14:13 +08:00
Soybean
98a7d25cf8 docs(projects): update README.md 2021-11-24 12:02:10 +08:00
Soybean
1b3463d2e7 docs(projects): update README.md 2021-11-24 11:53:32 +08:00
Soybean
cff11d9175 fix(types): 添加dotEnv类型的非空判断 2021-11-24 00:51:33 +08:00
Soybean
54577f10fc docs(projects): update README.md 2021-11-24 00:46:58 +08:00
Soybean
6261156c5a refactor(projects): 细节完善 2021-11-23 18:08:56 +08:00
Soybean
f5a5f44a2b refactor(projects): 文件夹位置规范 2021-11-23 10:55:20 +08:00
Soybean
3fb7a5f709 Merge pull request #19 from yanbowe/main
feat(storage): local存储增加有效期
2021-11-23 10:15:37 +08:00
Yanbowen
e6c9b35ab4 feat(storage): local存储增加有效期 2021-11-23 09:57:59 +08:00
Soybean
0569666a8f refactor(projects): axios处理的请求结果去除网路状态 2021-11-23 09:52:23 +08:00
381 changed files with 12075 additions and 13517 deletions

10
.env
View File

@@ -1,5 +1,7 @@
# 变量需要以VITE开头
BASE_URL=/
VITE_APP_TITLE=SoybeanAdmin
VITE_APP_TITLE_LABEL=SoybeanAdmin
VITE_BASE_URL=/
VITE_APP_NAME=SoybeanAdmin
VITE_APP_TITLE=Soybean管理系统
VITE_APP_DESC=SoybeanAdmin是一个中后台管理系统模版

21
.env-config.ts Normal file
View File

@@ -0,0 +1,21 @@
/** 请求环境配置 */
type ServiceEnv = {
[key in Service.HttpEnv]: {
/** 请求环境 */
env: Service.HttpEnv;
/** 请求地址 */
url: string;
};
};
/** 请求的环境 */
export const serviceEnv: ServiceEnv = {
test: {
env: 'test',
url: 'http://120.76.42.91:18888'
},
prod: {
env: 'prod',
url: 'http://120.76.42.91:18888'
}
};

View File

@@ -1,4 +0,0 @@
#请求的环境
VITE_HTTP_ENV=DEV
#请求地址
VITE_HTTP_URL=https://test.aisuit.com.cn

View File

@@ -1,4 +0,0 @@
#请求的环境 正式环境
VITE_HTTP_ENV=PROD
#请求地址
VITE_HTTP_URL=http://192.168.100.43:8201

View File

@@ -1,3 +0,0 @@
VITE_HTTP_ENV=STAGING
#请求地址
VITE_HTTP_URL=http://192.168.100.43:8201

View File

@@ -7,8 +7,8 @@ lib
.vscode
.idea
/dist/
/mock/
/public
/docs
.vscode
.local
!.env-config.ts

View File

@@ -20,33 +20,143 @@ module.exports = {
sourceType: 'module'
},
plugins: ['vue', '@typescript-eslint'],
extends: [
'plugin:vue/vue3-recommended',
'airbnb-base',
'@vue/typescript/recommended',
'plugin:prettier/recommended',
'@vue/prettier/@typescript-eslint'
],
extends: ['plugin:vue/vue3-recommended', 'airbnb-base', '@vue/typescript/recommended', 'plugin:prettier/recommended'],
rules: {
'no-unused-vars': 'off',
'import/extensions': 'off',
'import/no-extraneous-dependencies': 'off',
'import/no-unresolved': 0,
'no-shadow': 0,
'import/order': [
'error',
{
'newlines-between': 'never',
groups: ['builtin', 'external', 'internal', 'parent', 'sibling', 'index'],
pathGroups: [
{
pattern: 'vue',
group: 'external',
position: 'before'
},
{
pattern: 'vue-router',
group: 'external',
position: 'before'
},
{
pattern: 'pinia',
group: 'external',
position: 'before'
},
{
pattern: 'naive-ui',
group: 'external',
position: 'before'
},
{
pattern: '@/config',
group: 'internal',
position: 'before'
},
{
pattern: '@/settings',
group: 'internal',
position: 'before'
},
{
pattern: '@/enum',
group: 'internal',
position: 'before'
},
{
pattern: '@/plugins',
group: 'internal',
position: 'before'
},
{
pattern: '@/layouts',
group: 'internal',
position: 'before'
},
{
pattern: '@/layouts',
group: 'internal',
position: 'before'
},
{
pattern: '@/views',
group: 'internal',
position: 'before'
},
{
pattern: '@/components',
group: 'internal',
position: 'before'
},
{
pattern: '@/router',
group: 'internal',
position: 'before'
},
{
pattern: '@/store',
group: 'internal',
position: 'before'
},
{
pattern: '@/composables',
group: 'internal',
position: 'before'
},
{
pattern: '@/hooks',
group: 'internal',
position: 'before'
},
{
pattern: '@/service',
group: 'internal',
position: 'before'
},
{
pattern: '@/utils',
group: 'internal',
position: 'before'
},
{
pattern: '@/assets',
group: 'internal',
position: 'before'
},
{
pattern: '@/**',
group: 'internal',
position: 'before'
},
{
pattern: '@/interface',
group: 'internal',
position: 'before'
}
],
pathGroupsExcludedImportTypes: ['vue', 'vue-router', 'pinia', 'naive-ui']
}
],
'import/prefer-default-export': 0,
'no-use-before-define': 'off',
'vue/multi-word-component-names': 0,
'max-classes-per-file': 0,
'no-shadow': 0,
'no-unused-vars': 'off',
'no-use-before-define': 'off',
'vue/comment-directive': 0,
'vue/multi-word-component-names': 0,
'@typescript-eslint/ban-types': 'off',
'@typescript-eslint/ban-ts-ignore': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-empty-function': 'off',
'@typescript-eslint/no-explicit-any': 0,
'@typescript-eslint/no-inferrable-types': 0,
'@typescript-eslint/ban-ts-ignore': 'off',
'@typescript-eslint/ban-types': 'off',
'@typescript-eslint/no-var-requires': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/no-empty-function': 'off',
'@typescript-eslint/no-non-null-assertion': 'off',
'@typescript-eslint/no-unused-vars': ['warn', { ignoreRestSiblings: true }],
'@typescript-eslint/no-use-before-define': ['error', { classes: true, functions: false, typedefs: false }]
'@typescript-eslint/no-use-before-define': ['error', { classes: true, functions: false, typedefs: false }],
'@typescript-eslint/no-var-requires': 'off'
}
};

20
.gitignore vendored
View File

@@ -1,7 +1,27 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
.DS_Store
dist
dist-ssr
*.local
/cypress/videos/
/cypress/screenshots/
# Editor directories and files
.idea
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
stats.html

1
.husky/.gitignore vendored
View File

@@ -1 +0,0 @@
_

View File

@@ -1,4 +1,4 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
pnpm lint:fix
pnpm lint && pnpm typecheck

View File

@@ -15,5 +15,13 @@ module.exports = {
requireConfig: false, // Require a 'prettierconfig' to format prettier
stylelintIntegration: false, //不让prettier使用stylelint的代码格式进行校验
trailingComma: 'none', // 在对象或数组最后一个元素后面是否加逗号在ES5中加尾逗号
tslintIntegration: false // 不让prettier使用tslint的代码格式进行校验
}
tslintIntegration: false, // 不让prettier使用tslint的代码格式进行校验
overrides: [
{
files: '*.html',
options: {
parser: 'html'
}
}
]
};

View File

@@ -4,7 +4,8 @@
"formulahendry.auto-complete-tag",
"steoates.autoimport",
"formulahendry.auto-rename-tag",
"coenraads.bracket-pair-colorizer",
"coenraads.bracket-pair-colorizer-2",
"naumovs.color-highlight",
"pranaygp.vscode-css-peek",
"mikestead.dotenv",
"editorconfig.editorconfig",

10
.vscode/settings.json vendored
View File

@@ -9,6 +9,8 @@
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
"editor.bracketPairColorization.enabled": true,
"editor.guides.bracketPairs": "active",
"git.enableSmartCommit": true,
"path-intellisense.mappings": {
"@": "${workspaceFolder}/src",
@@ -54,15 +56,19 @@
"[markdown]": {
"editor.defaultFormatter": "yzhang.markdown-all-in-one"
},
"workbench.productIconTheme": "fluent-icons",
"vue3snippets.enable-compile-vue-file-on-did-save-code": false,
"editor.formatOnSave": false,
"material-icon-theme.activeIconPack": "angular",
"material-icon-theme.files.associations": {},
"material-icon-theme.folders.associations": {
"enum": "typescript",
"enums": "typescript",
"store": "context",
"stores": "context",
"composable": "hook",
"composables": "hook",
"business": "core",
"directive": "tools",
"directives": "tools",
"business": "core"
}
}

View File

@@ -2,110 +2,49 @@
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.0.3](https://github.com/honghuangdc/soybean-admin/compare/v0.0.2...v0.0.3) (2021-11-23)
### 0.0.2 (2021-11-21)
### [0.1.1](https://github.com/honghuangdc/soybean-admin/compare/v0.0.5...v0.1.1) (2022-01-20)
### Features
* **component:** 增加剪贴板示例 ([f1cd995](https://github.com/honghuangdc/soybean-admin/commit/f1cd9955d9ef0dd06e6eb0ab88ab6be80db789a3))
* **components:** 添加面包屑 ([c1cdc3a](https://github.com/honghuangdc/soybean-admin/commit/c1cdc3a9ed673d0fd84aa1eaa9fc72468bd5aaf9))
* **components:** 添加图片验证码 ([336c776](https://github.com/honghuangdc/soybean-admin/commit/336c7766f9130619b7076e832d7ade7cbc3049f2))
* **components:** 添加主题配置抽屉,添加暗黑主题 ([a87593f](https://github.com/honghuangdc/soybean-admin/commit/a87593f58a1185d6360b8e49ffe1c9fff768770e))
* **components:** 添加vertical-mix的导航模式下的菜单 ([f24ec1c](https://github.com/honghuangdc/soybean-admin/commit/f24ec1c5326c117e618aed8b3e1867c24fcd84f4))
* **projects:** 布局调整 ([eda87f0](https://github.com/honghuangdc/soybean-admin/commit/eda87f041d5d87ae9612f369608e486a8e563f17))
* **projects:** 菜单数据及组件接入 ([3226a72](https://github.com/honghuangdc/soybean-admin/commit/3226a724be65935ce89fe6ae67f49a20d255c6ac))
* **projects:** 导航栏模式配置:界面实现及主题配置布局调整 ([f002124](https://github.com/honghuangdc/soybean-admin/commit/f002124ee11bc93e6b9955549143b695417e7f8d))
* **projects:** 登录页面实现 ([f1e7cf6](https://github.com/honghuangdc/soybean-admin/commit/f1e7cf608ea7d61dcd24f8780cde9cc4c59658ce))
* **projects:** 多页签绑定路由 ([f29bc05](https://github.com/honghuangdc/soybean-admin/commit/f29bc05dd9f53144ef56440033a6f747c112e83d))
* **projects:** 分析页更新,添加关于页面 ([8e18218](https://github.com/honghuangdc/soybean-admin/commit/8e18218196c52e6a34b96bc313044b6e47886f85))
* **projects:** 工作台页面:添加技术栈官网链接 ([364c64b](https://github.com/honghuangdc/soybean-admin/commit/364c64b4641e48bcf8cc8600680bcaa39a1a9413))
* **projects:** 工作台页面布局 ([4c85569](https://github.com/honghuangdc/soybean-admin/commit/4c85569b764b176c9c3a7f9ba3092ff3567e5512))
* **projects:** 首页更新 ([5c01006](https://github.com/honghuangdc/soybean-admin/commit/5c01006306873944671a4f1d863ced6ba23f6245))
* **projects:** 四种基本布局完成 ([86d4a20](https://github.com/honghuangdc/soybean-admin/commit/86d4a207eef8daf01c6336e8aaedf3aebb90e7a7))
* **projects:** 添加百度地图插件 ([6abe094](https://github.com/honghuangdc/soybean-admin/commit/6abe094ff23f52fdd62c025bce17debd9ea2f907))
* **projects:** 添加多级菜单页面 ([3f49d6d](https://github.com/honghuangdc/soybean-admin/commit/3f49d6db30aee0a6c1007cb00069835b102deb70))
* **projects:** 添加多页签风格:按钮和浏览器两种风格 ([3cfa0f1](https://github.com/honghuangdc/soybean-admin/commit/3cfa0f103cf788e57ee26743e89bf5fe33a09660))
* **projects:** 添加多页签右键菜单 ([d6f5237](https://github.com/honghuangdc/soybean-admin/commit/d6f5237c8c167314d578312dcad7505737f0b4c8))
* **projects:** 添加富文本和markdown编辑器插件及示例页面 ([60c2064](https://github.com/honghuangdc/soybean-admin/commit/60c20647a0d8e6d877a0f23a6e7da05ff09d14a0))
* **projects:** 添加固定路由 ([ff4a09c](https://github.com/honghuangdc/soybean-admin/commit/ff4a09c452c98791f7d67ba5f135e9cf5099c29c))
* **projects:** 添加环境文件env对应的类型 ([4f05095](https://github.com/honghuangdc/soybean-admin/commit/4f050953363b364815a08103047df3fe377d8f56))
* **projects:** 添加判断是否是移动端的hooks ([0a9fba9](https://github.com/honghuangdc/soybean-admin/commit/0a9fba90b5e51fd2d39c47490f49dac7599a9742))
* **projects:** 添加全屏显示 ([0a1711d](https://github.com/honghuangdc/soybean-admin/commit/0a1711d5b1d8e863d24a55690fa8696c79acaaf9))
* **projects:** 添加项目配置拷贝 ([2d9d5c0](https://github.com/honghuangdc/soybean-admin/commit/2d9d5c0353ca6d2dc86965fe383bf2925a47d239))
* **projects:** 添加exception页面403404500 ([d012c4e](https://github.com/honghuangdc/soybean-admin/commit/d012c4ecf2cd325567d419684153955560ce90da))
* **projects:** 添加multiTab标签页 ([eec0b36](https://github.com/honghuangdc/soybean-admin/commit/eec0b36f594e0d337f13d3d0ce30b1f768614f5c))
* **projects:** 添加reload context ([03ebd49](https://github.com/honghuangdc/soybean-admin/commit/03ebd49c8639bf7f4f88b1a0523d2caec2d248ee))
* **projects:** 添加svg logo自适应主题颜色 ([e1e5579](https://github.com/honghuangdc/soybean-admin/commit/e1e5579e8fe71ed97e2ce11d907705157874bd71))
* **projects:** 添加swiper插件 ([27f600c](https://github.com/honghuangdc/soybean-admin/commit/27f600c4677afeacd3e67f189df139db5cde0aa3))
* **projects:** 头部添加菜单折叠按钮和github地址 ([3ec1fc8](https://github.com/honghuangdc/soybean-admin/commit/3ec1fc8f0c23fcba56d4bffb20028948f985659c))
* **projects:** 项目初始化搭建集成eslint规范集成代码提交规范 ([6754da4](https://github.com/honghuangdc/soybean-admin/commit/6754da4d83976a02eced801220320d8c9aa1da85))
* **projects:** 新增导航模式配置 ([49c2dc4](https://github.com/honghuangdc/soybean-admin/commit/49c2dc4f23913c9ef86ee046c6ae53d4406cbca7))
* **projects:** 新增顶部菜单 ([221d2cc](https://github.com/honghuangdc/soybean-admin/commit/221d2cc02dfdf3f78cb415f26c88f1f274942222))
* **projects:** 新增多页签缓存功能 ([d86f891](https://github.com/honghuangdc/soybean-admin/commit/d86f891c64f802bbca50e31e3e4f7ccdad65eed1))
* **projects:** 新增高德地图插件 ([ea82edc](https://github.com/honghuangdc/soybean-admin/commit/ea82edc1146fefa208bb9e6f985dfb000d197d16))
* **projects:** 新增视频插件 ([6a692d4](https://github.com/honghuangdc/soybean-admin/commit/6a692d4f99942389cd2a5e72ebc852a92e80f742))
* **projects:** 新增腾讯地图插件 ([3f02c21](https://github.com/honghuangdc/soybean-admin/commit/3f02c215c54fde4c85bf13e92c2620553d5a1840))
* **projects:** 新增文档页面 ([7654b2a](https://github.com/honghuangdc/soybean-admin/commit/7654b2adf3d0bf051d13b401dfa3534ca7ee3e0c))
* **projects:** 新增主题配置 ([ed67b79](https://github.com/honghuangdc/soybean-admin/commit/ed67b797c215fe165808505f4b0b9400f3182383))
* **projects:** 新增主题配置:页面功能 ([8601ce2](https://github.com/honghuangdc/soybean-admin/commit/8601ce2ea184455fcba1d17d759cd4b933b31d96))
* **projects:** 新增主题颜色配置 ([d93493b](https://github.com/honghuangdc/soybean-admin/commit/d93493b91ca856573c306e890e8c6f6a46b5bda3))
* **projects:** 增加Icon以及打印功能示例 ([d5bce26](https://github.com/honghuangdc/soybean-admin/commit/d5bce26454c7d7c9da29e01675624f985755779f))
* **projects:** 主题配置:页面功能和页面显示 ([a0392b3](https://github.com/honghuangdc/soybean-admin/commit/a0392b3d28f89f2b5fcf5b4d2b82ab7a068a23b8))
* **projects:** vertical-mix的导航模式的二级菜单显示 ([736f314](https://github.com/honghuangdc/soybean-admin/commit/736f3146cb7cb3f56e06a8185ec8532f25c40b13))
* **route:** 增加功能示例模块 ([efd29bc](https://github.com/honghuangdc/soybean-admin/commit/efd29bc331f630b57eab800bba08b22c53115d76))
* **projects:** theme store完成 ([bf020a8](https://github.com/honghuangdc/soybean-admin/commit/bf020a82580e6b1fbda1cc1e0bd6176770434884))
* **projects:** 主题配置抽屉: 迁移其他功能 ([6d132c5](https://github.com/honghuangdc/soybean-admin/commit/6d132c59770e925cfc61217dcefa5b4d937604df))
* **projects:** 主题配置抽屉:迁移暗黑模式、布局模式、添加颜色选择面板 ([912bfdf](https://github.com/honghuangdc/soybean-admin/commit/912bfdf4390ab624d3f8e343be88e8c1cf7ab5b6))
* **projects:** 创建自定义布局组件SoybeanLayout ([0653fb1](https://github.com/honghuangdc/soybean-admin/commit/0653fb144fe9d49f24ef4fe6e4a58de6de342b78))
* **projects:** 初始化加载效果:应用主题颜色 ([035fa11](https://github.com/honghuangdc/soybean-admin/commit/035fa114c9fd638cf467e6a73a8e4c558f503deb))
* **projects:** 图标选择器增加扩展树形 ([041012b](https://github.com/honghuangdc/soybean-admin/commit/041012b3ee04d960c1e38895839225613f7af377))
* **projects:** 增加Icon选择器组件 ([9472b51](https://github.com/honghuangdc/soybean-admin/commit/9472b51811f419e9139de81c73f2c71d170700c2))
* **projects:** 增加全局搜索菜单功能 ([b9ce691](https://github.com/honghuangdc/soybean-admin/commit/b9ce69130b12712013228326f883e2d973e4e46a))
* **projects:** 增加项目文档外链 ([1901a0b](https://github.com/honghuangdc/soybean-admin/commit/1901a0bfb7bfa516dfda552675397ddec96b8d4b))
* **projects:** 多级路由的所有子路由转换成二级路由 ([85b55bb](https://github.com/honghuangdc/soybean-admin/commit/85b55bb37a0a06e2645b96ed81aefe463127121a))
* **projects:** 引入mockjs ([9bc682d](https://github.com/honghuangdc/soybean-admin/commit/9bc682dae878c084e38a0e2c9a4a2de171023c48))
* **projects:** 新增BasicLayout布局 ([006467a](https://github.com/honghuangdc/soybean-admin/commit/006467a0626f427da3f516d90c15bf1e1eef0e55))
* **projects:** 添加cryptojs对本地缓存数据进行加密 ([7a0648d](https://github.com/honghuangdc/soybean-admin/commit/7a0648dba55a98f61f4d81696307d86c82a1d34d))
* **projects:** 添加NaiveProvider组件 ([c804b21](https://github.com/honghuangdc/soybean-admin/commit/c804b21ceb92133c6ea7cc64c87521cc164e40ce))
* **projects:** 添加侧边菜单 ([e25afe2](https://github.com/honghuangdc/soybean-admin/commit/e25afe2fadfe86b9330ee02190a4e40b8321714c))
* **projects:** 添加头部折叠按钮 ([a090d39](https://github.com/honghuangdc/soybean-admin/commit/a090d398fc071e246b92d0da80883cf5cbedba0e))
* **projects:** 添加常用组件、composables函数 ([230a50a](https://github.com/honghuangdc/soybean-admin/commit/230a50a4cf4d2ebb62b19d6324234243cf6b2f0d))
* **projects:** 添加抽屉 ([10e4d81](https://github.com/honghuangdc/soybean-admin/commit/10e4d81bd6a0b35d8cfb4f7a1e981f8ef6ab87cc))
* **projects:** 添加表格页面示例 ([51c744c](https://github.com/honghuangdc/soybean-admin/commit/51c744c8e2c8ed9691e92e35b6a88582f22c30d8))
* **projects:** 添加路由跳转浏览器新标签 ([987cef3](https://github.com/honghuangdc/soybean-admin/commit/987cef336338987f2e6f0d5aba8f6d4602b297ca))
* **projects:** 登录页面开始迁移 ([f5a36a0](https://github.com/honghuangdc/soybean-admin/commit/f5a36a05cb626ec62115283f1d2c534b2a787bdd))
* **projects:** 细节完善 ([cc290ac](https://github.com/honghuangdc/soybean-admin/commit/cc290accc29282e9ba655356e2695b6ca4b23605))
* **projects:** 细节完善、迁移页面 ([ce531ce](https://github.com/honghuangdc/soybean-admin/commit/ce531ce5dda0b4a1024aa6bd3d68835b59760d57))
* **projects:** 菜单搜索增加大小写转换 ([2907868](https://github.com/honghuangdc/soybean-admin/commit/29078689b0652cf4ae852c93d8601a157579adcc))
* **projects:** 请求拦截器添加刷新token ([839b82b](https://github.com/honghuangdc/soybean-admin/commit/839b82ba8b052b02e24bcfe6da54160609a4fd4b))
* **projects:** 路由页面跳转权限完成 ([0d2a562](https://github.com/honghuangdc/soybean-admin/commit/0d2a5629e89c73a32d6c79f04b51543e1513e006))
* **projects:** 迁移多页签 ([28efbdb](https://github.com/honghuangdc/soybean-admin/commit/28efbdbc70733d22011a0eee084d35711429d188))
* **projects:** 迁移登录完成 ([b93b80c](https://github.com/honghuangdc/soybean-admin/commit/b93b80cb4b35268dfb6a09517a2494af24748dac))
* **projects:** 集成naiveUI主题配置将css vars添加至html ([2c19684](https://github.com/honghuangdc/soybean-admin/commit/2c196841bd8527d7acccefe6a7545e0a49d532f7))
* **projects:** 面包屑 ([09c7658](https://github.com/honghuangdc/soybean-admin/commit/09c7658c21c7dda461dbb528e85b638b5a7dfacd))
### Bug Fixes
* **多页签:** 在pc模式下右键某个多页签会切换路由 ([a4394dc](https://github.com/honghuangdc/soybean-admin/commit/a4394dc3ee81ea2abc9a9fd243714309a1b4e6ab))
* **components:** 修复按钮Tab自适应主题颜色 ([3d1f419](https://github.com/honghuangdc/soybean-admin/commit/3d1f41925d54ebe89f1bbbdfe916be59bb97c9cf))
* **components:** 修复BaseLayout的HorizontalLayout ([0344f46](https://github.com/honghuangdc/soybean-admin/commit/0344f46c9377acfb52c28cf373a5416845d1aa1b))
* **components:** 修复tab组件适应暗黑主题模式 ([2fe3d27](https://github.com/honghuangdc/soybean-admin/commit/2fe3d27a36b641339fd87eaa7acad8c3424b97b4))
* **components:** tab组件在黑暗模式下泛白的颜色问题以及chromeTab的重叠问题 ([6797dbf](https://github.com/honghuangdc/soybean-admin/commit/6797dbf1b0617dcca662a25cf663d93dc4ad5807))
* **deps:** 降低vite版本新版本有些许问题 ([b429c8b](https://github.com/honghuangdc/soybean-admin/commit/b429c8b8ca61191c6bed1c52742ddd5fcf9ddc3a))
* **deps:** 去除图片验证码依赖 ([76a1afa](https://github.com/honghuangdc/soybean-admin/commit/76a1afae4e87c3c08f7fd31b20323c0456565f64))
* **deps:** vite依赖放入devDependencies ([7527b1f](https://github.com/honghuangdc/soybean-admin/commit/7527b1f07cdc2d82ec0104ed7317c7ff731da0b7))
* **hooks:** 修复登录页切换登录页参数丢失问题 ([789855a](https://github.com/honghuangdc/soybean-admin/commit/789855a3786623893aa55a2f6c977155394a8a44))
* **hooks:** 修复toLogin函数导致登录重定向地址过多 ([b4adf67](https://github.com/honghuangdc/soybean-admin/commit/b4adf678a4f96f670f9cbdcaebe21378fa94c77c))
* **projects:** 布局修复:从填充屏幕高的页面切换至滚动页面导致布局坍塌 ([2fdb5f5](https://github.com/honghuangdc/soybean-admin/commit/2fdb5f563f7d9fa00d8e5343d992342ff34e3a5a))
* **projects:** 更正dashboard的布局文件 ([31fda0c](https://github.com/honghuangdc/soybean-admin/commit/31fda0ce992457972205db3a39e4c7327d21c087))
* **projects:** 关于页面:开发环境依赖更正 ([3b3baf9](https://github.com/honghuangdc/soybean-admin/commit/3b3baf93ee36423bfe4fc0ab24eda0f99ce92363))
* **projects:** 腾讯地图容器高自适应 ([d7054c5](https://github.com/honghuangdc/soybean-admin/commit/d7054c599b1ce59a123667443863a8054ba19a90))
* **projects:** 头部logo链接更正 ([5d8c3f5](https://github.com/honghuangdc/soybean-admin/commit/5d8c3f54a3e414cdeff35bf5ddb2a1e13d7d703a))
* **projects:** 完善侧边菜单展开逻辑 ([b5f0512](https://github.com/honghuangdc/soybean-admin/commit/b5f05128abcf2403181b7cc7800d9e6593844657))
* **projects:** 修复百度地图sdk地址 ([9a97d23](https://github.com/honghuangdc/soybean-admin/commit/9a97d23c755b7fa7c3166d783e99cac10a0a9753))
* **projects:** 修复登录的重定向地址 ([f97f226](https://github.com/honghuangdc/soybean-admin/commit/f97f2266566164cad912e7ffcdebee1c1b2f4324))
* **projects:** 修复登录页刷新跳404 ([358d4e8](https://github.com/honghuangdc/soybean-admin/commit/358d4e8a1992aa040b909ae580470a0fd2142f5f))
* **projects:** 修复顶部加载条主题 ([ea5917d](https://github.com/honghuangdc/soybean-admin/commit/ea5917d2258356bbcb296420ea1d017f5ad05b7a))
* **projects:** 修复多级菜单页面multitab显示问题 ([f0474bd](https://github.com/honghuangdc/soybean-admin/commit/f0474bd96104dcca332d35d8202eedc3df00eb10))
* **projects:** 修复多页签删除功能 ([99adbc5](https://github.com/honghuangdc/soybean-admin/commit/99adbc5a30c9128d005dc8096d58c5b320f67fef))
* **projects:** 修复分析页折线图表布局问题 ([43b832b](https://github.com/honghuangdc/soybean-admin/commit/43b832bee0dc1d852f3e435f16eaa37f27b0f66c))
* **projects:** 修复富文本编辑器在亮色主题下全屏后背景色丢失 ([4ab7702](https://github.com/honghuangdc/soybean-admin/commit/4ab7702186e1121e50f1d4725b73f28498aba312))
* **projects:** 修复没有子页面的路由写法问题 ([b80c224](https://github.com/honghuangdc/soybean-admin/commit/b80c2246641d44b9ad35dfbfb3d17500cfcb6e43))
* **projects:** 修复同时显示两种multiTab ([5be2e2a](https://github.com/honghuangdc/soybean-admin/commit/5be2e2a2e5658e09c47a4dc1331129e14ed6d761))
* **projects:** 修复页面滚动和页面100%视高占比 ([fa2cc78](https://github.com/honghuangdc/soybean-admin/commit/fa2cc789371999de6b2f698ba7ed87a4d740ad37))
* **projects:** 修复页面滚动行为 ([57e00e6](https://github.com/honghuangdc/soybean-admin/commit/57e00e64177bc9925ca95785335786836571766a))
* **projects:** 修复页面缓存 ([fa0a907](https://github.com/honghuangdc/soybean-admin/commit/fa0a907941a90ed72288205fef14b0923a0ffd8e))
* **projects:** 修复页面缓存,添加多页签删除 ([2489374](https://github.com/honghuangdc/soybean-admin/commit/248937479cc9ccb936116300d628dfa734014b37))
* **projects:** 修复在暗黑模式下第一次进入网页不会触发暗黑模式监听 ([c4a652e](https://github.com/honghuangdc/soybean-admin/commit/c4a652e21e4c3e2ee6e86e04e46d5dccd579d584))
* **projects:** 修复主题配置 ([ff24fda](https://github.com/honghuangdc/soybean-admin/commit/ff24fda5ee12074e7130122ca311d0ce174cc184))
* **projects:** 修复主题相关,自适应操作系统暗黑模式 ([bfa42d7](https://github.com/honghuangdc/soybean-admin/commit/bfa42d769d464dbc8d51689c5fc8c59a348941fb))
* **projects:** 修复globalFooter适应暗黑模式 ([93f08d9](https://github.com/honghuangdc/soybean-admin/commit/93f08d90671b3ddfbdb969d5b13f4a3fa9903a19))
* **projects:** 修复multiTab关闭逻辑添加关闭左边和右边的标签右键操作 ([ed90cb8](https://github.com/honghuangdc/soybean-admin/commit/ed90cb8f8e8d3bbf594757caa950f8521869ece4))
* **projects:** 修复tab过多时样式坍塌添加tab横向滚动 ([0ec4d21](https://github.com/honghuangdc/soybean-admin/commit/0ec4d218e365f54ab0c138a955dcd990cbf2d9bc))
* **projects:** 修复tab在移动端无法点击 ([1a76de0](https://github.com/honghuangdc/soybean-admin/commit/1a76de04463b0344b39c09df0e0762825d66653b))
* **projects:** 修复vertical sider自适应主题 ([9097fa3](https://github.com/honghuangdc/soybean-admin/commit/9097fa386687d077a480033d9978cfbd59e0e3a0))
* **projects:** 修复vertical-mix导航模式的二级菜单显示问题 ([6f286e6](https://github.com/honghuangdc/soybean-admin/commit/6f286e674724db12d6c5a4339ba6f3db720b781d))
* **projects:** 页面各部分背景颜色添加自然过渡 ([1c5fdca](https://github.com/honghuangdc/soybean-admin/commit/1c5fdca59637c141ae1f0b47d9bcf05788a631c2))
* **projects:** wangEditor在暗黑模式下的背景色问题 ([a7de314](https://github.com/honghuangdc/soybean-admin/commit/a7de31404508a2d4436435d06cdb63f851a86029))
* **types:** 数据类型 EnumDataType.boolean 为 [object Boolean] ([e9b5560](https://github.com/honghuangdc/soybean-admin/commit/e9b55608f960c0d3cdeca91af6f2777a23fd20dd))
* **types:** 修复naive组件回调函数参数类型错误 ([667282f](https://github.com/honghuangdc/soybean-admin/commit/667282f81a8822006242d612a08ac59571e3508e))
* **types:** 修复TS类型错误 ([45d31a0](https://github.com/honghuangdc/soybean-admin/commit/45d31a0f5625784423bea463b2373b0cd35b37f5))
* **utils:** utils函数名称更正 ([68f4d01](https://github.com/honghuangdc/soybean-admin/commit/68f4d012cc3cce1df5cb61dfa0212126ea0b202e))
### Performance Improvements
* **projects:** 添加windicss指定的扫描目录提升构建性能 ([8e6b0b2](https://github.com/honghuangdc/soybean-admin/commit/8e6b0b299d2ef50f2b85e67b7a1aa7fd2ac1bce1))
* **deps:** 降低vite版本 ([c9c5ca9](https://github.com/honghuangdc/soybean-admin/commit/c9c5ca9989eddb084f2706155473123c5dcfc334))
* **projects:** 修复redirect-not-found子路由 ([5bfb819](https://github.com/honghuangdc/soybean-admin/commit/5bfb8199b463d9ca6430577b5c493c0b78967aa9))
* **projects:** 修复vertical-mix布局、重构初始化的loading ([579e074](https://github.com/honghuangdc/soybean-admin/commit/579e07400e1b9a52934ed808a37c8579a41e8e74))
* **projects:** 修复网络请求错误空信息的提示 ([ff9216b](https://github.com/honghuangdc/soybean-admin/commit/ff9216b621aaef0a8203386fa1c3ca5477a2edea))
* **projects:** 修复面包屑数据 ([28b5d22](https://github.com/honghuangdc/soybean-admin/commit/28b5d224010a28669ad3a1919fc49f6e2dc808cd))
* **projects:** 去除Layout组件冗余代码 ([0e783bc](https://github.com/honghuangdc/soybean-admin/commit/0e783bcf7be0b3a083fe950adfb0afc72b510f97))
* **projects:** 请求相关细节修复 ([2ad1ad3](https://github.com/honghuangdc/soybean-admin/commit/2ad1ad32b8410d84902a33d825032c282ca6df86))

21
LICENSE
View File

@@ -1,21 +0,0 @@
MIT License
Copyright (c) 2021 Soybean
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -1,18 +1,13 @@
<div align="center">
<a href="https://github.com/honghuangdc/soybean-admin">
<img alt="SoybeanAdmin Logo" width="200" height="200" src="https://s3.bmp.ovh/imgs/2021/09/088571214c76b1e5.png">
</a><br /><br />
<h1>Soybean Admin</h1>
<br />
<img src="https://i.loli.net/2021/11/24/x5lLfuSnEawBAgi.png"/>
<h1>Soybean Admin Thin</h1>
</div>
[![license](https://raw.githubusercontent.com/honghuangdc/project-assets/main/img/license.svg)](LICENSE)
[![license](https://img.shields.io/badge/license-MIT-green.svg)](./LICENSE)
## 简介
Soybean Admin 是一个基于 Vue3、Vite、Naive UI、TypeScript 的免费中后台模版,它使用了最新的前端技术栈,内置丰富的插件,有着极高的代码规范,开箱即用的中后台前端解决方案,也可用于学习参考
Soybean Admin Thin 是Soybean Admin的精简版
## 特性
@@ -26,25 +21,26 @@ Soybean Admin 是一个基于 Vue3、Vite、Naive UI、TypeScript 的免费中
- [soybean-admin](https://soybean.pro/)
<p align="center">
## 文档
<img alt="SoybeanAdmin" width="100%" src="https://raw.githubusercontent.com/honghuangdc/project-assets/main/img/02.png">
<img alt="SoybeanAdmin" width="100%" src="https://raw.githubusercontent.com/honghuangdc/project-assets/main/img/03.png">
<img alt="SoybeanAdmin" width="100%" src="https://raw.githubusercontent.com/honghuangdc/project-assets/main/img/01.png">
<img alt="SoybeanAdmin" width="100%" src="https://raw.githubusercontent.com/honghuangdc/project-assets/main/img/04.png">
<img alt="SoybeanAdmin" width="100%" src="https://raw.githubusercontent.com/honghuangdc/project-assets/main/img/05.png">
</p>
- [项目文档](https://docs.soybean.pro)
### 代码仓库
**github**https://github.com/honghuangdc/soybean-admin
- [github](https://github.com/honghuangdc/soybean-admin)
**gitee**https://gitee.com/honghuangdc/soybean-admin
- [gitee](https://gitee.com/honghuangdc/soybean-admin)
## 项目示例图
![](https://i.loli.net/2021/11/24/pIhTKP7fdCqbVHl.png)
![](https://i.loli.net/2021/11/24/gxRwsLnKi6IVp7C.png)
![](https://i.loli.net/2021/11/24/UmVfjSJbxH6iYc2.png)
![](https://i.loli.net/2021/11/24/Uot1bcfGXiF726T.png)
![](https://i.loli.net/2021/11/24/WzOIvlgJZaUtGm7.png)
### 使用 Gitpod
@@ -52,10 +48,6 @@ Soybean Admin 是一个基于 Vue3、Vite、Naive UI、TypeScript 的免费中
[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/honghuangdc/soybean-admin)
## 文档
[项目相关文档](./doc)
## 安装使用
- 克隆代码
@@ -102,9 +94,10 @@ pnpm i -g commitizen
支持现代浏览器, 不支持 IE
| [<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/)</br>IE | [<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/)</br>Edge | [<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/)</br>Firefox | [<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/)</br>Chrome | [<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/)</br>Safari |
| [<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/)IE | [<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/)Edge | [<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/)Firefox | [<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/)Chrome | [<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/)Safari |
| :-: | :-: | :-: | :-: | :-: |
| not support | last 2 versions | last 2 versions | last 2 versions | last 2 versions |
## 开源作者
[@Soybean](https://github.com/honghuangdc)
@@ -113,15 +106,18 @@ pnpm i -g commitizen
`Soybean Admin` 是完全开源免费的项目,在帮助开发者更方便地进行中大型管理系统开发,同时也提供 QQ 交流群使用问题欢迎在群内提问。
- QQ 群 `711301266`
<div style="text-align:left;">
<img src="https://raw.githubusercontent.com/honghuangdc/project-assets/main/img/qq_qrcode.JPG" style="width:200px" />
- 微信交流群:
<div style="text-align:left">
<img src="https://s2.loli.net/2021/12/29/m65oExs7yHcPbKZ.jpg" style="width:200px" />
</div>
- QQ 群 `711301266`
- 本人微信号honghuangdc欢迎来技术交流。
<div style="text-align:left">
<img src="https://i.loli.net/2021/11/24/1J6REWXiHomU2kM.jpg" style="width:200px" />
</div>
- 本人微信号honghuangdc欢迎来技术交流业务咨询。
## License

View File

@@ -3,6 +3,6 @@ import dayjs from 'dayjs';
/** 项目构建时间 */
const PROJECT_BUILD_TIME = JSON.stringify(dayjs().format('YYYY-MM-DD HH:mm:ss'));
export default {
export const define = {
PROJECT_BUILD_TIME
};

5
build/env/index.ts vendored
View File

@@ -1,5 +0,0 @@
import dotenv from 'dotenv';
const { parsed: viteEnv } = dotenv.config(); // 加载环境
export default viteEnv;

View File

@@ -1,5 +1,2 @@
import viteEnv from './env';
import plugins from './plugins';
import define from './define';
export { viteEnv, plugins, define };
export * from './plugins';
export * from './define';

View File

@@ -1,12 +1,17 @@
import { loadEnv } from 'vite';
import type { ConfigEnv, PluginOption } from 'vite';
import { minifyHtml, injectHtml } from 'vite-plugin-html'; // html插件(使用变量、压缩)
import viteEnv from '../env';
export default [
minifyHtml(),
injectHtml({
injectData: {
title: viteEnv.VITE_APP_TITLE,
appName: viteEnv.VITE_APP_TITLE_LABEL
}
})
];
export default (config: ConfigEnv): PluginOption[] => {
const viteEnv = loadEnv(config.mode, `.env.${config.mode}`);
return [
minifyHtml(),
injectHtml({
injectData: {
appName: viteEnv.VITE_APP_NAME,
appTitle: viteEnv.VITE_APP_TITLE
}
})
];
};

View File

@@ -4,7 +4,8 @@ import Components from 'unplugin-vue-components/vite'; // 从指定目录自动
export default [
Components({
dts: false,
resolvers: [IconsResolver({ componentPrefix: 'icon' })]
}),
Icons()
Icons({ scale: 1, defaultClass: 'inline-block' })
];

View File

@@ -1,9 +1,17 @@
import type { ConfigEnv, PluginOption } from 'vite';
import vue from './vue';
import html from './html';
import iconify from './iconify';
import windicss from './windicss';
import mock from './mock';
import visualizer from './visualizer';
const plugins = [vue, ...html, ...iconify, windicss, visualizer];
export function setupVitePlugins(configEnv: ConfigEnv): (PluginOption | PluginOption[])[] {
const plugins = [vue, ...html(configEnv), ...iconify, windicss, mock];
export default plugins;
if (configEnv.command === 'build') {
plugins.push(visualizer);
}
return plugins;
}

9
build/plugins/mock.ts Normal file
View File

@@ -0,0 +1,9 @@
import { viteMockServe } from 'vite-plugin-mock';
export default viteMockServe({
mockPath: 'mock',
injectCode: `
import { setupMockServer } from '../mock';
setupMockServer();
`
});

View File

@@ -1,7 +1,6 @@
import { visualizer } from 'rollup-plugin-visualizer';
export default visualizer({
open: true,
gzipSize: true,
brotliSize: true
});

View File

@@ -1,47 +0,0 @@
### 1.interface和type
##### interface和type使用优先级能用interface表示的类型就用interface。
### 2.请求函数
#### api接口
统一以 **fetch** 开头,例如:
```typescript
/**
* 获取用户信息
* @param id - 用户唯一标识id
*/
function fetchUserInfo(idstring) {
// ***
}
/**
* 删除列表项
* @param id - 列表id
*/
function fetchDeleteListItem(idstring) {
// ***
}
```
#### middleware中间件
统一以 **handle** 开头,例如
```typescript
/**接口返回的用户信息 */
interface ResponseUserInfo {
userId: string;
userName: string;
userAge: number;
}
/**
* 获取用户信息 中间件
@param data - 返回的用户信息
*/
function handleUserInfo(data: ResponseUserInfo): UserInfo {
// ***
}
```

View File

@@ -1,35 +0,0 @@
### css书写顺序
1. 定位属性:
`position display float left top right bottom overflow clear z-index`
2. 自身属性:
`width height padding border margin background`
3. 文字样式:
`font-family font-size font-style font-weight font-varient color`
4. 文本属性:
`text-align vertical-align text-wrap text-transform text-indent text-decoration letter-spacing word-spacing white-space text-overflow`
5. css3中新增属性
`content box-shadow border-radius transform`
#### class类名的顺序
1. 自定义的class类名(遵循BEM命名法)
2. css插件提供的类名按照以上的css属性对应的顺序
例如自定义类名结合tailwind css
<div class="demo-container absolute flex justify-center items-center left-10px top-12px overflow-hidden wh-full p-10px border-1px border-[#f00] m-24px bg-[#fff] text-32px text-[#0f0]"></div>
<style>
.demo-container {
box-shadow: 2px 0 8px 0 rgb(29 35 41 / 5%);
}
</style>

View File

@@ -1,41 +0,0 @@
### iconify用法
#### 一、静态用法:直接用图标的组件名称
1. 安装vscode智能提示的插件: Iconify IntelliSense
2. 找图标:网址 https://icones.js.org/ 或者 vscode安装 icones插件
3. 确定图标名字:找到图标后复制名字 如:**'mdi:emoticon'** 组件为: `<icon-mdi:emoticon />`, icon-为设置的前缀
4. 设置样式同html标签一样直接应用style属性或者class属性; 通过设置color和font-size属性设置对应的颜色和大小
#### 二、多个图标动态渲染
1. 确定图标名字,如:'mdi:emoticon'
2. 引入Icon组件
`import { Icon } from '@iconify/vue';`
3. 动态渲染
`<Icon icon="mdi:emoticon" />`
*psIcon组件属性 https://docs.iconify.design/icon-components/vue/*
#### 三、结合naiveUI组件动态渲染
1. 确定图标名字,如:**'mdi:emoticon'**
2. 引入vue的h函数
`import { h } from 'vue';`
3. 引入Icon组件
`import { Icon } from '@iconify/vue';`
4. 动态渲染
`() => h(Icon, { icon: 'mdi:emoticon', style: { color: '#f00', fontSize: '16px' } })`
*ps@/uitls已封装好了函数iconifyRender*

View File

@@ -1,209 +0,0 @@
### script-setup写法
#### 第一部分
##### template
#### 第二部分
##### script
##### 一、import的顺序, 依次按照下面的顺序。
1. vue模块
```typescript
import { } from 'vue';
```
2. vue相关类型
```typescript
import type { } from 'vue';
```
3. vue-router模块
```typescript
import { } from 'vue-router';
```
4. vue-router相关类型
```typescript
import type { } from 'vue-router';
```
5. UI框架模块
```typescript
import { } from 'naive-ui';
```
6. UI框架相关类型
```typescript
import type { } from 'naive-ui';
```
7. 第三方依赖
```typescript
import BScroll from 'bscroll';
```
8. 第三方依赖相关类型
```typescript
import type { } from 'bscroll';
```
9. @/enum
```typescript
import { } from '@/enum';
```
10. @/setting
```typescript
import { } from '@/setting';
```
11. @/plugins
```typescript
import { } from '@/plugins';
```
12. @/layouts
```typescript
import { } from '@/layouts';
```
13. @/views
```typescript
import { } from '@/views';
```
14. @/components
```typescript
import { } from '@/components';
```
15. @/hooks
```typescript
import { } from '@/hooks';
```
16. @/store
```typescript
import { } from '@/store';
```
17. @/context
```typescript
import { } from '@/context';
```
18. @/router
```typescript
import { } from '@/router';
```
19. @/service
```typescript
import { } from '@/service';
```
20. @/utils
```typescript
import { } from '@/utils';
```
21. @/interface
```typescript
import { } from '@/interface';
```
22. @/assets
```typescript
import { } from '@/assets';
```
23. 相对路径依赖
```typescript
import { } from './components';
```
##### 二、TS类型声明
```typescript
interface Props {
/**姓名 */
name: string;
/**年龄 */
age?: number;
}
interface Emits {
/**
* 删除事件
* @param id - 删除项的id
*/
(e: 'delete', id: number): void;
}
```
##### 三、defineProps、defineEmits、withDefaults
1. 定义属性,如:
```typescript
const props = withDefaults(defineProps<Props>(), {
age: 24
});
```
其中name是必须的属性age是可选属性通过withDefaults添加默认值
2. 定义emit事件
```typescript
const emit = defineEmits<Emits>();
```
##### 四、响应式use函数
有些use函数需要传入响应式的变量参数时则书写在声明的变量下面。
```typescript
const router = useRouter();
const route = useRoute();
```
```typescript
/**dom引用 */
const domRef = ref<HTMLElement | null>(null);
const { height: domRefHeight } = useElementSize(domRef); //获取domRef的响应式高度
```
##### 五、变量、函数声明
##### 六、vue生命周期函数、nextTick执行
##### 七、defineExpose

View File

@@ -1,72 +0,0 @@
### 命名法:
#### 1.驼峰命名法(小驼峰)
**getUser**
#### 2.帕斯卡命名法(大驼峰)
**GlobalHeader**
#### 3.短横线命名法
**user-center**
#### 4.下划线命名法
**MAX_LENGTH**
### 文件、文件夹命名:
1. 文件夹作为**路由页面**时用小写字母,包含多个单词时,单词之间建议使用半角的连词线 ( - ) 分隔, 即**短横线命名法**此时vue文件为**index.vue**。
2. 文件夹作为**vue组件**时用**大写驼峰命名法**。
3. 文件作为**vue组件**时用**大写驼峰命名法**。
4. 文件作为**use函数**时用**小驼峰命名法**。
5. 其余文件用**短横线命名法**。
### 变量命名:
#### 命名方式 : 小驼峰式命名方法
**命名规范 : 类型+对象描述的方式,如果没有明确的类型,就可以使前缀为名词**
动词 | 含义 | 返回值
---|---|---
can | 判断是否可执行某个动作 | 函数返回一个布尔值。true可执行false不可执行。
has | 判断是否含有某个值 | 函数返回一个布尔值。true含有此值false不含有此值。
is | 判断是否为某个值 | 函数返回一个布尔值。true为某个值false不为某个值。
get | 获取某个值 | 函数返回一个非布尔值。
set | 设置某个值 | 无返回值、返回是否设置成功或者返回链式对象。
```javascript
/** 是否可读 */
function canRead(){
return true;
}
/** 获取姓名 */
function getName(){
return this.name;
}
```
### 常量
#### 命名方法 : 使用大写字母和下划线来组合命名,下划线用以分割单词。
```javascript
const MAX_COUNT = 10;
const URL = 'http://www.baidu.com';
```
### TS类型接口interface和type
##### 命名方法:大写驼峰
```typescript
interface PersonInfo {
/**姓名 */
name: string;
/**性别 '0':男; '1': 女; '2': 未知 */
gender: '0' | '1' | '2';
/**年龄 */
age: 25;
}
```

View File

@@ -1,101 +0,0 @@
## 目录规范
```javascript
qitan-pc
├── build //vite构建相关配置和插件
├── define //定义的全局常量通过vite构建时注入
├── env //.env环境文件内容加载插件
└── plugins //构建插件
├── html.ts //html插件(注入变量,压缩代码等)
├── iconify.ts //iconify图标插件
├── visualizer.ts //构建的依赖大小占比分析插件
├── vue.ts //vue相关vite插件
└── windicss.ts //css框架插件
├── doc //项目相关说明文档
├── public //公共目录
├── resource //资源文件夹(不会被打包)
└── favicon.ico //网站标签图标
├── src
├── assets //静态资源
├── components //全局组件
├── business //业务相关组件
├── common //公共组件
└── custom //自定义组件
├── context //全局上下文(通过provide和inject实现)
├── app //从app.vue注入的上下文
└── part //局部组件注入的上下文
├── enum //TS枚举
├── animate.ts //动画枚举
├── business.ts //业务相关枚举
├── common.ts //通用枚举
├── route.ts //路由相关枚举
├── storage.ts //存储相关枚举
└── theme.ts //系统主题配置相关枚举
├── hooks //组合式的钩子函数hooks
├── business //业务相关hooks
└── common //通用hooks
├── interface //TS类型接口
├── business.ts //业务相关类型接口
├── common.ts //通用类型接口
└── theme.ts //系统主题配置相关类型接口
├── layouts //布局组件
├── BasicLayout //基本布局(包含全局头部、侧边栏、底部等公共部分)
├── BlankLayout //空白布局组件(单个页面)
└── RouterViewLayout //路由组件(用于多级路由之间的桥接)
├── plugins //插件
└── dark-mode.ts //windicss暗黑模式插件
├── router //vue路由
├── modules //路由页面(按模块划分)
├── permission //路由权限(路由守卫)
├── routes //声明的路由
└── setup //路由挂载函数
├── service //网络请求
├── api //接口api
├── middleware //请求结果的处理中间件
└── request //封装的请求函数
├── settings //项目初始配置
└── theme.ts //项目主题初始配置
├── store //状态管理
└── modules //状态管理划分的模块
├── styles //样式
├── css //css
└── scss //scss
├── typings //TS类型声明文件(*.d.ts)
├── utils //全局工具函数
├── auth //用户鉴权
├── common //通用工具函数
├── package //npm依赖
├── router //路由
├── request //请求工具函数
└── storage //存储
├── views //页面
├── about
├── component
├── dashboard
├── document
├── multi-menu
└── system //系统内置页面:登录、异常页等
├── App.vue //vue文件入口
├── AppProvider.vue //配置naive UI的vue文件(国际化,loadingBar、message等组件)
└── main.ts //项目入口ts文件
├── .cz-config.js //git cz提交配置
├── .editorconfig //统一编辑器配置
├── .env //环境文件
├── .env.development //环境文件(开发模式)
├── .env.production //环境文件(生产模式)
├── .env.staging //环境文件(自定义staging模式)
├── .eslintignore //忽略eslint检查的配置文件
├── .eslintrc.js //eslint配置文件
├── .gitignore //忽略git提交的配置文件
├── .husky //git commit提交钩子提交前检查代码格式和提交commit内容的格式
├── .prettierrc.js //prettier代码格式插件配置
├── commitlint.config.js //commitlint提交规范插件配置
├── index.html
├── package.json //npm依赖描述文件
├── pnpm-lock.yaml //npm包管理器pnpm依赖锁定文件
├── README.md //项目介绍文档
├── tsconfig.json //TS配置
├── vite.config.ts //vite配置
└── windi.config.ts //windicss框架配置
```

View File

@@ -4,29 +4,27 @@
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title><%= title %></title>
<title><%= appName %></title>
</head>
<body>
<div id="appProvider" style="display: none"></div>
<div id="app">
<!-- 页面渲染之前加载动画 -->
<div class="app-loading">
<img class="app-loading_logo" src="/resource/logo.png" />
<div class="app-loading__dot-wrapper">
<div class="app-loading__dot">
<i class="left top"></i>
<i class="left bottom delay-400"></i>
<i class="right top delay-800"></i>
<i class="right bottom delay-1200"></i>
<div class="loading-container">
<div id="loadingLogo" class="loading-svg"></div>
<div class="loading-spin__container">
<div class="loading-spin">
<div class="left-0 top-0 loading-spin-item"></div>
<div class="left-0 bottom-0 loading-spin-item loading-delay-500"></div>
<div class="right-0 top-0 loading-spin-item loading-delay-1000"></div>
<div class="right-0 bottom-0 loading-spin-item loading-delay-1500"></div>
</div>
</div>
<h2 class="app-loading_title"><%= appName %></h2>
<style>
@import '/resource/loading.css';
</style>
<h2 class="loading-title"><%= appTitle %></h2>
</div>
<!-- End -->
</div>
<style>
@import '/resource/loading.css';
</style>
<script src="/resource/loading.js"></script>
</div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>

93
mock/api/auth.ts Normal file
View File

@@ -0,0 +1,93 @@
import type { MockMethod } from 'vite-plugin-mock';
const token: ApiAuth.Token = {
token: '__TEMP_TOKEN__',
refreshToken: '__TEMP_REFRESH_TOKEN__'
};
const apis: MockMethod[] = [
// 获取验证码
{
url: '/mock/getSmsCode',
method: 'post',
response: (): Service.BackendServiceResult<boolean> => {
return {
code: 200,
message: 'ok',
data: true
};
}
},
// 密码登录
{
url: '/mock/loginByPwd',
method: 'post',
response: (): Service.BackendServiceResult<ApiAuth.Token> => {
return {
code: 200,
message: 'ok',
data: token
};
}
},
// 验证码登录
{
url: '/mock/loginByCode',
method: 'post',
response: (): Service.BackendServiceResult<ApiAuth.Token> => {
return {
code: 200,
message: 'ok',
data: token
};
}
},
// 获取用户信息(请求头携带token)
{
url: '/mock/getUserInfo',
method: 'get',
response: (): Service.BackendServiceResult<ApiAuth.UserInfo> => {
return {
code: 200,
message: 'ok',
data: {
userId: '0',
userName: 'Soybean',
userPhone: '15170283876',
userRole: 'super'
}
};
}
},
{
url: '/mock/testToken',
method: 'post',
response: (option: any): Service.BackendServiceResult<true | null> => {
if (option.headers?.authorization !== token.token) {
return {
code: 66666,
message: 'token 失效',
data: null
};
}
return {
code: 200,
message: 'ok',
data: true
};
}
},
{
url: '/mock/updateToken',
method: 'post',
response: (): Service.BackendServiceResult<string> => {
return {
code: 200,
message: 'ok',
data: token.token
};
}
}
];
export default apis;

4
mock/api/index.ts Normal file
View File

@@ -0,0 +1,4 @@
import auth from './auth';
import route from './route';
export default [...auth, ...route];

211
mock/api/route.ts Normal file
View File

@@ -0,0 +1,211 @@
import type { MockMethod } from 'vite-plugin-mock';
const routes: AuthRoute.Route[] = [
{
name: 'dashboard',
path: '/dashboard',
component: 'basic',
children: [
{
name: 'dashboard_analysis',
path: '/dashboard/analysis',
component: 'self',
meta: {
title: '分析页'
}
},
{
name: 'dashboard_workbench',
path: '/dashboard/workbench',
component: 'self',
meta: {
title: '工作台',
permissions: ['super', 'admin']
}
}
],
meta: {
title: '仪表盘',
requiresAuth: true,
icon: 'carbon:dashboard',
order: 1
}
},
{
name: 'document',
path: '/document',
component: 'basic',
children: [
{
name: 'document_vue',
path: '/document/vue',
component: 'self',
meta: {
title: 'vue文档'
}
},
{
name: 'document_vue-new',
path: '/document/vue-new',
component: 'self',
meta: {
title: 'vue文档(新版)'
}
},
{
name: 'document_vite',
path: '/document/vite',
component: 'self',
meta: {
title: 'vite文档'
}
},
{
name: 'document_naive',
path: '/document/naive',
component: 'self',
meta: {
title: 'naive文档'
}
},
{
name: 'document_project',
path: '/document/project',
meta: {
title: '项目文档(外链)',
href: 'https://docs.soybean.pro/'
}
}
],
meta: {
title: '文档',
icon: 'carbon:document',
order: 2
}
},
{
name: 'about',
path: '/about',
component: 'self',
meta: {
title: '关于',
singleLayout: 'basic',
permissions: ['super', 'admin', 'test'],
icon: 'fluent:book-information-24-regular',
order: 7
}
},
{
name: 'exception',
path: '/exception',
component: 'basic',
children: [
{
name: 'exception_403',
path: '/exception/403',
component: 'self',
meta: {
title: '异常页403'
}
},
{
name: 'exception_404',
path: '/exception/404',
component: 'self',
meta: {
title: '异常页404'
}
},
{
name: 'exception_500',
path: '/exception/500',
component: 'self',
meta: {
title: '异常页500'
}
}
],
meta: {
title: '异常页',
icon: 'ant-design:exception-outlined',
order: 5
}
},
{
name: 'multi-menu',
path: '/multi-menu',
component: 'basic',
children: [
{
name: 'multi-menu_first',
path: '/multi-menu/first',
component: 'multi',
children: [
{
name: 'multi-menu_first_second',
path: '/multi-menu/first/second',
component: 'self',
meta: {
title: '二级菜单'
}
},
{
name: 'multi-menu_first_second-new',
path: '/multi-menu/first/second-new',
component: 'multi',
children: [
{
name: 'multi-menu_first_second-new_third',
path: '/multi-menu/first/second-new/third',
component: 'self',
meta: {
title: '三级菜单'
}
}
],
meta: {
title: '二级菜单(有子菜单)'
}
}
],
meta: {
title: '一级菜单'
}
}
],
meta: {
title: '多级菜单',
icon: 'carbon:menu',
order: 6
}
}
];
function dataMiddleware(data: AuthRoute.Route[]): ApiRoute.Route {
const routeHomeName: AuthRoute.RouteKey = 'dashboard_analysis';
function sortRoutes(sorts: AuthRoute.Route[]) {
return sorts.sort((next, pre) => Number(next.meta?.order) - Number(pre.meta?.order));
}
return {
routes: sortRoutes(data),
home: routeHomeName
};
}
const apis: MockMethod[] = [
{
url: '/mock/getUserRoutes',
method: 'post',
response: (): Service.BackendServiceResult => {
return {
code: 200,
message: 'ok',
data: dataMiddleware(routes)
};
}
}
];
export default apis;

6
mock/index.ts Normal file
View File

@@ -0,0 +1,6 @@
import { createProdMockServer } from 'vite-plugin-mock/es/createProdMockServer';
import api from './api';
export function setupMockServer() {
createProdMockServer(api);
}

View File

@@ -1,23 +1,17 @@
{
"name": "soybean-admin",
"version": "0.0.3",
"author": {
"name": "Soybean",
"email": "honghuangdc@gmail.com",
"url": "https://github.com/honghuangdc"
},
"name": "soybean-admin-thin",
"version": "0.1.1",
"scripts": {
"dev": "cross-env VITE_HTTP_ENV=test vite",
"dev:prod": "cross-env VITE_HTTP_ENV=prod vite",
"typecheck": "vue-tsc",
"build": "npm run typecheck && cross-env VITE_HTTP_ENV=prod vite build",
"build:test": "npm run typecheck && cross-env VITE_HTTP_ENV=test vite build",
"build:vercel": "npm run typecheck && cross-env VITE_HTTP_ENV=prod VITE_IS_VERCEL=1 vite build",
"preview": "vite preview --port 5050",
"release": "standard-version",
"changelog": "conventional-changelog -p angular -i CHANGELOG.md -s -r 0 && git add CHANGELOG.md",
"dev": "vite",
"dev:prod": "vite --mode production",
"dev:staging": "vite --mode staging",
"build": "vue-tsc --noEmit --skipLibCheck && vite build",
"build:dev": "vue-tsc --noEmit --skipLibCheck && vite build --mode development",
"build:staging": "vue-tsc --noEmit --skipLibCheck && vite build --mode staging",
"serve": "vite preview",
"lint": "eslint ./src --ext .vue,.js,jsx,.ts,tsx",
"lint:fix": "eslint --fix ./src --ext .vue,.js,jsx,.ts,tsx",
"lint": "eslint --fix ./ --ext .vue,.js,jsx,.ts,tsx",
"prepare": "husky install",
"postinstall": "patch-package"
},
@@ -30,73 +24,62 @@
}
},
"dependencies": {
"@antv/g2plot": "^2.3.40",
"@antv/g2plot": "^2.4.7",
"@better-scroll/core": "^2.4.2",
"@vueuse/core": "^7.0.0",
"axios": "^0.24.0",
"chroma-js": "^2.1.2",
"@vueuse/core": "^7.5.3",
"axios": "^0.25.0",
"clipboard": "^2.0.8",
"colord": "^2.9.2",
"crypto-js": "^4.1.1",
"dayjs": "^1.10.7",
"form-data": "^4.0.0",
"naive-ui": "^2.21.0",
"pinia": "^2.0.4",
"print-js": "^1.6.0",
"qs": "^6.10.1",
"swiper": "^7.3.0",
"vditor": "^3.8.7",
"vue": "^3.2.22",
"vue-router": "^4.0.12",
"wangeditor": "^4.7.9",
"xgplayer": "^2.31.2"
"lodash-es": "^4.17.21",
"naive-ui": "^2.24.1",
"pinia": "^2.0.9",
"qs": "^6.10.3",
"vue": "^3.2.26",
"vue-router": "^4.0.12"
},
"devDependencies": {
"@amap/amap-jsapi-types": "^0.0.8",
"@commitlint/cli": "^15.0.0",
"@commitlint/config-conventional": "^15.0.0",
"@iconify/json": "^1.1.431",
"@iconify/vue": "^3.1.1",
"@types/bmapgl": "^0.0.4",
"@types/chroma-js": "^2.1.3",
"@commitlint/cli": "^16.0.3",
"@commitlint/config-conventional": "^16.0.0",
"@iconify/json": "^1.1.458",
"@iconify/vue": "^3.1.2",
"@types/crypto-js": "^4.1.0",
"@types/node": "^17.0.10",
"@types/qs": "^6.9.7",
"@typescript-eslint/eslint-plugin": "^5.4.0",
"@typescript-eslint/parser": "^5.4.0",
"@vitejs/plugin-vue": "^1.9.4",
"@vue/compiler-sfc": "^3.2.22",
"@vue/eslint-config-prettier": "^6.0.0",
"@vue/eslint-config-typescript": "^9.1.0",
"@typescript-eslint/eslint-plugin": "^5.10.0",
"@typescript-eslint/parser": "^5.10.0",
"@vitejs/plugin-vue": "^2.0.1",
"@vue/eslint-config-prettier": "^7.0.0",
"@vue/eslint-config-typescript": "^10.0.0",
"commitizen": "^4.2.4",
"cross-env": "^7.0.3",
"cz-conventional-changelog": "^3.3.0",
"cz-customizable": "^6.3.0",
"dotenv": "^10.0.0",
"eslint": "^8.3.0",
"eslint": "^8.7.0",
"eslint-config-airbnb-base": "^15.0.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-import": "^2.25.3",
"eslint-plugin-import": "^2.25.4",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-vue": "^8.1.1",
"eslint-plugin-vue": "^8.3.0",
"husky": "^7.0.4",
"lint-staged": "^12.1.0",
"lint-staged": "^12.2.1",
"mockjs": "^1.1.0",
"patch-package": "^6.4.7",
"postinstall-postinstall": "^2.1.0",
"prettier": "^2.4.1",
"rollup-plugin-visualizer": "^5.5.2",
"sass": "^1.43.4",
"typescript": "^4.5.2",
"unplugin-icons": "^0.12.18",
"unplugin-vue-components": "^0.17.2",
"vite": "~2.5.10",
"vite-plugin-html": "^2.1.1",
"vite-plugin-windicss": "^1.5.1",
"vue-tsc": "^0.29.6",
"vueuc": "^0.4.15",
"windicss": "^3.2.1"
},
"homepage": "https://github.com/honghuangdc/soybean-admin",
"repository": {
"type": "git",
"url": "git+https://github.com/honghuangdc/soybean-admin.git"
},
"bugs": {
"url": "https://github.com/honghuangdc/soybean-admin/issues"
"prettier": "^2.5.1",
"rollup-plugin-visualizer": "^5.5.4",
"sass": "^1.49.0",
"typescript": "^4.5.4",
"unplugin-icons": "^0.13.0",
"unplugin-vue-components": "^0.17.13",
"vite": "^2.7.13",
"vite-plugin-html": "^2.1.2",
"vite-plugin-mock": "^2.9.6",
"vite-plugin-windicss": "^1.6.3",
"vue-tsc": "^0.30.6",
"vueuc": "^0.4.23",
"windicss": "^3.4.3"
}
}

6299
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,91 +1,91 @@
.app-loading {
position: fixed;
left: 0;
top: 0;
z-index: -1;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
background-color:#f5f7f9;
.loading-container {
position: fixed;
left: 0;
top: 0;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
}
.app-loading_logo {
width: 128px;
height: 128px;
.loading-svg {
width: 128px;
height: 128px;
color: var(--primary-color);
}
.app-loading__dot-wrapper {
width: 56px;
height: 56px;
margin: 36px 0;
.loading-spin__container {
width: 56px;
height: 56px;
margin: 36px 0;
}
.app-loading__dot {
position: relative;
height: 100%;
transform: rotate(45deg);
animation-name: loadingRotate;
animation-duration: 1.2s;
animation-iteration-count: infinite;
animation-timing-function: linear;
.loading-spin {
position: relative;
height: 100%;
animation: loadingSpin 1s linear infinite;
}
@keyframes loadingRotate {
to {
-webkit-transform: rotate(405deg);
transform: rotate(405deg);
}
}
@-webkit-keyframes loadingRotate {
to {
-webkit-transform: rotate(405deg);
transform: rotate(405deg);
}
}
.app-loading__dot > i {
position: absolute;
display: block;
width: 18px;
height: 18px;
background: #1890ff;
border-radius: 50%;
-webkit-transform: scale(0.75);
transform: scale(0.75);
transform-origin: 50% 50%;
opacity: 0.3;
animation: spinOpacity 1s infinite linear alternate;
}
@keyframes spinOpacity {
to {
opacity: 1;
}
}
@-webkit-keyframes spinOpacity {
to {
opacity: 1;
}
}
.delay-400 {
animation-delay: 0.4s !important;
}
.delay-800 {
animation-delay: 0.8s !important;
}
.delay-1200 {
animation-delay: 1.2s !important;
}
.left {
.left-0 {
left: 0;
}
.right {
.right-0 {
right: 0;
}
.top {
.top-0 {
top: 0;
}
.bottom {
.bottom-0 {
bottom: 0;
}
.app-loading_title {
.loading-spin-item {
position: absolute;
height: 16px;
width: 16px;
background-color: var(--primary-color);
border-radius: 8px;
-webkit-animation: loadingPulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
animation: loadingPulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
}
@keyframes loadingSpin {
from {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
to {
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
}
@keyframes loadingPulse {
0%, 100% {
opacity: 1;
}
50% {
opacity: .5;
}
}
.loading-delay-500 {
-webkit-animation-delay: 500ms;
animation-delay: 500ms;
}
.loading-delay-1000 {
-webkit-animation-delay: 1000ms;
animation-delay: 1000ms;
}
.loading-delay-1500 {
-webkit-animation-delay: 1500ms;
animation-delay: 1500ms;
}
.loading-title {
font-size: 28px;
font-weight: 500;
color: #646464;
}

View File

@@ -0,0 +1,44 @@
/**
* 初始化加载效果的svg格式logo
* @param { string }id - 元素id
*/
function initSvgLogo(id) {
const svgStr = `<svg width="128px" height="128px" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
y="0px" viewBox="0 0 158.9 158.9" style="enable-background:new 0 0 158.9 158.9;" xml:space="preserve">
<path style="fill:none" d="M0,158.9C0,106.3,0,53.7,0,1.1C0,0.2,0.2,0,1.1,0c52.2,0,104.5,0,156.7,0c0.9,0,1.1,0.2,1.1,1.1
c0,52.2,0,104.5,0,156.7c0,0.9-0.2,1.1-1.1,1.1C105.2,158.8,52.6,158.8,0,158.9z" />
<path style="fill:currentColor" d="M81.3,55.9c-0.1-11.7-2.9-22.5-9.4-32.4c-1-1.5-2.1-2.9-2.5-4.7c-0.7-3.4,0.9-6.9,4-8.6c3-1.7,6.8-1.2,9.3,1.2
c2.4,2.6,4.4,5.6,5.9,8.8c4.7,8.9,7.6,18.6,8.4,28.6c1,12.5-0.7,25-5.2,36.7c-0.9,2.5-1.9,4.9-3,7.3c-0.3,0.4-0.3,1,0,1.4
c9.6,13.3,21.8,23,37.8,27.2c6.4,1.7,13.1,2.3,19.7,1.6c4.2-0.4,7.9,2.7,8.4,6.9c0.7,4.3-2.3,8.3-6.6,9c0,0,0,0-0.1,0
c-7.7,0.9-15.5,0.5-23-1.3c-13.9-3.1-26.7-10-36.9-19.9c-4.4-4.2-8.4-8.8-11.9-13.7c-0.5-0.8-1.4-1.2-2.3-1.1
c-9.5,0.7-18.8,3.3-27.4,7.6c-11.6,6-20.7,14.6-26.4,26.4c-0.7,1.9-2,3.5-3.7,4.7c-2.9,1.7-6.6,1.5-9.2-0.7c-2.8-2.2-3.8-6-2.4-9.3
c2.2-5.2,5.1-10.1,8.7-14.5c12.2-15.4,28.2-24.6,47.3-28.6c4-0.8,8.1-1.4,12.2-1.6c0.5,0,1-0.3,1.2-0.8c3.3-7.1,5.5-14.6,6.5-22.3
C81.1,61.2,81.3,58.6,81.3,55.9z" />
<path style="fill:currentColor" d="M136.3,108.3c-3.8-0.5-7.6-1.4-11.1-2.9c-7.7-2.8-14.4-7.5-19.7-13.8c-2.9-3.3-2.5-8.4,0.8-11.3
c1.4-1.2,3.1-1.9,4.9-1.9c2.5-0.1,5,1,6.5,2.9c4.9,5.6,11.6,9.4,18.9,10.8c1.5,0.2,3.1,0.6,4.5,1.2c3.2,1.8,4.8,5.6,3.8,9.2
C144,106.1,140.8,108.4,136.3,108.3z" />
<path style="fill:currentColor" d="M55.7,33.3c3,0.2,5.6,2.2,6.6,5c2.2,5.4,3.4,11.2,3.6,17c0.3,5.9-0.6,11.7-2.5,17.3c-2,5.8-8.2,7.8-12.9,4.2
c-2.6-2.2-3.6-5.8-2.4-9c1.4-4,1.9-8.2,1.7-12.4c-0.2-3.8-1-7.5-2.4-11C45.3,38.9,49.2,33.3,55.7,33.3z" />
<path style="fill:currentColor" d="M77.9,126.6c0,3.9-2.8,7.2-6.7,7.9c-7.8,1.5-14.8,5.9-19.7,12.2c-2.7,3.5-7.6,4.2-11.2,1.6
c-3.6-2.6-4.3-7.6-1.7-11.2c0.1-0.1,0.2-0.3,0.3-0.4c4.1-5.2,9.3-9.6,15.1-12.8c4.4-2.5,9.1-4.2,14-5.1
C73.3,117.7,77.9,121.3,77.9,126.6z" />
</svg>
`;
const appEl = document.querySelector(id);
const div = document.createElement('div');
div.innerHTML = svgStr;
if (appEl) {
appEl.appendChild(div);
}
}
function addThemeColorCssVars() {
const key = '__THEME_COLOR__';
const themeColor = '#1890ff';
const cssVars = window.localStorage.getItem(key) || `--primary-color: ${themeColor}`;
document.documentElement.style.cssText = cssVars;
}
initSvgLogo('#loadingLogo');
addThemeColorCssVars();

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -1,10 +1,24 @@
<template>
<app-provider>
<router-view />
</app-provider>
<n-config-provider
:theme="theme.naiveTheme"
:theme-overrides="theme.naiveThemeOverrides"
:locale="zhCN"
:date-locale="dateZhCN"
class="h-full"
>
<naive-provider>
<router-view />
</naive-provider>
</n-config-provider>
</template>
<script lang="ts" setup>
import AppProvider from './AppProvider.vue';
<script setup lang="ts">
import { NConfigProvider, zhCN, dateZhCN } from 'naive-ui';
import { NaiveProvider } from '@/components';
import { useThemeStore, subscribeStore } from '@/store';
const theme = useThemeStore();
subscribeStore();
</script>
<style></style>
<style scoped></style>

View File

@@ -1,26 +0,0 @@
<template>
<n-config-provider
class="h-full"
:locale="zhCN"
:date-locale="dateZhCN"
:theme="naiveTheme"
:theme-overrides="theme.themeOverrids"
>
<n-element class="h-full">
<naive-provider>
<slot></slot>
</naive-provider>
</n-element>
</n-config-provider>
</template>
<script lang="ts" setup>
import { NConfigProvider, NElement, zhCN, dateZhCN } from 'naive-ui';
import { NaiveProvider } from '@/components';
import { useThemeStore } from '@/store';
import { useDarkMode } from '@/composables';
const theme = useThemeStore();
const { naiveTheme } = useDarkMode();
</script>
<style></style>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

View File

Before

Width:  |  Height:  |  Size: 8.6 KiB

After

Width:  |  Height:  |  Size: 8.6 KiB

View File

@@ -0,0 +1,48 @@
<template>
<div class="w-full text-14px">
<n-checkbox v-model:checked="checked">我已经仔细阅读并接受</n-checkbox>
<n-button :text="true" type="primary" @click="handleClickProtocol">用户协议</n-button>
<n-button :text="true" type="primary" @click="handleClickPolicy">隐私权政策</n-button>
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue';
import { NCheckbox, NButton } from 'naive-ui';
interface Props {
/** 是否勾选 */
value?: boolean;
}
interface Emits {
(e: 'update:value', value: boolean): void;
/** 点击协议 */
(e: 'click-protocol'): void;
/** 点击隐私政策 */
(e: 'click-policy'): void;
}
const props = withDefaults(defineProps<Props>(), {
value: true
});
const emit = defineEmits<Emits>();
const checked = computed({
get() {
return props.value;
},
set(newValue: boolean) {
emit('update:value', newValue);
}
});
function handleClickProtocol() {
emit('click-protocol');
}
function handleClickPolicy() {
emit('click-policy');
}
</script>
<style scoped></style>

View File

@@ -0,0 +1,3 @@
import LoginAgreement from './LoginAgreement/index.vue';
export { LoginAgreement };

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -1,5 +0,0 @@
import Banner1 from './Banner1.vue';
import Banner2 from './Banner2.vue';
import Banner3 from './Banner3.vue';
export { Banner1, Banner2, Banner3 };

View File

@@ -1,24 +0,0 @@
<template>
<div :style="{ color }">
<banner1 v-if="type === '1'" />
<banner2 v-if="type === '2'" />
<banner3 v-if="type === '3'" />
</div>
</template>
<script lang="ts" setup>
import { Banner1, Banner2, Banner3 } from './components';
interface Props {
/** banner类型 */
type?: '1' | '2' | '3';
/** 主题颜色 */
color?: string;
}
withDefaults(defineProps<Props>(), {
type: '1',
color: '#409eff'
});
</script>
<style scoped></style>

View File

@@ -0,0 +1,10 @@
<template>
<div
class="bg-white text-[#333639] dark:(bg-[#18181c] text-white text-opacity-82) transition-all duration-300 ease-in-out"
>
<slot></slot>
</div>
</template>
<script setup lang="ts"></script>
<style scoped></style>

View File

@@ -0,0 +1,39 @@
<template>
<div class="flex-center text-18px hover:text-primary cursor-pointer" @click="handleSwitch">
<icon-mdi-moon-waning-crescent v-if="darkMode" />
<icon-mdi-white-balance-sunny v-else />
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue';
interface Props {
/** 暗黑模式 */
dark?: boolean;
}
interface Emits {
(e: 'update:dark', darkMode: boolean): void;
}
const props = withDefaults(defineProps<Props>(), {
dark: false
});
const emit = defineEmits<Emits>();
const darkMode = computed({
get() {
return props.dark;
},
set(newValue: boolean) {
emit('update:dark', newValue);
}
});
function handleSwitch() {
darkMode.value = !darkMode.value;
}
</script>
<style scoped></style>

View File

@@ -1,5 +0,0 @@
import SvgNoPermission from './SvgNoPermission.vue';
import SvgNotFound from './SvgNotFound.vue';
import SvgServiceError from './SvgServiceError.vue';
export { SvgNoPermission, SvgNotFound, SvgServiceError };

View File

@@ -1,24 +0,0 @@
<template>
<div class="w-400px h-400px" :style="{ color }">
<svg-no-permission v-if="type === '403'" />
<svg-not-found v-if="type === '404'" />
<svg-service-error v-if="type === '500'" />
</div>
</template>
<script lang="ts" setup>
import { SvgNoPermission, SvgNotFound, SvgServiceError } from './components';
interface Props {
/** 异常类型 */
type?: '403' | '404' | '500';
/** 主题颜色 */
color?: string;
}
withDefaults(defineProps<Props>(), {
type: '404',
color: '#409eff'
});
</script>
<style scoped></style>

View File

@@ -1,29 +0,0 @@
<template>
<div class="absolute-lt wh-full overflow-hidden">
<div class="absolute -right-300px -top-900px">
<corner-top :start-color="themeColor" :end-color="stopColor" />
</div>
<div class="absolute -left-200px -bottom-400px">
<corner-bottom :start-color="themeColor" :end-color="stopColor" />
</div>
</div>
</template>
<script lang="ts" setup>
import { computed } from 'vue';
import { mixColor } from '@/utils';
import { CornerTop, CornerBottom } from './components';
interface Props {
/** 主题颜色 */
themeColor?: string;
}
const props = withDefaults(defineProps<Props>(), {
themeColor: '#409EFF'
});
const COLOR_WHITE = '#ffffff';
const stopColor = computed(() => mixColor(COLOR_WHITE, props.themeColor, 0.7));
</script>
<style scoped></style>

View File

@@ -1,5 +1,5 @@
<template>
<div :style="{ color }">
<div>
<svg-fill-logo v-if="fill" />
<svg-logo v-else />
</div>
@@ -11,13 +11,10 @@ import { SvgLogo, SvgFillLogo } from './components';
interface Props {
/** logo是否填充 */
fill?: boolean;
/** logo的主题颜色 */
color?: string;
}
withDefaults(defineProps<Props>(), {
fill: false,
color: '#409EFF'
fill: false
});
</script>
<style scoped></style>

View File

@@ -1,8 +1,7 @@
import NaiveProvider from './NaiveProvider/index.vue';
import SystemLogo from './SystemLogo/index.vue';
import ExceptionSvg from './ExceptionSvg/index.vue';
import LoginBg from './LoginBg/index.vue';
import BannerSvg from './BannerSvg/index.vue';
import DarkModeSwitch from './DarkModeSwitch/index.vue';
import DarkModeContainer from './DarkModeContainer/index.vue';
import HoverContainer from './HoverContainer/index.vue';
export { NaiveProvider, SystemLogo, ExceptionSvg, LoginBg, BannerSvg, HoverContainer };
export { NaiveProvider, SystemLogo, DarkModeSwitch, DarkModeContainer, HoverContainer };

View File

@@ -1,6 +1,6 @@
<template>
<div ref="scrollbar" class="wh-full text-left">
<div ref="scrollbarContent" class="inline-block" :class="{ 'h-full': !isScrollY }">
<div ref="bsWrap" class="h-full text-left">
<div ref="bsContent" class="inline-block" :class="{ 'h-full': !isScrollY }">
<slot></slot>
</div>
</div>
@@ -8,38 +8,39 @@
<script setup lang="ts">
import { ref, computed, watch, onMounted } from 'vue';
import { useElementSize } from '@vueuse/core';
import BScroll from '@better-scroll/core';
import type { Options } from '@better-scroll/core';
import { useElementSize } from '@vueuse/core';
interface Props {
/** better-scroll的配置: https://better-scroll.github.io/docs/zh-CN/guide/base-scroll-options.html */
options?: Options;
options: Options;
}
const props = withDefaults(defineProps<Props>(), {
options: undefined
});
const props = defineProps<Props>();
const scrollbar = ref<HTMLElement | null>(null);
const bsInstance = ref<BScroll | null>(null);
const scrollbarContent = ref<HTMLElement | null>(null);
const isScrollY = computed(() => Boolean(props.options?.scrollY));
const bsWrap = ref<HTMLElement>();
const instance = ref<BScroll>();
const bsContent = ref<HTMLElement>();
const isScrollY = computed(() => Boolean(props.options.scrollY));
function initBetterScroll() {
bsInstance.value = new BScroll(scrollbar.value!, props.options);
if (!bsWrap.value) return;
instance.value = new BScroll(bsWrap.value, props.options);
}
// 滚动元素发生变化刷新BS
const { width, height } = useElementSize(scrollbarContent);
const { width, height } = useElementSize(bsContent);
watch([() => width.value, () => height.value], () => {
if (bsInstance.value) {
bsInstance.value.refresh();
if (instance.value) {
instance.value.refresh();
}
});
onMounted(() => {
initBetterScroll();
});
defineExpose({ instance });
</script>
<style scoped></style>

View File

@@ -1,18 +1,6 @@
<template>
<div
class="
relative
flex-center
h-30px
pl-14px
border-1px border-[#e5e7eb]
dark:border-[#ffffff3d]
rounded-2px
transition-border-color
duration-300
ease-in-out
cursor-pointer
"
class="relative flex-center h-30px pl-14px border-1px border-[#e5e7eb] dark:border-[#ffffff3d] rounded-2px cursor-pointer transition-colors duration-300 ease-in-out"
:class="[closable ? 'pr-6px' : 'pr-14px']"
:style="buttonStyle"
@mouseenter="setTrue"
@@ -22,7 +10,7 @@
<slot></slot>
</span>
<div v-if="closable" class="pl-10px">
<icon-close :is-primary="isActive || isHover" :primary-color="primaryColor" @click="handleClose" />
<icon-close :is-active="isIconActive" :primary-color="primaryColor" @click="handleClose" />
</div>
</div>
</template>
@@ -30,8 +18,8 @@
<script lang="ts" setup>
import { computed } from 'vue';
import { useBoolean } from '@/hooks';
import { IconClose } from '@/components';
import { addColorAlpha } from '@/utils';
import IconClose from '../IconClose/index.vue';
interface Props {
/** 激活状态 */
@@ -44,27 +32,27 @@ interface Props {
darkMode?: boolean;
}
interface Emits {
/** 点击关闭图标 */
(e: 'close'): void;
}
const props = withDefaults(defineProps<Props>(), {
isActive: false,
primaryColor: '#409EFF',
primaryColor: '#1890ff',
closable: true,
darkMode: false
});
const emit = defineEmits<{
/** 点击关闭图标 */
(e: 'close'): void;
}>();
const emit = defineEmits<Emits>();
const { bool: isHover, setTrue, setFalse } = useBoolean();
function handleClose(e: MouseEvent) {
e.stopPropagation();
emit('close');
}
const isIconActive = computed(() => props.isActive || isHover.value);
const buttonStyle = computed(() => {
const style: { [key: string]: string } = {};
if (props.isActive || isHover.value) {
if (isIconActive.value) {
style.color = props.primaryColor;
style.borderColor = addColorAlpha(props.primaryColor, 0.3);
if (props.isActive) {
@@ -74,5 +62,10 @@ const buttonStyle = computed(() => {
}
return style;
});
function handleClose(e: MouseEvent) {
e.stopPropagation();
emit('close');
}
</script>
<style scoped></style>

View File

@@ -1,6 +1,6 @@
<template>
<div
class="relative flex-y-center h-34px px-24px cursor-pointer -mr-18px"
class="relative flex-y-center h-34px px-24px -mr-18px cursor-pointer"
:class="{ 'z-10': isActive, 'z-9': isHover }"
@mouseenter="setTrue"
@mouseleave="setFalse"
@@ -18,7 +18,7 @@
<slot></slot>
</span>
<div v-if="closable" class="pl-18px">
<icon-close :is-primary="isActive" :primary-color="primaryColor" @click="handleClose" />
<icon-close :is-active="isActive" :primary-color="primaryColor" @click="handleClose" />
</div>
<n-divider v-if="!isHover && !isActive" :vertical="true" class="absolute right-0 !bg-[#a4abb8] z-2" />
</div>
@@ -41,16 +41,20 @@ interface Props {
darkMode?: boolean;
}
interface Emits {
/** 点击关闭图标 */
(e: 'close'): void;
}
withDefaults(defineProps<Props>(), {
isActive: false,
primaryColor: '#409EFF',
closable: true,
darkMode: false
darkMode: false,
isLast: false
});
const emit = defineEmits<{
/** 点击关闭图标 */
(e: 'close'): void;
}>();
const emit = defineEmits<Emits>();
const { bool: isHover, setTrue, setFalse } = useBoolean();

View File

@@ -95,9 +95,11 @@ watch([() => props.startValue, () => props.endValue], () => {
start();
}
});
watchEffect(() => {
source.value = props.startValue;
});
onMounted(() => {
if (props.autoplay) {
start();

View File

@@ -1,15 +0,0 @@
<template>
<web-site-link label="github地址" :link="link" />
</template>
<script setup lang="ts">
import WebSiteLink from '../WebSiteLink/index.vue';
interface Props {
/** github链接 */
link: string;
}
defineProps<Props>();
</script>
<style scoped></style>

View File

@@ -1,13 +1,13 @@
<template>
<div
class="relative flex-center w-18px h-18px text-14px"
:style="{ color: isPrimary ? primaryColor : defaultColor }"
:style="{ color: isActive ? primaryColor : defaultColor }"
@mouseenter="setTrue"
@mouseleave="setFalse"
>
<transition name="transition-opacity">
<icon-carbon-close-filled v-if="isHover" key="hover" class="absolute" />
<icon-carbon-close v-else key="unhover" class="absolute" />
<transition name="fade">
<icon-mdi:close-circle v-if="isHover" key="hover" class="absolute" />
<icon-mdi:close v-else key="unhover" class="absolute" />
</transition>
</div>
</template>
@@ -17,7 +17,7 @@ import { useBoolean } from '@/hooks';
interface Props {
/** 激活状态 */
isPrimary?: boolean;
isActive?: boolean;
/** 主题颜色 */
primaryColor?: string;
/** 默认颜色 */
@@ -26,7 +26,7 @@ interface Props {
withDefaults(defineProps<Props>(), {
isPrimary: false,
primaryColor: '#409EFF',
primaryColor: '#1890ff',
defaultColor: '#9ca3af'
});

View File

@@ -0,0 +1,39 @@
<template>
<div>
<canvas ref="domRef" width="152" height="40" class="cursor-pointer" @click="getImgCode"></canvas>
</div>
</template>
<script setup lang="ts">
import { watch } from 'vue';
import { useImageVerify } from '@/hooks';
interface Props {
code?: string;
}
interface Emits {
(e: 'update:code', code: string): void;
}
const props = withDefaults(defineProps<Props>(), {
code: ''
});
const emit = defineEmits<Emits>();
const { domRef, imgCode, setImgCode, getImgCode } = useImageVerify();
watch(
() => props.code,
newValue => {
setImgCode(newValue);
}
);
watch(imgCode, newValue => {
emit('update:code', newValue);
});
defineExpose({ getImgCode });
</script>
<style scoped></style>

View File

@@ -1,20 +0,0 @@
<template>
<p>
<span>{{ label }}</span>
<a class="text-blue-500" :href="link" target="_blank">
{{ link }}
</a>
</p>
</template>
<script setup lang="ts">
interface Props {
/** 网址名称 */
label: string;
/** 网址链接 */
link: string;
}
defineProps<Props>();
</script>
<style scoped></style>

View File

@@ -1,9 +1,7 @@
import CountTo from './CountTo/index.vue';
import IconClose from './IconClose/index.vue';
import BetterScroll from './BetterScroll/index.vue';
import ButtonTab from './ButtonTab/index.vue';
import ChromeTab from './ChromeTab/index.vue';
import BetterScroll from './BetterScroll/index.vue';
import WebSiteLink from './WebSiteLink/index.vue';
import GithubLink from './GithubLink/index.vue';
import CountTo from './CountTo/index.vue';
import ImageVerify from './ImageVerify/index.vue';
export { CountTo, IconClose, ButtonTab, ChromeTab, BetterScroll, WebSiteLink, GithubLink };
export { BetterScroll, ButtonTab, ChromeTab, CountTo, ImageVerify };

View File

@@ -1,2 +1,5 @@
export * from './common';
export * from './custom';
export * from './svg';
export * from './custom';
export * from './common';
export * from './business';

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,408 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 500">
<g id="freepik--background-simple--inject-163">
<path
d="M464.5,113.47q-2.38-4-5-7.9C436.33,71.22,396.44,47.73,357.2,37.11a231.87,231.87,0,0,0-52.71-7.69c-116.62-4-163.07,88-201.61,111.67S5,205.33,9,290.32s65.22,165,183.81,170,126.5-48.42,192.71-68.19c43.82-13.08,75-57.26,90.2-98.09C496.5,238.38,495.52,166.11,464.5,113.47Z"
style="fill: currentColor"
></path>
<path
d="M464.5,113.47q-2.38-4-5-7.9C436.33,71.22,396.44,47.73,357.2,37.11a231.87,231.87,0,0,0-52.71-7.69c-116.62-4-163.07,88-201.61,111.67S5,205.33,9,290.32s65.22,165,183.81,170,126.5-48.42,192.71-68.19c43.82-13.08,75-57.26,90.2-98.09C496.5,238.38,495.52,166.11,464.5,113.47Z"
style="fill: #fff; opacity: 0.7000000000000001"
></path>
</g>
<g id="freepik--Window--inject-163">
<polygon
points="438.56 121.49 438.56 118.2 377.7 118.2 377.7 69.42 375.72 69.42 375.72 118.2 315.29 118.2 315.29 121.49 375.72 121.49 375.72 166.65 315.29 166.65 315.29 169.95 375.72 169.95 375.72 215.11 315.29 215.11 315.29 218.4 375.72 218.4 375.72 265.85 377.7 265.85 377.7 218.4 438.56 218.4 438.56 215.11 377.7 215.11 377.7 169.95 438.56 169.95 438.56 166.65 377.7 166.65 377.7 121.49 438.56 121.49"
style="fill: #263238; stroke: #263238; stroke-miterlimit: 10"
></polygon>
<path
d="M311.12,65.46V271.13H442.3V65.46ZM437.87,264.18H315.55V72.4H437.87Z"
style="fill: #263238; stroke: #263238; stroke-miterlimit: 10"
></path>
</g>
<g id="freepik--Plant--inject-163">
<path
d="M254,323.92h0a.1.1,0,0,0-.06-.13.1.1,0,0,0-.13.06,132,132,0,0,0-6.94,21.75A202,202,0,0,0,243,368.15l-.54,5.7c-.08.95-.19,1.9-.26,2.85l-.15,2.86c-.08,1.91-.2,3.82-.26,5.73l.06,5.73.06,2.86c0,.95.11,1.91.18,2.86.14,1.9.26,3.81.43,5.71.37,3.8.94,7.57,1.52,11.34a.11.11,0,0,0,.1.08.09.09,0,0,0,.1-.1h0c0-1.91-.09-3.8-.13-5.71s-.22-3.78-.19-5.68,0-3.8-.06-5.69l-.06-2.84,0-2.84,0-5.68.15-5.67.06-2.84c0-.95.11-1.89.16-2.84l.35-5.67a200.9,200.9,0,0,1,3.21-22.49A131.72,131.72,0,0,1,254,323.92Z"
style="fill: #263238"
></path>
<path
d="M254.81,353.6a.1.1,0,0,0-.06-.12.1.1,0,0,0-.13.06,132.44,132.44,0,0,0-6.43,29.24c-.5,5-1.06,9.94-1.13,14.94a127.13,127.13,0,0,0,.53,15,.11.11,0,0,0,.09.08.09.09,0,0,0,.11-.08c.58-5,.93-9.94,1.28-14.9s.4-9.93.72-14.89a148.32,148.32,0,0,1,5-29.31Z"
style="fill: #263238"
></path>
<path
d="M271.27,364.05a.1.1,0,0,0-.14,0,50.06,50.06,0,0,0-11,9.59,44.64,44.64,0,0,0-4.3,6l-.88,1.67-.7,1.74a15.71,15.71,0,0,0-.6,1.75c-.18.6-.38,1.18-.54,1.78a71,71,0,0,0-2.27,14.52,84,84,0,0,0,.54,14.62.11.11,0,0,0,.1.08.09.09,0,0,0,.1-.09l1.26-14.47a127.64,127.64,0,0,1,1.83-14.27c.13-.59.3-1.15.45-1.73a16,16,0,0,1,.5-1.71l.59-1.67.76-1.58a43.25,43.25,0,0,1,3.94-6,49.72,49.72,0,0,1,10.33-10.05h0A.11.11,0,0,0,271.27,364.05Z"
style="fill: #263238"
></path>
<path
d="M263.3,382.64a16.06,16.06,0,0,0-5,6,35.33,35.33,0,0,0-2.81,7.37c-.19.63-.35,1.27-.49,1.91l-.45,1.92a34.52,34.52,0,0,0-.49,3.91c0,1.32-.05,2.63,0,3.94a34.57,34.57,0,0,0,.51,3.91.13.13,0,0,0,.08.08.1.1,0,0,0,.12-.08,35.91,35.91,0,0,0,.7-3.85c.2-1.28.4-2.54.55-3.81s.35-2.52.45-3.79.27-2.54.55-3.78a34.19,34.19,0,0,1,2.14-7.3,16.18,16.18,0,0,1,4.2-6.27l0,0a.09.09,0,0,0,0-.13A.11.11,0,0,0,263.3,382.64Z"
style="fill: #263238"
></path>
<path
d="M240.22,397.14c-.54-6.42-1.6-12.79-2.6-19.14s-2.12-12.7-3.28-19-2.46-12.63-3.83-18.91a.1.1,0,1,0-.19,0c1.1,6.34,2.09,12.69,3,19.05s1.87,12.71,2.68,19.08,1.4,12.77,2.19,19.13l2.35,19.13a.12.12,0,0,0,.1.09.11.11,0,0,0,.11-.1c.07-1.61.07-3.22.11-4.84s-.07-3.22-.09-4.83C240.74,403.57,240.46,400.36,240.22,397.14Z"
style="fill: #263238"
></path>
<path
d="M236.37,397.05c-.35-2.55-.81-5.08-1.3-7.6l-.9-3.75c-.3-1.25-.58-2.5-.94-3.74a105.84,105.84,0,0,0-4.92-14.61l-.77-1.77-.85-1.73c-.55-1.16-1.2-2.27-1.83-3.4a28.58,28.58,0,0,0-4.64-6.14.09.09,0,0,0-.13,0,.1.1,0,0,0,0,.14h0a28,28,0,0,1,4.24,6.29c.56,1.14,1.15,2.26,1.63,3.44l.76,1.75.67,1.79a105.45,105.45,0,0,1,4.28,14.61c.58,2.47,1,5,1.45,7.49l.6,3.76c.22,1.25.49,2.5.66,3.76.4,2.51.87,5,1.3,7.53s.85,5,1.39,7.55a.11.11,0,0,0,.09.09.11.11,0,0,0,.11-.1q0-3.85-.18-7.7C236.94,402.15,236.63,399.6,236.37,397.05Z"
style="fill: #263238"
></path>
<path
d="M231.05,397.38c-1.19-3.38-2.57-6.68-4.07-9.91a86.8,86.8,0,0,0-5.12-9.38.1.1,0,1,0-.17.1,87.62,87.62,0,0,1,4.37,9.68c1.3,3.28,2.48,6.62,3.46,10s1.73,6.83,2.63,10.23,1.71,6.83,2.76,10.27a.1.1,0,0,0,.09.07.11.11,0,0,0,.11-.1,51.83,51.83,0,0,0-1-10.69A66.72,66.72,0,0,0,231.05,397.38Z"
style="fill: #263238"
></path>
<path
d="M230.83,408.61a23.15,23.15,0,0,0-2.83-5.94,24.44,24.44,0,0,0-4.12-5.11,19.36,19.36,0,0,0-2.62-2,10.92,10.92,0,0,0-3-1.34.1.1,0,0,0-.11.06.1.1,0,0,0,0,.13h0a14.89,14.89,0,0,1,4.93,3.83,23.66,23.66,0,0,1,3.43,5.2c1,1.84,1.48,3.88,2.33,5.79.37,1,.74,1.95,1.18,2.93a23.09,23.09,0,0,0,1.29,3h0a.11.11,0,0,0,.09.05.09.09,0,0,0,.1-.09,22.57,22.57,0,0,0-.12-3.29C231.31,410.74,231.09,409.67,230.83,408.61Z"
style="fill: #263238"
></path>
<path
d="M231.23,349.25a18.29,18.29,0,0,1-13-13.76c-2.43-11.34,5.4-6.48-1.62-24.3s-5.4-21.87-3-27,3.78-3.51,5.94,3.24,10,17.28,13,37S231.23,349.25,231.23,349.25Z"
style="fill: currentColor"
></path>
<path
d="M252,330.09s-7-2.43-7.29-15.66,5.13-10.53,5.94-27,1.89-28.08,4.86-28.35,10.8,8.1,13.5,26.46-3.51,30.51-8.91,35.91S252,330.09,252,330.09Z"
style="fill: currentColor"
></path>
<path
d="M227.45,365.18s-1.62-9.72-4.86-14.31-10.26-8.64-14.85-17.54-9.72-13.23-9.45-.54,5.94,19.16,13,23.48S227.45,365.18,227.45,365.18Z"
style="fill: currentColor"
></path>
<path
d="M224.48,381.92s-6.48-12.42-15.93-21.6-17-13.77-14.31-9.18,5.94,4.32,10.53,12.42,3.24,14,9.72,18.63S224.48,381.92,224.48,381.92Z"
style="fill: currentColor"
></path>
<path
d="M223.67,397.85c-.27-.81-.54-6.75-9.72-11.61s-17.82-3-16.74-.54,6.75,6.48,12.42,8.91S223.67,397.85,223.67,397.85Z"
style="fill: currentColor"
></path>
<path
d="M251.47,365.72s-4.05-5.13-1.89-15.93,7-8.1,12.42-13.77,4.32-6.47,9.72-12.41,10.26-9.18,12.42-6.75-1.08,10-4.32,14.31S271.45,337.64,269,343s-1.35,14-7.56,18.09S251.47,365.72,251.47,365.72Z"
style="fill: currentColor"
></path>
<path
d="M265,368.69s9.72-11.07,16.74-19.17,9.72-14.3,10-8.91,2.43,9.72-3.24,16.74S265,368.69,265,368.69Z"
style="fill: currentColor"
></path>
<path
d="M259.84,386.51s-.27-4.32,15.12-14.31,21.87-11.88,20.25-7.83-8.37,8.1-15.66,15.39S259.84,386.51,259.84,386.51Z"
style="fill: currentColor"
></path>
<path
d="M231.87,348.1s-3.61-19.36-7.39-33.13-6.21-22.14-6.21-22.14"
style="fill: none; stroke: #263238; stroke-linecap: round; stroke-linejoin: round"
></path>
<path
d="M251.39,330.29s6.56-21,8.72-33.68-.27-22.14-1.35-27.81"
style="fill: none; stroke: #263238; stroke-linecap: round; stroke-linejoin: round"
></path>
<path
d="M226.6,364.78a101.76,101.76,0,0,0-9.95-14.18c-5.94-7-10.53-10.8-13.23-17.54"
style="fill: none; stroke: #263238; stroke-linecap: round; stroke-linejoin: round"
></path>
<path
d="M251.47,365.72s2.16-13,7.29-19.71,15.39-17.27,19.44-24"
style="fill: none; stroke: #263238; stroke-linecap: round; stroke-linejoin: round"
></path>
<path
d="M223,397.55s-9.08-5.91-15.56-9.15"
style="fill: none; stroke: #263238; stroke-linecap: round; stroke-linejoin: round"
></path>
<polygon
points="252.89 454.81 234.13 454.81 224.75 407.84 262.27 407.84 252.89 454.81"
style="fill: #263238; stroke: #263238; stroke-linecap: round; stroke-linejoin: round"
></polygon>
</g>
<g id="freepik--Floor--inject-163">
<line
x1="64.8"
y1="454.81"
x2="489.98"
y2="454.81"
style="fill: none; stroke: #263238; stroke-miterlimit: 10"
></line>
<line
x1="31.18"
y1="454.81"
x2="57.55"
y2="454.81"
style="fill: none; stroke: #263238; stroke-miterlimit: 10"
></line>
</g>
<g id="freepik--Device--inject-163">
<path
d="M216.14,167v-31.5h-2.85V95.19a24.85,24.85,0,0,0-24.85-24.86H54.92A24.86,24.86,0,0,0,30.06,95.19V412.62a24.86,24.86,0,0,0,24.86,24.86H188.44a24.85,24.85,0,0,0,24.85-24.86V193.85h2.85V175.24h-2.85V167Z"
style="fill: #707070; stroke: #263238; stroke-linejoin: round"
></path>
<path
d="M184.08,434.05H59.27a26.33,26.33,0,0,1-26.33-26.33V100.09c0-14.55,7.46-26.34,26.33-26.34H184.08c17.31-.23,26.34,11.79,26.34,26.34V407.72A26.33,26.33,0,0,1,184.08,434.05Z"
style="fill: #263238; stroke: #263238; stroke-linejoin: round"
></path>
<path
d="M131.34,77.8l-.05.19c-1.46,5.44-4.82,9-8.54,9h-2.14c-3.72,0-7.08-3.52-8.54-9l0-.19-52.08-.18A21.92,21.92,0,0,0,38,99.53l-.07,304.94c0,14.21,11.12,25.73,24.85,25.73H180.62c13.73,0,24.86-11.52,24.86-25.73l0-307.13a19,19,0,0,0-18.78-19Z"
style="fill: #fff; stroke: #263238; stroke-miterlimit: 10"
></path>
<path
d="M205.46,102.88V97.34a19,19,0,0,0-18.78-19l-55.34-.57-.05.19c-1.46,5.44-4.82,9-8.54,9h-2.14c-3.72,0-7.08-3.52-8.54-9l0-.19-52.08-.18A21.92,21.92,0,0,0,38,99.53v3.35Z"
style="fill: #dbdbdb; stroke: #263238; stroke-miterlimit: 10"
></path>
<path d="M123.5,77.2a2.34,2.34,0,1,0-2.33,2.34A2.33,2.33,0,0,0,123.5,77.2Z" style="fill: #707070"></path>
<path
d="M54.4,83.14c0,2.37-2.65,3.22-2.66,5v.12h2.57v.79H50.88V88.4c0-2.53,2.65-3,2.65-5.22,0-.81-.27-1.23-.92-1.23s-.92.46-.92,1.15v.69h-.81v-.63c0-1.2.54-2,1.75-2S54.4,82,54.4,83.14Z"
style="fill: #263238"
></path>
<path
d="M58.69,83.13v.2a1.57,1.57,0,0,1-1,1.62,1.55,1.55,0,0,1,1,1.62v.6c0,1.2-.56,2-1.77,2s-1.76-.78-1.76-2v-.53H56v.59c0,.7.29,1.13.92,1.13s.91-.42.91-1.21v-.6c0-.78-.32-1.15-1-1.17h-.47V84.6h.51a.94.94,0,0,0,.94-1.08v-.35c0-.81-.28-1.22-.91-1.22s-.92.43-.92,1.14v.4h-.82v-.36c0-1.19.56-2,1.76-2S58.69,81.94,58.69,83.13Z"
style="fill: #263238"
></path>
<path d="M60.38,83.73v1.08h-.84V83.73Zm0,4.26v1.08h-.84V88Z" style="fill: #263238"></path>
<path
d="M62.14,84.43a1.28,1.28,0,0,1,1.17-.65c1,0,1.45.74,1.45,1.86v1.53c0,1.2-.57,2-1.76,2s-1.76-.78-1.76-2v-.52h.81v.58c0,.7.3,1.13.92,1.13s.92-.43.92-1.13V85.71c0-.71-.29-1.13-.92-1.13a.84.84,0,0,0-.88.84v.17h-.82l.21-4.35h3.09V82h-2.3Z"
style="fill: #263238"
></path>
<path
d="M69.12,83.12v.15H68.3v-.2c0-.71-.29-1.12-.93-1.12s-1,.42-1,1.26V85a1.26,1.26,0,0,1,1.26-.84c1,0,1.46.73,1.46,1.86v1.18c0,1.2-.59,2-1.79,2s-1.8-.78-1.8-2v-4c0-1.24.56-2,1.8-2S69.12,81.92,69.12,83.12Zm-2.7,2.93v1.18c0,.7.29,1.13.93,1.13s.93-.43.93-1.13V86.05c0-.7-.3-1.13-.93-1.13S66.42,85.35,66.42,86.05Z"
style="fill: #263238"
></path>
<rect x="152.41" y="83.47" width="2.21" height="5.53" style="fill: #263238"></rect>
<rect x="155.36" y="82.36" width="2.21" height="6.64" style="fill: #263238"></rect>
<rect x="158.31" y="81.57" width="2.21" height="7.42" style="fill: #263238"></rect>
<rect x="161.25" y="80.2" width="2.21" height="8.79" style="fill: #263238"></rect>
<path d="M190.83,88.84H177.56V80.73h13.27Zm-12.53-.73h11.79V81.47H178.3Z" style="fill: #263238"></path>
<rect x="179.41" y="82.27" width="7" height="5.03" style="fill: #263238"></rect>
<rect x="190.37" y="83.83" width="1.67" height="1.91" style="fill: #263238"></rect>
<path
d="M172.7,87.08a.48.48,0,0,1-.26-.07c-2.7-1.61-4.48-.12-4.56-.05a.49.49,0,0,1-.69,0,.5.5,0,0,1,0-.7c.1-.08,2.38-2,5.72,0a.5.5,0,0,1-.25.92Z"
style="fill: #263238"
></path>
<path
d="M173.7,85.41a.48.48,0,0,1-.26-.07c-3.9-2.32-6.53-.07-6.55,0a.5.5,0,0,1-.66-.74s3.2-2.74,7.72-.06a.49.49,0,0,1,.17.68A.48.48,0,0,1,173.7,85.41Z"
style="fill: #263238"
></path>
<path
d="M174.6,83.48a.47.47,0,0,1-.25-.07c-4.94-2.94-8.23-.17-8.37,0a.49.49,0,0,1-.7,0,.48.48,0,0,1,.05-.69s3.94-3.38,9.53-.06a.5.5,0,0,1,.17.68A.49.49,0,0,1,174.6,83.48Z"
style="fill: #263238"
></path>
<path d="M171.21,87.91A1.25,1.25,0,1,1,170,86.67,1.24,1.24,0,0,1,171.21,87.91Z" style="fill: #263238"></path>
<path
d="M121.53,217.66c22,.34,40.33,8.68,54.78,25.36a5.08,5.08,0,0,1-.47,7.33,5,5,0,0,1-7.15-.66,62.94,62.94,0,0,0-18.47-14.9,61.21,61.21,0,0,0-68.4,7.45,92.38,92.38,0,0,0-7.42,7.39,5.17,5.17,0,0,1-7.32.66,5.1,5.1,0,0,1-.36-7.33,71.44,71.44,0,0,1,45.7-24.87c1.44-.19,2.89-.35,4.34-.41S119.94,217.66,121.53,217.66Z"
style="fill: #263238"
></path>
<path
d="M123.35,238.05c13.9.36,27,6.29,37.24,18.17a5,5,0,0,1-.46,7.3,5,5,0,0,1-7.22-.7,39.62,39.62,0,0,0-19.8-12.9C117,245.56,103,249.54,91.3,261.49c-.44.45-.84.93-1.25,1.39a5.08,5.08,0,1,1-7.68-6.65,51.11,51.11,0,0,1,16.38-12.85C105.94,239.81,113.57,238.08,123.35,238.05Z"
style="fill: #263238"
></path>
<path
d="M146.21,272.81a5.08,5.08,0,0,1-3.25,4.76,5,5,0,0,1-5.66-1.42,21.34,21.34,0,0,0-7.76-5.77C121.2,266.84,112,269,105.79,276a4.92,4.92,0,0,1-5.43,1.63A5.07,5.07,0,0,1,98,269.52a30.52,30.52,0,0,1,47,.08,14.27,14.27,0,0,1,1.5,3.09Z"
style="fill: #263238"
></path>
<path d="M121.52,299.5a10.2,10.2,0,1,1,10.17-10.15A10.14,10.14,0,0,1,121.52,299.5Z" style="fill: #263238"></path>
<path
d="M121.58,182a72.72,72.72,0,1,0,72.71,72.71A72.8,72.8,0,0,0,121.58,182ZM58.86,254.75A62.68,62.68,0,0,1,164,208.56L75.39,297.13A62.52,62.52,0,0,1,58.86,254.75Zm62.72,62.72a62.4,62.4,0,0,1-38.85-13.54l88-88a62.67,62.67,0,0,1-49.18,101.57Z"
style="fill: currentColor"
></path>
</g>
<g id="freepik--Sofa--inject-163">
<polygon
points="427.5 454.81 418.02 454.81 415.99 432.25 429.53 432.25 427.5 454.81"
style="fill: #263238; stroke: #263238; stroke-miterlimit: 10"
></polygon>
<polygon
points="466.98 454.81 457.5 454.81 455.47 432.25 469.01 432.25 466.98 454.81"
style="fill: #263238; stroke: #263238; stroke-miterlimit: 10"
></polygon>
<polygon
points="372.23 454.81 362.75 454.81 360.73 432.25 374.26 432.25 372.23 454.81"
style="fill: #263238; stroke: #263238; stroke-miterlimit: 10"
></polygon>
<polygon
points="329.93 454.81 320.46 454.81 318.43 432.25 331.96 432.25 329.93 454.81"
style="fill: #263238; stroke: #263238; stroke-miterlimit: 10"
></polygon>
<path
d="M375.17,286.9h98.52s.39,34.25-4.68,58.5-11.28,38.91-11.28,38.91H364.11S378,330.67,375.17,286.9Z"
style="fill: #fff; stroke: #263238; stroke-miterlimit: 10"
></path>
<path
d="M416.06,292.13c-8.64-.68-12.07-2.42-18.53-6-8.41-4.61-10.21-1.54-9.61,3.07s-8.17,35-10,50.3-1.21,23.53-1.21,23.53-5.4,4.61-1.8,6.14a32.28,32.28,0,0,0,7.21,2.05h69.66s12.38-63.61,13.58-73.84-4.2-11.25-7.21-9.72-3.6,2.56-7.81,3.07C440.5,292,427.9,293.05,416.06,292.13Z"
style="fill: currentColor"
></path>
<path
d="M393.63,293.16a16.26,16.26,0,0,0,3.69-7.1c-.84-.45-1.61-.82-2.32-1.12a13.69,13.69,0,0,1-3.26,6.61,14.3,14.3,0,0,1-4.54,3.65c-.18.91-.38,1.9-.6,3A16.06,16.06,0,0,0,393.63,293.16Z"
style="fill: #fff"
></path>
<path
d="M456,313.06c-4.41,5.18-4.24,9.78-4.08,14.24.16,4.16.3,8.08-3.48,12.53s-7.69,4.92-11.82,5.44c-4.42.54-9,1.11-13.4,6.29s-4.25,9.78-4.08,14.23a28.53,28.53,0,0,1-.15,5.47h2.52a33.48,33.48,0,0,0,.11-5.56c-.15-4.16-.3-8.09,3.49-12.53s7.68-4.93,11.82-5.44c4.42-.54,9-1.11,13.4-6.29s4.24-9.78,4.08-14.24c-.16-4.16-.3-8.09,3.49-12.53a14,14,0,0,1,5.34-4c.17-1,.34-1.92.5-2.83A16.07,16.07,0,0,0,456,313.06Z"
style="fill: #fff"
></path>
<path
d="M385.23,370.14c4.43-.55,9-1.12,13.41-6.3s4.24-9.78,4.08-14.23c-.16-4.16-.3-8.09,3.48-12.53s7.69-4.93,11.82-5.44c4.42-.55,9-1.11,13.4-6.29s4.25-9.79,4.08-14.24c-.15-4.16-.3-8.09,3.49-12.53s7.69-4.93,11.82-5.44,8.26-1,12.34-5.14a4.35,4.35,0,0,0-2.74-.86,14.82,14.82,0,0,1-7.92,3.27,19.67,19.67,0,0,1-2.12.36l-3,.35A16.3,16.3,0,0,0,437.1,297c-4.42,5.19-4.25,9.79-4.08,14.24.15,4.16.3,8.09-3.49,12.54s-7.68,4.92-11.82,5.43c-4.42.55-9,1.11-13.4,6.29s-4.24,9.79-4.08,14.24c.16,4.16.3,8.09-3.48,12.53s-7.69,4.93-11.82,5.44a23.21,23.21,0,0,0-8.38,2.16,32.7,32.7,0,0,0,4,1.12A32.06,32.06,0,0,1,385.23,370.14Z"
style="fill: #fff"
></path>
<path
d="M379.74,347.75c4.41-5.18,4.24-9.78,4.08-14.23-.15-4.17-.3-8.09,3.49-12.54s7.68-4.92,11.81-5.43c4.42-.55,9-1.12,13.41-6.3s4.24-9.78,4.08-14.23c0-1-.07-1.91-.06-2.86l-.49,0-2-.19c0,1.07,0,2.12.05,3.17.16,4.16.3,8.09-3.48,12.53s-7.69,4.93-11.82,5.44c-4.42.55-9,1.11-13.41,6.29s-4.24,9.78-4.07,14.24c.15,4.16.29,8.09-3.49,12.53-.21.25-.42.48-.64.7-.1,1.27-.19,2.47-.26,3.59A18.26,18.26,0,0,0,379.74,347.75Z"
style="fill: #fff"
></path>
<path
d="M416.06,292.13c-8.64-.68-12.07-2.42-18.53-6-8.41-4.61-10.21-1.54-9.61,3.07s-8.17,35-10,50.3-1.21,23.53-1.21,23.53-5.4,4.61-1.8,6.14a32.28,32.28,0,0,0,7.21,2.05h69.66s12.38-63.61,13.58-73.84-4.2-11.25-7.21-9.72-3.6,2.56-7.81,3.07C440.5,292,427.9,293.05,416.06,292.13Z"
style="fill: none; stroke: #263238; stroke-miterlimit: 10"
></path>
<path
d="M375.17,286.9H369.6a4.49,4.49,0,0,0-4.37,3.45l-6.92,29c-1.28,5.38-5.66,20.88-10.48,23.59h0a19.79,19.79,0,0,1-9.69,2.53H317.26l8.88,90.77h38l10-144.53a5.11,5.11,0,0,0,0-1h1.13Z"
style="fill: #fff; stroke: #263238; stroke-miterlimit: 10"
></path>
<path
d="M322.83,345.46h20.89a19.82,19.82,0,0,0,9.69-2.53h0c4.82-2.71,9.19-18.21,10.48-23.59l6.91-29a4.5,4.5,0,0,1,4.37-3.45h0a4.49,4.49,0,0,1,4.48,4.8L369.4,436.23h-38Z"
style="fill: #fff; stroke: #263238; stroke-miterlimit: 10"
></path>
<polygon
points="412.04 436.28 414.21 371.26 327.1 370.49 329.28 436.28 412.04 436.28"
style="fill: #fff; stroke: #263238; stroke-miterlimit: 10"
></polygon>
<path
d="M479.26,286.9h-5.57a4.5,4.5,0,0,0-4.37,3.45l-6.92,29c-1.28,5.38-5.65,20.88-10.48,23.59h0a19.76,19.76,0,0,1-9.69,2.53H421.35L425,436.23h42.82L478.17,291.7a4.39,4.39,0,0,0,0-1h1.13Z"
style="fill: #fff; stroke: #263238; stroke-miterlimit: 10"
></path>
<path
d="M426.92,345.46h20.89a19.82,19.82,0,0,0,9.69-2.53h0c4.82-2.71,9.2-18.21,10.48-23.59l6.92-29a4.49,4.49,0,0,1,4.36-3.45h0a4.48,4.48,0,0,1,4.48,4.8L473.58,434a2.39,2.39,0,0,1-2.37,2.21H430.33Z"
style="fill: #fff; stroke: #263238; stroke-miterlimit: 10"
></path>
<path
d="M414.21,352,412,436.28h18.29L433.47,352a6.54,6.54,0,0,0-6.55-6.54h-6.16A6.54,6.54,0,0,0,414.21,352Z"
style="fill: #fff; stroke: #263238; stroke-miterlimit: 10"
></path>
<path
d="M307.94,352l3.14,84.28h18.29L327.19,352a6.54,6.54,0,0,0-6.54-6.54h-6.16A6.54,6.54,0,0,0,307.94,352Z"
style="fill: #fff; stroke: #263238; stroke-miterlimit: 10"
></path>
<line
x1="327.54"
y1="399.23"
x2="413.38"
y2="399.23"
style="fill: none; stroke: #263238; stroke-miterlimit: 10"
></line>
</g>
<g id="freepik--Character--inject-163">
<path
d="M285.55,287.23s-7.94,44.12-9.68,51.58-6,45.49-6,54.94.74,38,.74,38-3.23,1.49-3.23,2.73,2.49,9.2,2.49,9.2l14.66,5.47s3-7,3.23-9.45-1.74-3.48-1.74-7.71,7.46-53.44,9.7-61.64,8.7-32.81,9.94-35.05,7.46-18.64,7.46-18.64l3.48,1.74s2.23,51.7,3.48,54.93S338,429.2,338,429.2s-2.73,1.24-1,4.23,4.72,9.69,4.72,9.69,2.74-3.73,6-4.47,8.7,2.48,8.7,2.48,3.23-7.46,2.48-10.93-4-9.45-4.22-11.19-7-51.86-7-51.86,1.74-70.1,1.74-74.82a31.49,31.49,0,0,0-1.74-9.45,117.57,117.57,0,0,1-32.32,6.22c-17.65.74-27.34-6.46-27.34-6.46Z"
style="fill: #263238; stroke: #263238; stroke-miterlimit: 10"
></path>
<path
d="M269.91,443.71s-8.21,7.45-9.7,8.45-11.93,5-11.68,7,3,3.23,3,3.23h33.81s.24-1,.74-5.72a18.86,18.86,0,0,0-1.49-8.95Z"
style="fill: #fff; stroke: #263238; stroke-miterlimit: 10"
></path>
<path
d="M285.83,458.76l-37.12,1a6.16,6.16,0,0,0,2.8,2.57h33.81S285.49,461.66,285.83,458.76Z"
style="fill: #fff; stroke: #263238; stroke-miterlimit: 10"
></path>
<path
d="M341.74,443.12s-.25,6.21-.25,9.45-.49,7-.25,7.7.75,2,.75,2h19.64s.74-2-.25-5.72-2.74-5.71-3.23-9a36.31,36.31,0,0,0-1.74-6.46S346.71,433.43,341.74,443.12Z"
style="fill: #fff; stroke: #263238; stroke-miterlimit: 10"
></path>
<path
d="M361.89,459.91c-7.47,0-16.77-.24-20.72-.34a3.34,3.34,0,0,0,.07.7c.25.75.75,2,.75,2h19.64A7.22,7.22,0,0,0,361.89,459.91Z"
style="fill: #fff; stroke: #263238; stroke-miterlimit: 10"
></path>
<path
d="M278.5,193.64s-21.12,19.83-20.2,21.68S265,232.18,265,232.18s1.66,10,.74,16.31a64.54,64.54,0,0,0-.56,12.05,25.59,25.59,0,0,0,7,6.11c4.08,2.23,7.23,6.12,9.83-.18s1.48-17.61,1.48-17.61S287,262.58,287.59,265s-2,22.24-2,22.24S298.33,298,320,295.56s28.54-10,28.54-10-2.23-24.28-2.23-27.06a54,54,0,0,0-.37-5.75s7.6,7.79,11.31,7.42,10.19-15.57,8.52-18-7.41-12.25-10.93-19.29a85.73,85.73,0,0,1-5.28-13.19s-6.12-20.76-8-22.24-22.7-1.25-26.41-2.17a124.1,124.1,0,0,0-14.83-2C299.08,183.26,282.58,187.15,278.5,193.64Z"
style="fill: currentColor; stroke: #263238; stroke-miterlimit: 10"
></path>
<path
d="M340.8,221.39c-.1-5.32-.12-9.46-.12-9.46"
style="fill: none; stroke: #263238; stroke-miterlimit: 10"
></path>
<path
d="M346,252.75a78.12,78.12,0,0,1-3.7-8.89c-.74-2.21-1.13-10.1-1.34-17.49"
style="fill: none; stroke: #263238; stroke-miterlimit: 10"
></path>
<path
d="M272.93,230.8c-1.89-3.3-3.33-5.88-3.51-6.4"
style="fill: none; stroke: #263238; stroke-miterlimit: 10"
></path>
<path d="M283.51,248.86s-4.74-8-8.72-14.84" style="fill: none; stroke: #263238; stroke-miterlimit: 10"></path>
<path
d="M307.6,185.85a92.16,92.16,0,0,1,.19,19.65"
style="fill: none; stroke: #263238; stroke-miterlimit: 10"
></path>
<path
d="M320.07,277.32c2.23.45,4.62.86,7.17,1.19"
style="fill: none; stroke: #263238; stroke-miterlimit: 10"
></path>
<path d="M293.14,265.36s6,6.58,22,10.8" style="fill: none; stroke: #263238; stroke-miterlimit: 10"></path>
<path
d="M309.45,279.44a50.88,50.88,0,0,0,21.87,4.45"
style="fill: none; stroke: #263238; stroke-miterlimit: 10"
></path>
<path
d="M265.16,163.61s2.22,10.38,2.41,12.61.74,5.19,3.52,9.63,10,14.27,11.49,14.83,7.23-.93,7.23-.93,6.11,12.05,7.78,11.68,5.93-14.09,6.49-19.65a39.64,39.64,0,0,0,.18-8.34l-2.59-9.26s-2.22-13-2.22-13.9,1.29-7.6-5.93-10.38-16.13-3-22.06,3.89S265.16,163.61,265.16,163.61Z"
style="fill: #fff; stroke: #263238; stroke-miterlimit: 10"
></path>
<path
d="M285,151.94a33.32,33.32,0,0,1-10,9.82c-6.85,4.45-3.52-.37-3.52-.37s-4.82,3-8.71,5-2.41,2.6-3.89,2-7-16.38,5.39-24,21.43-5.61,21.43-5.61-5.38-2.41-.56-2.41S292,139,292,139s2.59-.74,3.7.74a4.4,4.4,0,0,0,1.77,1.17c6,2.54,8.09,8.22,9.22,14.15.74,3.89-2.41,13.16-2.41,13.16L299.08,171a12.88,12.88,0,0,1-3-4.08,15.94,15.94,0,0,1-.74-4.63s-3.15,4.07-3.71,1.11-2-10.56-2-10.56.56,3-1.29,3S285,151.94,285,151.94Z"
style="fill: #263238; stroke: #263238; stroke-miterlimit: 10"
></path>
<path
d="M298.7,172.32s-.18-6.3,3.53-8.34,6.3.19,5.18,6.12-7.78,8.15-7.78,8.15"
style="fill: #fff; stroke: #263238; stroke-miterlimit: 10"
></path>
<polygon
points="289.81 199.75 299.63 189.93 293.14 204.94 289.81 199.75"
style="fill: #263238; stroke: #263238; stroke-miterlimit: 10"
></polygon>
<path
d="M285.27,189.82a1.66,1.66,0,0,1-.51,2.2c-.67.27-1.52-.28-1.9-1.23s-.15-1.94.51-2.21S284.88,188.87,285.27,189.82Z"
style="fill: #263238"
></path>
<path
d="M287.83,172.66c.36,1.18.1,2.3-.57,2.51s-1.53-.58-1.89-1.75-.1-2.29.57-2.5S287.47,171.49,287.83,172.66Z"
style="fill: #263238"
></path>
<path
d="M275.66,174.72c.36,1.18.1,2.3-.58,2.51s-1.52-.57-1.88-1.75-.11-2.29.57-2.5S275.29,173.55,275.66,174.72Z"
style="fill: #263238"
></path>
<path
d="M276.1,170.1a7.06,7.06,0,0,1,2.59,5.56c0,3.71-.56,9.27-.56,9.27l6.68-.93"
style="fill: none; stroke: #263238; stroke-miterlimit: 10"
></path>
<path d="M280.54,167.69s3.34-5.93,8.53-4.82" style="fill: none; stroke: #263238; stroke-miterlimit: 10"></path>
<path d="M274.61,168.8s-4.07-1.29-6.85.37" style="fill: none; stroke: #263238; stroke-miterlimit: 10"></path>
<path
d="M388,216.43s4.08-1.48,5.56-2,3,.37,5.56-.92,5.56-3.9,5.75-2-.75,2.59-2.23,3.52-3.89,2.78-3.89,2.78l-.74,1.85-11.12-.92S387.1,217,388,216.43Z"
style="fill: #fff; stroke: #263238; stroke-miterlimit: 10"
></path>
<path
d="M410.35,221.22s5.11-4.05,5.85-5.9-.56-2-1.85-1.3S409,218.1,409,218.1Z"
style="fill: #fff; stroke: #263238; stroke-miterlimit: 10"
></path>
<path
d="M406.17,222.1s3.8.4,4.18-.88,3.38-9.34,2.89-10.35-1.44-.92-2.49.75a57.18,57.18,0,0,0-2.9,7.07s-2.54.57-3.18,2.31S406.17,222.1,406.17,222.1Z"
style="fill: #fff; stroke: #263238; stroke-miterlimit: 10"
></path>
<path
d="M401.37,223.1s3.53,1.49,4.27.37,5.93-8,5.74-9.08-1.11-1.29-2.59,0a55.84,55.84,0,0,0-4.82,5.93s-2.6-.18-3.71,1.3S401.37,223.1,401.37,223.1Z"
style="fill: #fff; stroke: #263238; stroke-miterlimit: 10"
></path>
<path
d="M349.67,253.5a23.39,23.39,0,0,1,10.38-14.27C368.94,233.48,381,223.1,381,223.1s4.08-5.74,7-6.67,12.6,1.85,12.6,1.85,7.79-7.78,8-6.11-3.7,7.6-5.56,9.82-7.6,2.78-8.89,2.78a67,67,0,0,0-6.86.56c-.74.18-13,16.86-18.53,25s-8,9.63-11.49,9.82-7.23-2.6-8.16-3.89S349.67,253.5,349.67,253.5Z"
style="fill: #fff; stroke: #263238; stroke-miterlimit: 10"
></path>
<path
d="M233.77,222.82l11.68,25.34a1.86,1.86,0,0,0,2,1l9.69-1.79a1.85,1.85,0,0,0,1.36-2.52L248,220.12a1.82,1.82,0,0,0-1.89-1.11l-10.89,1.21A1.84,1.84,0,0,0,233.77,222.82Z"
style="fill: #263238; stroke: #263238; stroke-miterlimit: 10"
></path>
<path
d="M241.44,244.51s-4.19-6.42-4.19-7.86,2.44-4.85,3.87-7.93,1.65-5.14,2.88-4.72,1,1.64.61,3.69a79.85,79.85,0,0,1-2.66,7.8l.41,2.47a26.4,26.4,0,0,1,3.69-5.55c1.85-1.84,3.9-4.92,5.34-4.31s2.05,1,.82,2.47a42.71,42.71,0,0,0-4.14,5.91,36.87,36.87,0,0,0-2.79,5.58,42.73,42.73,0,0,1,4.37-3.66c2-1.44,4.82-3.52,6-2.7s1.44,1.64.21,2.67-2.35,1.73-4,3.17a60.68,60.68,0,0,0-4.84,5.45,17.87,17.87,0,0,1,4.84-2.66c3.49-1.43,6.68-1.27,6.81-.17s-3.67,2.1-3.67,2.1c-2.72.62-2.85,1.55-2.85,1.55s2.26,4.52,1.85,6c0,0,9.12-1.43,12.61-2.45s8.94,1,10.59,2.65c3.49,3.49,5.13,8.83,3.29,13.35s-1.85,3.08-16.43-1-14.3-5.54-17.86-11.5C244.91,252.54,241.44,244.51,241.44,244.51Z"
style="fill: #fff; stroke: #263238; stroke-miterlimit: 10"
></path>
<line
x1="254.06"
y1="253.77"
x2="253.75"
y2="257.53"
style="fill: none; stroke: #263238; stroke-miterlimit: 10"
></line>
</g>
</svg>
</template>
<script setup lang="ts"></script>
<style scoped></style>

View File

@@ -0,0 +1,8 @@
import SvgNoPermission from './SvgNoPermission.vue';
import SvgNotFound from './SvgNotFound.vue';
import SvgServiceError from './SvgServiceError.vue';
import SvgEmptyData from './SvgEmptyData.vue';
import SvgNetworkError from './SvgNetworkError.vue';
import SvgBanner from './SvgBanner.vue';
export { SvgNoPermission, SvgNotFound, SvgServiceError, SvgEmptyData, SvgNetworkError, SvgBanner };

View File

@@ -1,5 +1,3 @@
export * from './route';
export * from './router';
export * from './system';
export * from './router';
export * from './layout';
export * from './theme';

View File

@@ -1,82 +1,70 @@
import { ref, computed, watch } from 'vue';
import type { ScrollbarInst } from 'naive-ui';
import { useThemeStore, useAppStore } from '@/store';
import { useRouteProps } from './route';
import { computed } from 'vue';
import { useAppStore, useThemeStore } from '@/store';
import type { ThemeLayoutMode, GlobalHeaderProps } from '@/interface';
export function useLayoutConfig() {
const theme = useThemeStore();
type LayoutHeaderProps = Record<ThemeLayoutMode, GlobalHeaderProps>;
export function useBasicLayout() {
const app = useAppStore();
const { setScrollbarInstance } = useAppStore();
const routeProps = useRouteProps();
const theme = useThemeStore();
/** 反转sider */
const siderInverted = computed(() => theme.navStyle.theme !== 'light');
/** 侧边菜单宽度 */
const siderMenuWidth = computed(() => {
const { collapsed } = app.menu;
const { collapsedWidth, width } = theme.menuStyle;
return collapsed ? collapsedWidth : width;
type LayoutMode = 'vertical' | 'horizontal';
const mode = computed(() => {
const vertical: LayoutMode = 'vertical';
const horizontal: LayoutMode = 'horizontal';
return theme.layout.mode.includes(vertical) ? vertical : horizontal;
});
/** 反转header */
const headerInverted = computed(() => (theme.navStyle.theme !== 'dark' ? siderInverted.value : !siderInverted.value));
/** 头部定位 */
const headerPosition = computed(() => (theme.fixedHeaderAndTab ? 'absolute' : 'static'));
/** 全局头部的高度(px) */
const headerHeight = computed(() => `${theme.headerStyle.height}px`);
/** 多页签Tab的高度(px) */
const multiTabHeight = computed(() => `${theme.multiTabStyle.height}px`);
/** 全局头部和多页签的总高度 */
const headerAndMultiTabHeight = computed(() => {
const {
multiTabStyle: { visible, height: tabHeight },
headerStyle: { height: headerHeight }
} = theme;
const height = visible ? headerHeight + tabHeight : headerHeight;
return `${height}px`;
});
/** 全局侧边栏的样式 */
const globalSiderClassAndStyle = {
class: 'transition-all duration-300 ease-in-out',
style: 'z-index:12;box-shadow: 2px 0 8px 0 rgb(29 35 41 / 5%);'
const layoutHeaderProps: LayoutHeaderProps = {
vertical: {
showLogo: false,
showHeaderMenu: false,
showMenuCollape: true
},
'vertical-mix': {
showLogo: false,
showHeaderMenu: false,
showMenuCollape: false
},
horizontal: {
showLogo: true,
showHeaderMenu: true,
showMenuCollape: false
},
'horizontal-mix': {
showLogo: true,
showHeaderMenu: false,
showMenuCollape: true
}
};
/** 纵向flex布局样式 */
const flexColumnStyle = 'display:flex;flex-direction:column;height:100%;';
const headerProps = computed(() => layoutHeaderProps[theme.layout.mode]);
/** scrollbar的content的样式 */
const scrollbarContentStyle = computed(() => {
const { fullPage } = routeProps.value;
const height = fullPage ? '100%' : 'auto';
return `display:flex;flex-direction:column;height:${height};min-height:100%;`;
});
/** 滚动条实例 */
const scrollbar = ref<ScrollbarInst | null>(null);
watch(scrollbar, newValue => {
if (newValue) {
setScrollbarInstance(newValue);
const siderVisible = computed(() => theme.layout.mode !== 'horizontal');
const siderWidth = computed(() => {
const { width, mixWidth, mixChildMenuWidth } = theme.sider;
const isVerticalMix = theme.layout.mode === 'vertical-mix';
let w = isVerticalMix ? mixWidth : width;
if (isVerticalMix && app.mixSiderFixed) {
w += mixChildMenuWidth;
}
return w;
});
const siderCollapsedWidth = computed(() => {
const { collapsedWidth, mixCollapsedWidth, mixChildMenuWidth } = theme.sider;
const isVerticalMix = theme.layout.mode === 'vertical-mix';
let w = isVerticalMix ? mixCollapsedWidth : collapsedWidth;
if (isVerticalMix && app.mixSiderFixed) {
w += mixChildMenuWidth;
}
return w;
});
return {
siderInverted,
siderMenuWidth,
headerInverted,
headerPosition,
headerHeight,
multiTabHeight,
headerAndMultiTabHeight,
globalSiderClassAndStyle,
flexColumnStyle,
scrollbarContentStyle,
scrollbar
mode,
headerProps,
siderVisible,
siderWidth,
siderCollapsedWidth
};
}

View File

@@ -1,75 +0,0 @@
import { computed, watch } from 'vue';
import { useRoute } from 'vue-router';
import { routeName } from '@/router';
import type { RouteKey } from '@/interface';
/**
* 路由属性
*/
export function useRouteProps() {
const route = useRoute();
const props = computed(() => {
/** 路由名称 */
const name = route.name as string;
/** 缓存页面 */
const keepAlive = Boolean(route.meta?.keepAlive);
/** 视高100% */
const fullPage = Boolean(route.meta?.fullPage);
return {
name,
keepAlive,
fullPage
};
});
return props;
}
/**
* 路由查询参数
*/
export function useRouteQuery() {
const route = useRoute();
/** 登录跳转链接 */
const loginRedirectUrl = computed(() => {
let url: string | undefined;
if (route.name === routeName('login')) {
url = (route.query?.redirectUrl as string) || '';
}
return url;
});
return {
loginRedirectUrl
};
}
/**
* 路由名称变化后的回调
* @param callback
*/
export function routeNameWatcher(callback: (name: RouteKey) => void) {
const route = useRoute();
watch(
() => route.name,
newValue => {
callback(newValue as RouteKey);
}
);
}
/**
* 路由全路径变化后的回调
* @param callback
*/
export function routeFullPathWatcher(callback: (fullPath: string) => void) {
const route = useRoute();
watch(
() => route.fullPath,
newValue => {
callback(newValue);
}
);
}

View File

@@ -1,69 +1,86 @@
import { useRouter, useRoute } from 'vue-router';
import { useRouter } from 'vue-router';
import type { RouteLocationRaw } from 'vue-router';
import { router as globalRouter, routePath } from '@/router';
import type { LoginModuleType } from '@/interface';
import { router as globalRouter, routeName } from '@/router';
import { LoginModuleKey } from '@/interface';
/**
* 路由跳转
* @param inSetup - 是否在vue页面/组件的setup里面调用
* @param inSetup - 是否在vue页面/组件的setup里面调用在axios里面无法使用useRouter和useRoute
*/
export function useRouterPush(inSetup: boolean = true) {
const router = inSetup ? useRouter() : globalRouter;
const route = inSetup ? useRoute() : null;
/** 跳转首页 */
function toHome() {
router.push('/');
}
const route = globalRouter.currentRoute;
/**
* 重定向地址
* - current: 取当前的path作为重定向地址
* 路由跳转
* @param to - 需要跳转的路由
* @param newTab - 是否在新的浏览器Tab标签打开
*/
type LoginRedirect = 'current' | string;
/**
* 跳转登录页面(通过vue路由)
* @param module - 展示的登录模块
* @param redirectUrl - 重定向地址
*/
function toLogin(module: LoginModuleType = 'pwd-login', redirectUrl: LoginRedirect = 'current') {
const routeLocation: RouteLocationRaw = {
path: routePath('login'),
query: { module }
};
if (redirectUrl) {
let url = redirectUrl;
if (redirectUrl === 'current') {
url = router.currentRoute.value.fullPath;
}
routeLocation.query!.redirectUrl = url;
}
router.push(routeLocation);
}
/**
* 登陆页跳转登陆页
* @param module - 展示的登录模块
* @param query - 查询参数
*/
function toCurrentLogin(module: LoginModuleType) {
if (route) {
const { query } = route;
router.push({ path: routePath('login'), query: { ...query, module } });
function routerPush(to: RouteLocationRaw, newTab = false) {
if (newTab) {
const routerData = router.resolve(to);
window.open(routerData.href, '_blank');
} else {
throw Error('该函数必须在setup里面调用');
router.push(to);
}
}
/** 登录后跳转重定向的地址 */
function toLoginRedirectUrl(path: string) {
router.push(path);
/** 返回上一级路由 */
function routerBack() {
router.go(-1);
}
/**
* 跳转首页
* @param newTab - 在新的浏览器标签打开
*/
function toHome(newTab = false) {
routerPush({ name: routeName('root') }, newTab);
}
/**
* 跳转登录页面
* @param loginModule - 展示的登录模块
* @param redirectUrl - 重定向地址(登录成功后跳转的地址),默认undefined表示取当前地址为重定向地址
*/
function toLogin(loginModule?: LoginModuleKey, redirectUrl?: string) {
const module: LoginModuleKey = loginModule || 'pwd-login';
const routeLocation: RouteLocationRaw = {
name: routeName('login'),
params: { module }
};
const redirect = redirectUrl || route.value.fullPath;
Object.assign(routeLocation, { query: { redirect } });
routerPush(routeLocation);
}
/**
* 登录页切换其他模块
* @param module - 切换后的登录模块
*/
function toLoginModule(module: LoginModuleKey) {
const { query } = route.value;
routerPush({ name: routeName('login'), params: { module }, query });
}
/**
* 登录成功后跳转重定向的地址
*/
function toLoginRedirect() {
const { query } = route.value;
if (query?.redirect) {
routerPush(query.redirect as string);
} else {
toHome();
}
}
return {
routerPush,
routerBack,
toHome,
toLogin,
toCurrentLogin,
toLoginRedirectUrl
toLoginModule,
toLoginRedirect
};
}

View File

@@ -1,8 +1,23 @@
import { useBreakpoints, breakpointsTailwind } from '@vueuse/core';
/** 项目名称 */
export function useAppTitle() {
return import.meta.env.VITE_APP_TITLE as string;
interface AppInfo {
/** 项目名称 */
name: string;
/** 项目标题 */
title: string;
/** 项目描述 */
desc: string;
}
/** 项目信息 */
export function useAppInfo(): AppInfo {
const { VITE_APP_NAME: name, VITE_APP_TITLE: title, VITE_APP_DESC: desc } = import.meta.env;
return {
name,
title,
desc
};
}
/** 是否是移动端 */

View File

@@ -1,29 +0,0 @@
import { computed, watch } from 'vue';
import { darkTheme } from 'naive-ui';
import { useDark } from '@vueuse/core';
import { useThemeStore } from '@/store';
/** 系统暗黑模式 */
export function useDarkMode() {
const osDark = useDark();
const theme = useThemeStore();
const { handleDarkMode } = useThemeStore();
/** naive-ui暗黑主题 */
const naiveTheme = computed(() => (theme.darkMode ? darkTheme : undefined));
// 监听操作系统主题模式
watch(
osDark,
newValue => {
handleDarkMode(newValue);
},
{
immediate: true
}
);
return {
naiveTheme
};
}

View File

@@ -0,0 +1,2 @@
export * from './service';
export * from './regexp';

View File

@@ -0,0 +1,20 @@
/** 手机号码正则 */
export const REGEXP_PHONE =
/^[1](([3][0-9])|([4][0,1,4-9])|([5][0-3,5-9])|([6][2,5,6,7])|([7][0-8])|([8][0-9])|([9][0-3,5-9]))[0-9]{8}$/;
/** 邮箱正则 */
export const REGEXP_EMAIL = /^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/;
/** 密码正则(密码为8-18位数字/字符/符号的组合) */
export const REGEXP_PWD =
/^(?![0-9]+$)(?![a-z]+$)(?![A-Z]+$)(?!([^(0-9a-zA-Z)]|[()])+$)(?!^.*[\u4E00-\u9FA5].*$)([^(0-9a-zA-Z)]|[()]|[a-z]|[A-Z]|[0-9]){8,18}$/;
/** 6位数字验证码正则 */
export const REGEXP_CODE_SIX = /^\d{6}$/;
/** 4位数字验证码正则 */
export const REGEXP_CODE_FOUR = /^\d{4}$/;
/** url链接正则 */
export const REGEXP_URL =
/(((^https?:(?:\/\/)?)(?:[-;:&=+$,\w]+@)?[A-Za-z0-9.-]+(?::\d+)?|(?:www.|[-;:&=+$,\w]+@)[A-Za-z0-9.-]+)((?:\/[+~%/.\w-_]*)?\??(?:[-+=&;%@.\w_]*)#?(?:[\w]*))?)$/;

View File

@@ -4,24 +4,27 @@ export const REQUEST_TIMEOUT = 60 * 1000;
/** 错误信息的显示时间 */
export const ERROR_MSG_DURATION = 3 * 1000;
/** 兜底的请求错误code */
/** 默认的请求错误code */
export const DEFAULT_REQUEST_ERROR_CODE = 'DEFAULT';
/** 兜底的请求错误文本 */
/** 默认的请求错误文本 */
export const DEFAULT_REQUEST_ERROR_MSG = '请求错误~';
/** 请求超时的错误code(为固定值ECONNABORTED) */
export const REQUEST_TIMEOUT_CODE = 'ECONNABORTED';
/** 请求超时的错误文本 */
export const REQUEST_TIMEOUT_MSG = '请求超时~';
/** 网络不可用的code */
export const NETWORK_ERROR_CODE = 'NETWORK_ERROR';
/** 网络不可用的错误文本 */
export const NETWORK_ERROR_MSG = '网络不可用~';
/** 请求不成功各种状态的错误 */
export const ERROR_STATUS = {
400: '400: 请求出现语法错误',
400: '400: 请求出现语法错误~',
401: '401: 用户未授权~',
403: '403: 服务器拒绝访问~',
404: '404: 请求的资源不存在~',
@@ -32,8 +35,12 @@ export const ERROR_STATUS = {
502: '502: 错误网关~',
503: '503: 服务不可用~',
504: '504: 网关超时~',
505: '505: http版本不支持该请求~'
505: '505: http版本不支持该请求~',
[DEFAULT_REQUEST_ERROR_CODE]: DEFAULT_REQUEST_ERROR_MSG
};
/** 不弹出错误信息的code */
export const NO_ERROR_MSG_CODE: (string | number)[] = [];
/** token失效需要刷新token的code */
export const REFRESH_TOKEN_CODE: (string | number)[] = [66666];

1
src/config/index.ts Normal file
View File

@@ -0,0 +1 @@
export * from './common';

View File

@@ -1,10 +0,0 @@
import useReloadContext from './useReloadContext';
const { useReloadProvide, useReloadInject } = useReloadContext();
/** 从App组件注入provide */
function setupAppContext() {
useReloadProvide();
}
export { setupAppContext, useReloadInject };

View File

@@ -1,33 +0,0 @@
import { ref, nextTick } from 'vue';
import type { Ref } from 'vue';
import { useContext } from '@/hooks';
interface ReloadContext {
reload: Ref<boolean>;
handleReload(): void;
}
const { useProvide, useInject: useReloadInject } = useContext<ReloadContext>();
/** 重载上下文 */
export default function useReloadContext() {
const reload = ref(true);
function handleReload() {
reload.value = false;
nextTick(() => {
reload.value = true;
});
}
const context: ReloadContext = {
reload,
handleReload
};
function useReloadProvide() {
useProvide(context);
}
return {
useReloadProvide,
useReloadInject
};
}

View File

@@ -1,2 +0,0 @@
export * from './app';
export * from './part';

View File

@@ -1,3 +0,0 @@
import useVerticalMixSiderContext from './useVerticalMixSiderContext';
export { useVerticalMixSiderContext };

View File

@@ -1,54 +0,0 @@
import { ref } from 'vue';
import type { Ref } from 'vue';
import { useContext, useBoolean } from '@/hooks';
interface VerticalMixSiderContext {
/** 子菜单可见性 */
childMenuVisible: Ref<boolean>;
/** 展示子菜单 */
showChildMenu(): void;
/** 隐藏子菜单 */
hideChildMenu(): void;
/** 鼠标悬浮的一级菜单对应的路由名称 */
hoverRouteName: Ref<string>;
/** 设置悬浮路由名称 */
setHoverRouteName(name: string): void;
isMouseEnterChildMenu: Ref<boolean>;
setMouseEnterChildMenu(): void;
setMouseLeaveChildMenu(): void;
}
const { useProvide, useInject: useVerticalMixSiderInject } = useContext<VerticalMixSiderContext>();
export default function useVerticalMixSiderContext() {
const { bool: childMenuVisible, setTrue: showChildMenu, setFalse: hideChildMenu } = useBoolean();
const {
bool: isMouseEnterChildMenu,
setTrue: setMouseEnterChildMenu,
setFalse: setMouseLeaveChildMenu
} = useBoolean();
const hoverRouteName = ref('');
function setHoverRouteName(name: string) {
hoverRouteName.value = name;
}
const context: VerticalMixSiderContext = {
childMenuVisible,
showChildMenu,
hideChildMenu,
hoverRouteName,
setHoverRouteName,
isMouseEnterChildMenu,
setMouseEnterChildMenu,
setMouseLeaveChildMenu
};
function useVerticalMixSiderProvide() {
useProvide(context);
}
return {
useVerticalMixSiderProvide,
useVerticalMixSiderInject
};
}

View File

@@ -1,9 +0,0 @@
/** 动画类型 */
export enum EnumAnimate {
'zoom-fade' = '渐变',
'zoom-out' = '闪现',
'fade-slide' = '滑动',
'fade' = '消退',
'fade-bottom' = '底部消退',
'fade-scale' = '缩放消退'
}

View File

@@ -1,5 +1,5 @@
export * from './system';
export * from './theme';
export * from './animate';
export * from './typeof';
export * from './storage';
export * from './service';
export * from './system';
export * from './theme';

View File

@@ -0,0 +1,6 @@
/** http请求头的content-type类型 */
export enum ContentType {
json = 'application/json',
formUrlencoded = 'application/x-www-form-urlencoded',
formData = 'multipart/form-data'
}

View File

@@ -1,4 +1,6 @@
export enum EnumStorageKey {
/** 主题颜色 */
'theme-color' = '__THEME_COLOR__',
/** 用户token */
'token' = '__TOKEN__',
/** 用户刷新token */
@@ -6,5 +8,5 @@ export enum EnumStorageKey {
/** 用户信息 */
'user-info' = '__USER_INFO__',
/** 多页签路由信息 */
'tab-route' = '__TAB_ROUTE__'
'tab-routes' = '__TAB_ROUTES__'
}

View File

@@ -1,10 +1,3 @@
/** http请求头的content-type类型 */
export enum ContentType {
json = 'application/json',
formUrlencoded = 'application/x-www-form-urlencoded',
formData = 'multipart/form-data'
}
/** 登录模块 */
export enum EnumLoginModule {
'pwd-login' = '账密登录',

View File

@@ -1,27 +1,30 @@
/** 导航模式 */
export enum EnumNavMode {
/** 布局模式 */
export enum EnumThemeLayoutMode {
'vertical' = '左侧菜单模式',
'horizontal' = '顶部菜单模式',
'vertical-mix' = '左侧菜单混合模式',
'horizontal-mix' = '顶部菜单混合模式'
}
/** 导航风格 */
export enum EnumNavTheme {
'dark' = '暗色侧边栏',
'light' = '白色侧边栏',
'header-dark' = '暗色的侧边栏和顶栏'
}
/** 多页签风格 */
export enum EnumMultiTabMode {
'button' = '按钮风格',
'chrome' = '谷歌风格'
export enum EnumThemeTabMode {
'chrome' = '谷歌风格',
'button' = '按钮风格'
}
/** 水平模式的菜单位置 */
export enum EnumHorizontalMenuPosition {
export enum EnumThemeHorizontalMenuPosition {
'flex-start' = '居左',
'center' = '居中',
'flex-end' = '居右'
}
/** 过渡动画类型 */
export enum EnumThemeAnimateMode {
'zoom-fade' = '渐变',
'zoom-out' = '闪现',
'fade-slide' = '滑动',
'fade' = '消退',
'fade-bottom' = '底部消退',
'fade-scale' = '缩放消退'
}

View File

@@ -1,4 +1,5 @@
import useCountDown from './useCountDown';
import useSmsCode from './useSmsCode';
import useImageVerify from './useImageVerify';
export { useCountDown, useSmsCode };
export { useCountDown, useSmsCode, useImageVerify };

View File

@@ -0,0 +1,85 @@
import { ref, onMounted } from 'vue';
/**
* 绘制图形验证码
* @param width - 图形宽度
* @param height - 图形高度
*/
export default function useImageVerify(width = 152, height = 40) {
const domRef = ref<HTMLCanvasElement>();
const imgCode = ref('');
function setImgCode(code: string) {
imgCode.value = code;
}
function getImgCode() {
if (!domRef.value) return;
imgCode.value = draw(domRef.value, width, height);
}
onMounted(() => {
getImgCode();
});
return {
domRef,
imgCode,
setImgCode,
getImgCode
};
}
function randomNum(min: number, max: number) {
const num = Math.floor(Math.random() * (max - min) + min);
return num;
}
function randomColor(min: number, max: number) {
const r = randomNum(min, max);
const g = randomNum(min, max);
const b = randomNum(min, max);
return `rgb(${r},${g},${b})`;
}
function draw(dom: HTMLCanvasElement, width: number, height: number) {
let imgCode = '';
const NUMBER_STRING = '0123456789';
const ctx = dom.getContext('2d');
if (!ctx) return imgCode;
ctx.fillStyle = randomColor(180, 230);
ctx.fillRect(0, 0, width, height);
for (let i = 0; i < 4; i += 1) {
const text = NUMBER_STRING[randomNum(0, NUMBER_STRING.length)];
imgCode += text;
const fontSize = randomNum(18, 41);
const deg = randomNum(-30, 30);
ctx.font = `${fontSize}px Simhei`;
ctx.textBaseline = 'top';
ctx.fillStyle = randomColor(80, 150);
ctx.save();
ctx.translate(30 * i + 23, 15);
ctx.rotate((deg * Math.PI) / 180);
ctx.fillText(text, -15 + 5, -15);
ctx.restore();
}
for (let i = 0; i < 5; i += 1) {
ctx.beginPath();
ctx.moveTo(randomNum(0, width), randomNum(0, height));
ctx.lineTo(randomNum(0, width), randomNum(0, height));
ctx.strokeStyle = randomColor(180, 230);
ctx.closePath();
ctx.stroke();
}
for (let i = 0; i < 41; i += 1) {
ctx.beginPath();
ctx.arc(randomNum(0, width), randomNum(0, height), 1, 0, 2 * Math.PI);
ctx.closePath();
ctx.fillStyle = randomColor(150, 200);
ctx.fill();
}
return imgCode;
}

View File

@@ -1,15 +1,59 @@
import { computed } from 'vue';
import { REGEXP_PHONE } from '@/config';
import { fetchSmsCode } from '@/service';
import { useLoading } from '../common';
import useCountDown from './useCountDown';
export default function useSmsCode() {
const { loading, startLoading, endLoading } = useLoading();
const { counts, start, isCounting } = useCountDown(60);
const initLabel = '获取验证码';
const countingLabel = (second: number) => `${second}秒后重新获取`;
const label = computed(() => (isCounting.value ? countingLabel(counts.value) : initLabel));
const label = computed(() => {
let text = initLabel;
if (loading.value) {
text = '';
}
if (isCounting.value) {
text = countingLabel(counts.value);
}
return text;
});
/** 判断手机号码格式是否正确 */
function isPhoneValid(phone: string) {
let valid = true;
if (phone.trim() === '') {
window.$message?.error('手机号码不能为空!');
valid = false;
} else if (!REGEXP_PHONE.test(phone)) {
window.$message?.error('手机号码格式错误!');
valid = false;
}
return valid;
}
/**
* 获取短信验证码
* @param phone - 手机号
*/
async function getSmsCode(phone: string) {
const valid = isPhoneValid(phone);
if (!valid || loading.value) return;
startLoading();
const { data } = await fetchSmsCode(phone);
if (data) {
window.$message?.success('验证码发送成功!');
start();
}
endLoading();
}
return {
label,
start,
isCounting
isCounting,
getSmsCode,
loading
};
}

Some files were not shown because too many files have changed in this diff Show More