57 Commits

Author SHA1 Message Date
lyt
15f4144da5 'admin-23.04.12:发布v1.2.3版本,更新日志查看CHNAGELOG.md' 2023-04-12 13:33:36 +08:00
lyt
0ddb742253 'admin-23.03.37:图片显示问题,无bug' 2023-03-27 11:00:03 +08:00
lyt
87d1057174 'admin-23.03.07:优化分栏' 2023-03-07 02:50:04 +08:00
lyt
734208180f 'admin-23.02.23:发布v1.2.2版本,感谢赞助商.驰骋工作流引擎-表单引擎-低代码开发平台' 2023-02-23 01:24:57 +08:00
lyt
4589ecb6e8 'admin-22.12.12:发布v1.2.1版本,具体更新内容查看CHANGELOG.md' 2022-12-12 15:06:28 +08:00
lyt
1704a5d61c 'admin-22.12.06:发布v1.2.0版本,具体更新内容查看CHANGELOG.md' 2022-12-06 19:08:37 +08:00
lyt
5dec3d59c6 'admin-22.11.17:优化打包问题' 2022-11-17 09:55:50 +08:00
lyt
fbbc525398 'admin-22.06.27:修复模板编译可链式操作符报错' 2022-06-27 15:35:38 +08:00
lyt
4b263f3d79 'admin-22.06.12:更新v1.1.0版本' 2022-06-12 01:01:45 +08:00
lyt
81982f735f 'admin-21.12.22:优化更新请看CHANGELOG.md文件' 2021-12-22 21:11:29 +08:00
lyt
5bf34eb254 'admin-21.12.16:优化更新请看CHANGELOG.md文件' 2021-12-16 20:57:55 +08:00
lyt
d6e5455490 'admin-21.11.27:修复登录问题,感谢@jerrod,issues(#I4GIKU)' 2021-11-27 19:31:17 +08:00
lyt
c5107bd3af 'admin-21.11.08:更新优化,更新内容查看根目录CHANGELOG.md' 2021-11-08 00:46:20 +08:00
lyt
90f61ff7ca 'admin-21.10.30:更新最新依赖' 2021-10-30 20:23:08 +08:00
lyt
48d6157f45 'admin-21.09.10:更新最新依赖' 2021-09-10 23:42:46 +08:00
79e3b436a8 'admin-21.08.07:更新README.md' 2021-08-07 19:46:08 +08:00
856606c009 'admin-21.08.01:更新最新依赖' 2021-08-01 18:47:59 +08:00
4ebb31367f 'admin-21.07.03:右键菜单文字换行问题' 2021-07-03 17:35:39 +08:00
7551d8ae28 'admin-21.07.02:修复screenfull全屏时,按键盘esc键图标不改变问题,感谢群友@伯牙已遇钟子期' 2021-07-02 22:03:34 +08:00
lyt
e0786adc02 'admin-21.06.30:新增表单自适应演示界面、更新最新依赖' 2021-06-30 15:48:38 +08:00
lyt
cd43791fc3 'admin-21.06.30:新增表单自适应演示界面、更新最新依赖' 2021-06-30 15:37:33 +08:00
6708c42172 'admin-21.06.27:修复切换布局报错问题' 2021-06-27 17:53:42 +08:00
fda27398d8 'admin-21.06.19:修复诸多问题,具体查看CHANGELOG.md文件1.04更新日志' 2021-06-19 18:52:55 +08:00
e1c4d20756 'admin-21.06.19:修复诸多问题,具体查看CHANGELOG.md文件1.04更新日志' 2021-06-19 18:42:43 +08:00
c4f33fbc23 'admin-21.06.19:修复诸多问题,具体查看CHANGELOG.md文件1.04更新日志' 2021-06-19 18:27:45 +08:00
lyt
1574f1ace9 'admin-21.06.03:更正更新文案时间错误' 2021-06-03 11:49:01 +08:00
lyt
bed5e8d840 'admin-21.06.02:优化方法、更新最新依赖' 2021-06-02 17:32:55 +08:00
77e1fa9412 'admin-21.06.01:修复菜单搜索中文不可以搜索的问题,感谢群友@逍遥天意' 2021-06-01 21:08:41 +08:00
2bc69ff31f 'admin-21.05.31:修复分栏、经典布局路由设置meta.isHide为true时报错问题,感谢群友@29、@芭芭拉' 2021-05-31 22:14:51 +08:00
lyt
abef357ec0 'admin-21.05.31:修复分栏布局路由设置meta.isHide为true时报错问题,感谢群友@29' 2021-05-31 16:29:27 +08:00
lyt
cba977ad2b 'admin-21.05.28:修复布局配置设置初始值不生效问题' 2021-05-28 17:52:30 +08:00
lyt
0eaf78a849 'admin-21.05.28:布局配置新增其它设置功能' 2021-05-28 10:40:23 +08:00
103815bac1 'admin-21.05.27:新增utils下的storage.js读取浏览器缓存新写法,建议使用' 2021-05-27 21:18:47 +08:00
d95977ced4 'admin-21.05.27:新增utils下的storage.js读取浏览器缓存新写法,建议使用' 2021-05-27 21:17:46 +08:00
6386c2b952 'admin-21.05.27:新增utils下的storage.js读取浏览器缓存新写法,建议使用' 2021-05-27 21:15:26 +08:00
lyt
6bef276e48 'admin-21.05.26:更新最新依赖' 2021-05-26 11:02:08 +08:00
af6b082ebd 'admin-21.05.23:修复改变浏览器窗口时,部分布局配置失效问题' 2021-05-23 16:50:21 +08:00
lyt
8ec374e3b4 'admin-21.05.18:新增分栏布局分栏导航菜单可设置水平、垂直布局' 2021-05-18 16:09:07 +08:00
799f2b06be 'admin-21.05.16:修复全局大小件报错,优化iframe、更新最新依赖、规范工具类命名' 2021-05-16 18:37:47 +08:00
e1cb7d1a21 'admin-21.05.16:修复全局大小件报错,优化iframe、更新最新依赖、规范工具类命名' 2021-05-16 17:26:52 +08:00
lyt
c22fe7c3e5 'admin-21.05.13:修复全局改变组件大小默认值报错问题' 2021-05-13 16:49:28 +08:00
lyt
0378226aee 'admin-21.05.12:优化全局切换组件size不生效、更新最新依赖等' 2021-05-12 11:47:00 +08:00
lyt
3994b89d4a 'admin-21.05.07:更新最新依赖' 2021-05-07 15:51:49 +08:00
lyt
9dc3220fc7 'admin-21.04.29:优化自定义图标库' 2021-04-29 17:52:37 +08:00
lyt
3f7ef9f45a 'admin-2021.04.29:新增全局改变组件大小功能' 2021-04-29 10:36:05 +08:00
a2f5eb107a 'admin-21.04.28:修复themeConfig.js设置默认布局不生效的问题' 2021-04-28 20:37:09 +08:00
lyt
110482c3fb 'admin-21.04.27:更新最新依赖' 2021-04-27 16:50:21 +08:00
lyt
18ae7ff1f7 'admin-21.04.23:修复NProgress进度条不连贯问题' 2021-04-23 16:35:35 +08:00
lyt
a6ae98f284 'admin-21.04.22:部分电脑登录后首屏卡断问题,使用location.href替代router.push' 2021-04-22 17:22:24 +08:00
lyt
fcced5d3bb 'admin-21.04.22:优化加载进度条、新增在线签名页面等' 2021-04-22 17:21:30 +08:00
1c55dbcddb 'admin-21.04.21:修改异步引入组件,webpack报异常问题,感谢群友@joeb' 2021-04-21 21:26:55 +08:00
lyt
e248ed8c85 'admin-21.04.20:修改文案、优化进度条问题' 2021-04-20 11:56:35 +08:00
365a2eed96 'admin-21.04.19:新增tagsView非当前页、当前页操作示例' 2021-04-19 20:06:35 +08:00
779ea5cbc6 'admin-21.04.18:更新最新依赖、优化进度条问题' 2021-04-18 20:05:58 +08:00
lyt
ea6b527cfb 'admin-21.04.15:修改文案、链接等' 2021-04-15 15:36:53 +08:00
lyt
134c332f1f 'admin-21.04.15:修改文案、图片链接等' 2021-04-15 13:47:44 +08:00
lyt
1dbf22f584 'admin-21.04.15:基于vue2.x、elementui重构后的第一次提交' 2021-04-15 10:59:41 +08:00
294 changed files with 9306 additions and 17761 deletions

5
.env Normal file
View File

@ -0,0 +1,5 @@
# port 端口号
VUE_APP_PORT = 9999
# open 运行 npm run dev 时自动打开浏览器
VUE_APP_OPEN = false

2
.env.development Normal file
View File

@ -0,0 +1,2 @@
# 开发环境
VUE_APP_BASE_API = http://localhost:9999/

2
.env.production Normal file
View File

@ -0,0 +1,2 @@
# 线上环境
VUE_APP_BASE_API = ''

View File

@ -1,4 +1,3 @@
*.sh
node_modules
lib
@ -6,6 +5,7 @@ lib
*.scss
*.woff
*.ttf
*.json
.vscode
.idea
dist

22
.eslintrc.js Normal file
View File

@ -0,0 +1,22 @@
module.exports = {
root: true,
env: {
node: true,
},
parserOptions: {
parser: '@babel/eslint-parser',
},
plugins: ['vue'],
extends: ['plugin:vue/essential', 'eslint:recommended'],
rules: {
// http://eslint.cn/docs/rules/
'vue/no-parsing-error': 'off',
'no-unused-vars': 'error',
'no-dupe-args': 'error',
'no-empty': 'off',
'no-extra-semi': 'off',
'no-constant-condition': 'off',
'no-console': 'error',
'vue/multi-word-component-names': 'off',
},
};

31
.gitignore vendored
View File

@ -1,11 +1,22 @@
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
*.code-workspace
node_modules
.DS_Store
/dist
# Local History for Visual Studio Code
.history/
frontend/LICENSE
*.zip
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

124
CHANGELOG.md Normal file
View File

@ -0,0 +1,124 @@
# <a href="https://gitee.com/lyt-top/vue-next-admin/tree/vue-prev-admin" target="_blank">vue-prev-admin 更新日志</a>
🎉🎉🔥 `vue-prev-admin` 基于 vue2.x + webpack + element ui适配手机、平板、pc 的后台开源免费模板库vue3.x 请切换 master 分支)
## 1.2.3
`2023.04.12`
- 🐞 修复 [#I6UW2I 关闭标签页后,分栏没有消失,需要手动点击首页才会消失](https://gitee.com/lyt-top/vue-next-admin/issues/I6UW2I),感谢[@小菜鸟儿](https://gitee.com/cainiaoer)
- 🎯 优化 `layout/navBars/breadcrumb` 文件夹名称改成 `layout/navBars/topBar` 更易理解(可全局替换),感谢群友@傲世盛唐
- 🎯 优化 `layout/navBars/topBar/user.vue` 组件,`UserNews` 点击消息图标触发范围,防止点击消息通知背景色时不触发 Popover 弹出框
## 1.2.2
`2023.02.23`
🚩🚩🚩 感谢 [驰骋工作流引擎-表单引擎-低代码开发平台](http://www.ccflow.org/) 赞助商的赞助。驰骋公司为社会提供流程引擎+表单引擎+低代码开发平台一体的开源软件解决方案,欢迎广大开发者前去体验!
- 🎉 新增 赞助商组件(`/src/layout/sponsors`[项目目录结构查看](https://lyt-top.gitee.io/vue-next-admin-doc-preview/config/)
- 🎯 优化 `/src/utils/storage``key` 编写成 `${__NEXT_NAME__}:${key}`,防止部署多套系统到同一域名不同目录时,变量共用的问题(`__NEXT_NAME__``package.json` 中的 `name`
## 1.2.1
`2022.12.12`
- 🐞 优化 版本升级提示
- 🐞 优化 深色模式
## 1.2.0
`2022.12.06`
- 🎉 新增 版本升级提示
- 🎉 新增 主题色修改
- 🎉 新增 深色模式
- 🐞 优化 外链界面 `/src/layout/routerView/link.vue`
- 🐞 修复 `菜单水平折叠` 刷新界面还原默认值问题
- 💔 移除 `vue.config.js` 打包加时间戳方法,因为打包报错了
## 1.1.1
`2022.11.17`
- 🐞 优化 [vue2 版本打包出来配置路由懒加载无效。](https://gitee.com/lyt-top/vue-next-admin/issues/I5RFQT),感谢[@林建生](https://gitee.com/ljsshuai)
## 1.1.0
`2022.06.12`
- 🐞 优化 部分界面演示图片不出来问题
- 🐞 修复 [vue-prev-admin 全屏模式下,滚动条无法滚到底 #I4S79C](https://gitee.com/lyt-top/vue-next-admin/issues/I4S79C),感谢[@qfvh](https://gitee.com/qfvh)
## 1.0.9
`2021.12.22`
- 🎯 优化 部署后每次都要强制刷新清浏览器缓存问题
- 🎉 新增 工具类百分比验证演示
- 🐞 修复 tag-view 标签右键会超出浏览器
## 1.0.8
`2021.12.16`
- 🌟 更新 依赖更新最新版本
- 🎯 优化 登录界面逻辑、权限管理逻辑
- 🎯 优化 同步 vue-next-admin-images 后端控制菜单模拟数据
- 🎯 优化 菜单格式(对象改数组)
- 🐞 修复 登录页手机端样式问题
## 1.0.7
`2021.11.27`
- 🌟 更新 依赖更新最新版本
- 🐞 修复 登录问题 [#I4GIKU](https://gitee.com/lyt-top/vue-next-admin/issues/I4GIKU)
## 1.0.6
`2021.11.08`
- 🌟 更新 依赖更新最新版本
- 🎯 优化 目录移动 `@/views/layout` 移动 `@/layout` (可全局替换)
- 🎯 优化 eslint 语法检测问题,`@babel/eslint-parser` 替换已废弃的 `babel-eslint`,出现报错,请尝试降级 eslint
- 🎯 优化 vuex 文件自动导入
## 1.0.5
`2021.06.30`
- 🌟 更新 依赖更新最新版本
- 🎉 新增 表单自适应演示界面
- 🎯 优化 去掉内嵌 iframe 内边距padding
## 1.0.4
`2021.06.19`
- 🌟 更新 依赖更新最新版本
- 🎉 新增 项目仓库地址
- 🎯 优化 移除 utils/storage.ts 下的旧写法(改动较大)
- 🐞 修复 鼠标移入顶部用户信息栏 开/关全屏 文字反向问题
## 1.0.3
`2021.06.02`
- 🌟 更新 依赖更新最新版本
- 💯 优化 动态加载后端返回路由路由(模拟数据)方法
## 1.0.2
`2021.06.01`
- 🐞 修复 菜单搜索中文不可以搜索的问题,感谢群友@逍遥天意
## 1.0.1
`2021.05.31`
- 🎉 新增 新增个人中心演示空白页
- 🎉 新增 更新日志文件 `CHANGELOG.md`,以后每次更新都会在这里显示对应内容
- 🌟 更新 依赖更新最新版本
- 🐞 修复 分栏布局路由设置 `meta.isHide``true` 时报错问题,感谢群友@29@芭芭拉

42
LICENSE
View File

@ -1,21 +1,21 @@
MIT License
Copyright (c) 2022 倔强嘴角留下一抹殇
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.
MIT License
Copyright (c) 2021 lyt-Top
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.

File diff suppressed because one or more lines are too long

149
README.md

File diff suppressed because one or more lines are too long

4
babel.config.js Normal file
View File

@ -0,0 +1,4 @@
module.exports = {
presets: ['@vue/cli-plugin-babel/preset'],
plugins: ['@babel/plugin-proposal-optional-chaining'],
};

View File

@ -1,25 +0,0 @@
module.exports = {
parser: '@typescript-eslint/parser',
parserOptions: {
project: 'tsconfig.json',
tsconfigRootDir : __dirname,
sourceType: 'module',
},
plugins: ['@typescript-eslint/eslint-plugin'],
extends: [
'plugin:@typescript-eslint/recommended',
'plugin:prettier/recommended',
],
root: true,
env: {
node: true,
jest: true,
},
ignorePatterns: ['.eslintrc.js'],
rules: {
'@typescript-eslint/interface-name-prefix': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-explicit-any': 'off',
},
};

37
backend/.gitignore vendored
View File

@ -1,37 +0,0 @@
# compiled output
/dist
/node_modules
# Logs
logs
*.log
npm-debug.log*
pnpm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
package-lock.json
# OS
.DS_Store
# Tests
/coverage
/.nyc_output
# IDEs and editors
/.idea
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace
# IDE - VSCode
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
*.lock

View File

@ -1,4 +0,0 @@
{
"singleQuote": true,
"trailingComma": "all"
}

View File

@ -1,5 +0,0 @@
{
"$schema": "https://json.schemastore.org/nest-cli",
"collection": "@nestjs/schematics",
"sourceRoot": "src"
}

View File

@ -1,90 +0,0 @@
{
"name": "tsplatform",
"version": "1.1.0",
"description": "nestjs backend",
"author": "SweetHoney",
"private": true,
"license": "UNLICENSED",
"scripts": {
"prebuild": "rimraf dist",
"build": "nest build",
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
"start": "nest start",
"start:dev": "nest start --watch",
"start:debug": "nest start --debug --watch",
"start:prod": "node dist/main",
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
"test": "jest",
"test:watch": "jest --watch",
"test:cov": "jest --coverage",
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
"test:e2e": "jest --config ./test/jest-e2e.json"
},
"dependencies": {
"@fastify/static": "^6.5.0",
"@nestjs/common": "^9.0.0",
"@nestjs/config": "^2.2.0",
"@nestjs/core": "^9.0.0",
"@nestjs/jwt": "^9.0.0",
"@nestjs/platform-express": "^9.0.0",
"@nestjs/platform-fastify": "^9.2.0",
"@nestjs/swagger": "^6.1.3",
"@nestjs/typeorm": "^9.0.1",
"class-transformer": "^0.5.1",
"class-validator": "^0.13.2",
"cookie-parser": "^1.4.6",
"csurf": "^1.11.0",
"express-rate-limit": "^6.7.0",
"fastify-swagger": "^5.2.0",
"fs": "^0.0.1-security",
"helmet": "^6.0.0",
"mysql2": "^2.3.3",
"passport-jwt": "^4.0.0",
"reflect-metadata": "^0.1.13",
"rimraf": "^3.0.2",
"rxjs": "^7.2.0",
"ts-md5": "^1.3.1",
"typeorm": "^0.3.10"
},
"devDependencies": {
"@nestjs/cli": "^9.0.0",
"@nestjs/schematics": "^9.0.0",
"@nestjs/testing": "^9.0.0",
"@types/express": "^4.17.13",
"@types/jest": "28.1.8",
"@types/node": "^16.0.0",
"@types/passport-jwt": "^3.0.7",
"@types/supertest": "^2.0.11",
"@typescript-eslint/eslint-plugin": "^5.0.0",
"@typescript-eslint/parser": "^5.0.0",
"eslint": "^8.0.1",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-prettier": "^4.0.0",
"jest": "28.1.3",
"prettier": "^2.3.2",
"source-map-support": "^0.5.20",
"supertest": "^6.1.3",
"ts-jest": "28.0.8",
"ts-loader": "^9.2.3",
"ts-node": "^10.0.0",
"tsconfig-paths": "4.1.0",
"typescript": "^4.7.4"
},
"jest": {
"moduleFileExtensions": [
"js",
"json",
"ts"
],
"rootDir": "src",
"testRegex": ".*\\.spec\\.ts$",
"transform": {
"^.+\\.(t|j)s$": "ts-jest"
},
"collectCoverageFrom": [
"**/*.(t|j)s"
],
"coverageDirectory": "../coverage",
"testEnvironment": "node"
}
}

View File

@ -1,47 +0,0 @@
/*
* @Author: '490912587@qq.com' '490912587@qq.com'
* @Date: 2022-11-17 10:59:16
* @LastEditors: '490912587@qq.com' '490912587@qq.com'
* @LastEditTime: 2022-11-24 10:58:50
* @FilePath: \tsplatform\backend\src\Config\Index.ts
* @Description: 系统全局配置
*/
/**
* 系统配置
*/
export const AppConfig = {
debug: false,
port: 3000,
jwt: {
secret: "4vRk^ga52xVP$B2vYK$%r8a8hctLgbU9",
expiresIn: "60000s"
},
md5Key: `4vRk^ga52xVP$B2vYK$%r8a8hctLgbU9`
}
/**
* 数据库配置
*/
export const DataBaseConfig = {
DataBase: {
type: 'mysql',
host: '127.0.0.1',
port: 3306,
database: 'sweet_honey',
username: 'root',
password: 'root',
//是否自动迁移同步
synchronize: true,
},
DataBase1: {
type: 'mysql',
host: '127.0.0.1',
port: 3306,
database: 'test1',
username: 'root',
password: 'root',
//是否自动迁移同步
synchronize: true,
}
}

View File

@ -1,123 +0,0 @@
/*
* @Author: '490912587@qq.com' '490912587@qq.com'
* @Date: 2022-11-17 17:06:21
* @LastEditors: '490912587@qq.com' '490912587@qq.com'
* @LastEditTime: 2022-11-24 11:11:11
* @FilePath: \tsplatform\backend\src\Controller\AuthController.ts
* @Description: 系统授权控制器
*/
import { Body, Controller, Get, Post, Request, Req, UseGuards } from '@nestjs/common';
import { RestfulReturn } from 'src/Expand/RestfulReturn';
import {
ApiBearerAuth,
ApiOperation,
ApiTags,
} from '@nestjs/swagger';
import { UserService } from 'src/Service/UserService';
import { RestfulHttpCodeEnum } from 'src/Enum/Global';
import { JwtService } from '@nestjs/jwt';
import { LoginDto } from 'src/EntiyDto/LoginDto';
import { AppConfig } from 'src/Config/Index';
import { RoleService } from 'src/Service/RoleService';
import { MenuService } from 'src/Service/MenuService';
@ApiBearerAuth()
@ApiTags('系统授权管理')
@Controller('/auth')
export class AuthController {
constructor(
public readonly _restful: RestfulReturn,
public readonly _service: UserService,
public readonly _roleService: RoleService,
public readonly _menuService: MenuService,
public readonly _jwt: JwtService
) { }
@ApiOperation({
summary: '获取账号登录验证码',
description: '获取账号登录验证码'
})
@Get('/captcha')
async captcha() {
return await this._restful.toJson(
RestfulHttpCodeEnum.SUCCESS, ""
);
}
@ApiOperation({
summary: '账号密码登录',
description: '账号密码登录'
})
@Post('/login')
async login(@Body() dto: LoginDto) {
const result = await this._service.repository.findOne({ where: { UserName: dto.UserName, Password: dto.Password } });
if (result && result.Id > 0) {
const token = await this._jwt.signAsync({ uid: result.Id }, {
secret: AppConfig.jwt.secret,
expiresIn: AppConfig.jwt.expiresIn,
});
return await this._restful.toJson(
RestfulHttpCodeEnum.SUCCESS, { userinfo: result, token: token }
);
} else {
return await this._restful.toJson(
RestfulHttpCodeEnum.FAIL, "账号密码有误!"
);
}
}
@ApiOperation({
summary: '根据token获取用户信息',
description: '根据token获取用户信息'
})
@Get('/getUserInfo')
async getUserInfo(@Req() request: Request) {
try {
const token = request.headers["authorization"];
const jwtResult = await this._jwt.verifyAsync(token, { secret: AppConfig.jwt.secret, ignoreExpiration: false })
const uid = jwtResult.uid;
const result = await this._service.getById(uid);
const menuRole = await this._roleService.getMenusByRoleId(result.RoleId);
const menuIds: number[] = [];
for await (const info of menuRole) {
menuIds.push(info.MenuId);
}
const menus = await this._menuService.repository.createQueryBuilder().whereInIds(menuIds).getMany()
const permissions: string[] = [];
for await (const info of menus) {
permissions.push(info.Permission);
}
return await this._restful.toJson(
RestfulHttpCodeEnum.SUCCESS, { userInfo: result, permission: permissions }
);
}
catch (ex) {
return await this._restful.toJson(
RestfulHttpCodeEnum.FAIL, ex
);
}
}
@ApiOperation({
summary: '根据token退出登录',
description: '根据token退出登录'
})
@Get('/loginOut')
async loginOut(@Req() request: Request) {
try {
const token = request.headers["authorization"];
const jwtResult = await this._jwt.verifyAsync(token, { secret: AppConfig.jwt.secret, ignoreExpiration: false })
const uid = jwtResult.uid;
const result = await this._service.getById(uid);
return await this._restful.toJson(
RestfulHttpCodeEnum.SUCCESS, result
);
}
catch (ex) {
return await this._restful.toJson(
RestfulHttpCodeEnum.FAIL, ex
);
}
}
}

View File

@ -1,143 +0,0 @@
/*
* @Author: '490912587@qq.com' '490912587@qq.com'
* @Date: 2022-11-17 17:05:40
* @LastEditors: '490912587@qq.com' '490912587@qq.com'
* @LastEditTime: 2022-11-24 11:11:20
* @FilePath: \tsplatform\backend\src\Controller\RoleController.ts
* @Description: 省市区控制器
*/
import { Body, Controller, Get, Post, Query } from '@nestjs/common';
import { RestfulReturn } from 'src/Expand/RestfulReturn';
import {
ApiBearerAuth,
ApiOperation,
ApiTags,
} from '@nestjs/swagger';
import { IdDto, IdsDto, ListDto, PageDto } from 'src/EntiyDto/CommonDto';
import { RestfulHttpCodeEnum } from 'src/Enum/Global';
import { CityService } from 'src/Service/CityService';
import { SysCity } from 'src/Entity/SysCity';
import { Equal, Not } from 'typeorm';
@ApiBearerAuth()
@ApiTags('省市区管理')
@Controller('/city')
export class CityController {
constructor(
public readonly restful: RestfulReturn,
public readonly service: CityService
) {
}
//#region 基础控制器
@ApiOperation({
summary: '分页查询省市区列表',
description: '分页查询省市区列表'
})
@Get('/getPage')
async getPage(@Query() dto: PageDto) {
const result = await this.service.getPage(dto.Page, dto.PageSize, dto.Keywords, dto.OrderBy);
return await this.restful.toJson(
RestfulHttpCodeEnum.SUCCESS,
{
total: result[1],
page: 1,
pageSize: 10,
rows: result[0],
}
);
}
@ApiOperation({
summary: '查询省市区列表',
description: '查询省市区列表'
})
@Get('/getList')
async getList(@Query() dto: ListDto) {
const result = await this.service.getList(dto.Keywords, dto.OrderBy);
return await this.restful.toJson(
RestfulHttpCodeEnum.SUCCESS, result
);
}
@ApiOperation({
summary: '根据ID查询省市区',
description: '根据ID查询省市区'
})
@Get('/getById')
async getById(@Query() dto: IdDto) {
const result = await this.service.getById(dto.Id);
return await this.restful.toJson(
RestfulHttpCodeEnum.SUCCESS, result
);
}
@ApiOperation({
summary: '根据ID数组查询省市区',
description: '根据ID数组查询省市区'
})
@Get('/getByIds')
async getByIds(@Query() dto: IdsDto) {
const result = await this.service.getByIds(dto.Ids);
return await this.restful.toJson(
RestfulHttpCodeEnum.SUCCESS, result
);
}
@ApiOperation({
summary: '新增省市区',
description: '新增省市区'
})
@Post('/add')
async add(@Body() model: SysCity) {
const isRepeat = await this.service.repository.createQueryBuilder()
.orWhere({ RegionName: Equal(model.RegionName.trim()), })
.orWhere({ RegionCode: Equal(model.RegionCode.trim()) }).getCount();
if (isRepeat > 0) {
return await this.restful.toJson(
RestfulHttpCodeEnum.FAIL, "地区名称或者行政编号重复!"
);
} else {
const result = await this.service.save(new SysCity());
return await this.restful.toJson(
RestfulHttpCodeEnum.SUCCESS, result
);
}
}
@ApiOperation({
summary: '修改省市区',
description: '修改省市区'
})
@Post('/edit')
async edit(@Body() model: SysCity) {
const isRepeat = await this.service.repository.createQueryBuilder()
.where({ Id: Not(model.Id) })
.andWhere([{ RegionName: Equal(model.RegionName.trim()) }, { RegionCode: Equal(model.RegionCode.trim()) }])
.getCount();
if (isRepeat > 0) {
return await this.restful.toJson(
RestfulHttpCodeEnum.FAIL, "地区名称或者行政编号重复!"
);
} else {
const result = await this.service.save(new SysCity());
return await this.restful.toJson(
RestfulHttpCodeEnum.SUCCESS, result
);
}
}
@ApiOperation({
summary: '假删除省市区',
description: '假删除省市区'
})
@Post('/del')
async del(@Body() dto: IdDto) {
const result = await this.service.destroy(dto.Id);
return await this.restful.toJson(
RestfulHttpCodeEnum.SUCCESS, result
);
}
//#endregion
}

View File

@ -1,57 +0,0 @@
/*
* @Author: '490912587@qq.com' '490912587@qq.com'
* @Date: 2022-11-17 17:05:41
* @LastEditors: '490912587@qq.com' '490912587@qq.com'
* @LastEditTime: 2022-11-24 10:11:01
* @FilePath: \tsplatform\backend\src\Controller\UserController.ts
* @Description: 系统用户控制器
*/
import { Controller, Get } from '@nestjs/common';
import { RestfulReturn } from 'src/Expand/RestfulReturn';
import {
ApiBearerAuth,
ApiOperation,
ApiTags,
} from '@nestjs/swagger';
import { RestfulHttpCodeEnum } from 'src/Enum/Global';
import { CityService } from 'src/Service/CityService';
import { RoleService } from 'src/Service/RoleService';
import { MenuService } from 'src/Service/MenuService';
import { UserService } from 'src/Service/UserService';
@ApiBearerAuth()
@ApiTags('系统管理')
@Controller('/')
export class IndexController {
constructor(
public readonly restful: RestfulReturn,
public readonly role_service: RoleService,
public readonly menu_service: MenuService,
public readonly user_service: UserService,
public readonly city_service: CityService,
) {
}
@ApiOperation({
summary: '数据初始化',
description: '数据初始化'
})
@Get('/seed')
async seedData() {
//初始化账号数据
const userCount = await this.user_service.seedData();
//初始化菜单数据
const menuCount = await this.menu_service.seedData();
//初始化角色数据
const roleCounts = await this.role_service.seedData();
//初始化省市区数据
const cityCount = await this.city_service.seedData();
return await this.restful.toJson(
RestfulHttpCodeEnum.SUCCESS,
`一共Seed${userCount}条记录!\r\n` +
`一共Seed${menuCount}条记录!\r\n` +
`一共Seed${roleCounts[0]}条记录!\r\n` +
`一共Seed${roleCounts[0]}条记录!\r\n` +
`一共Seed${cityCount}条记录!`
);
}
}

View File

@ -1,294 +0,0 @@
/*
* @Author: '490912587@qq.com' '490912587@qq.com'
* @Date: 2022-11-17 09:19:20
* @LastEditors: '490912587@qq.com' '490912587@qq.com'
* @LastEditTime: 2022-11-24 00:23:12
* @FilePath: \tsplatform\backend\src\Controller\MenuController.ts
* @Description: 系统菜单控制器
*/
import { Body, Controller, Get, HttpException, HttpStatus, Post, Query } from '@nestjs/common';
import { RestfulReturn } from 'src/Expand/RestfulReturn';
import {
ApiBearerAuth,
ApiOperation,
ApiProperty,
ApiTags,
} from '@nestjs/swagger';
import { SysMenu } from 'src/Entity/SysMenu';
import { plainToClass } from 'class-transformer';
import { IdDto, IdsDto, IdStatusDto, ListDto, PageDto, RoleIdDto } from 'src/EntiyDto/CommonDto';
import { MenuService } from 'src/Service/MenuService';
import { RestfulHttpCodeEnum } from 'src/Enum/Global';
import { MenuDto } from 'src/EntiyDto/MenuDto';
import { RouteMenu } from 'src/EntiyDto/RouteMenu';
import { Equal, In, Not } from 'typeorm';
import { RoleService } from 'src/Service/RoleService';
@Controller('/menu')
@ApiBearerAuth()
@ApiTags('系统菜单管理')
export class MenuController {
constructor(
public readonly restful: RestfulReturn,
public readonly service: MenuService,
public readonly _roleService: RoleService,
) {
}
@ApiOperation({
summary: '获取所有菜单Tree菜单列表使用',
description: '获取所有菜单Tree'
})
@Get('/getMenuTree')
async getMenuTree() {
const result = await this.MenuTree(0);
return await this.restful.toJson(
RestfulHttpCodeEnum.SUCCESS, result
);
}
@ApiOperation({
summary: '根据角色ID获取用户授权的菜单Tree前端router使用',
description: '根据角色ID获取用户授权的菜单Tree'
})
@Get('/getAuthMenuTree')
async getAuthMenuTree(@Query() dto: RoleIdDto) {
if (dto.RoleId > 0) {
const result = await this.RouteTree(0, dto.RoleId);
return await this.restful.toJson(
RestfulHttpCodeEnum.SUCCESS, result
);
} else {
throw new HttpException("角色Id不能为空", HttpStatus.INTERNAL_SERVER_ERROR);
}
}
//递归获取菜单Tree
private async MenuTree(parentId: number): Promise<SysMenu[]> {
const result = await this.service.repository.createQueryBuilder()
.where({ ParentId: parentId })
.orderBy("sort", "ASC")
.getMany();
const treeList: SysMenu[] = new Array<SysMenu>;
for await (let info of result) {
const children = await this.MenuTree(info.Id);
const node: any = {
Id: info.Id,
ParentId: info.ParentId,
Type: info.Type,
Title: info.Title,
Path: info.Path,
Permission: info.Permission,
Component: info.Component,
Icon: info.Icon,
Name: info.Name,
Redirect: info.Redirect,
IsLink: info.IsLink,
IsHide: info.IsHide,
IsKeepAlive: info.IsKeepAlive,
IsAffix: info.IsAffix,
IsIframe: info.IsIframe,
Children: [],
Sort: info.Sort,
};
if (children.length > 0) {
node.Children = children;
}
treeList.push(node);
}
return treeList;
}
//递归获取前端路由Tree
private async RouteTree(parentId: number, RoleId: number): Promise<RouteMenu[]> {
const menuRole = await this._roleService.getMenusByRoleId(RoleId);
const menuIds: number[] = [];
for await (const info of menuRole) {
menuIds.push(info.MenuId);
}
const result = await this.service.repository.createQueryBuilder()
.where({ ParentId: parentId, Id: In(menuIds) })
.orderBy("sort", "ASC")
.getMany();
const treeList: RouteMenu[] = new Array<RouteMenu>;
for await (let info of result) {
const children = await this.RouteTree(info.Id, RoleId);
const node: RouteMenu = {
name: info.Name,
path: info.Path,
component: info.Component,
redirect: info.Redirect,
meta: {
title: info.Title,
icon: info.Icon,
isLink: info.IsLink,
isHide: info.IsHide,
isKeepAlive: info.IsKeepAlive,
isAffix: info.IsAffix,
isIframe: info.IsIframe,
permission: info.Permission,
},
children: [],
};
if (children.length > 0) {
for await (let item of children) {
node.children.push({
name: item.name,
path: item.path,
component: item.component,
redirect: item.redirect,
meta: {
title: item.meta.title,
icon: item.meta.icon,
isLink: item.meta.isLink,
isHide: item.meta.isHide,
isKeepAlive: item.meta.isKeepAlive,
isAffix: item.meta.isAffix,
isIframe: item.meta.isIframe,
permission: item.meta.permission,
},
children: [],
});
}
}
treeList.push(node);
}
return treeList;
}
//#region 基础控制器
@ApiOperation({
summary: '分页查询菜单列表',
description: '分页查询菜单列表'
})
@ApiProperty()
@Get('/getPage')
async getPage(@Query() dto: PageDto) {
const result = await this.service.getPage(dto.Page, dto.PageSize, dto.Keywords, dto.OrderBy);
return await this.restful.toJson(
RestfulHttpCodeEnum.SUCCESS,
{
total: result[1],
page: 1,
pageSize: 10,
rows: result[0],
}
);
}
@ApiOperation({
summary: '查询菜单列表',
description: '查询菜单列表'
})
@Get('/getList')
async getList(@Query() dto: ListDto) {
const result = await this.service.getList(dto.Keywords, dto.OrderBy);
return await this.restful.toJson(
RestfulHttpCodeEnum.SUCCESS, result
);
}
@ApiOperation({
summary: '根据ID查询菜单',
description: '根据ID查询菜单'
})
@Get('/getById')
async getById(@Query() dto: IdDto) {
const result = await this.service.getById(dto.Id);
return await this.restful.toJson(
RestfulHttpCodeEnum.SUCCESS, result
);
}
@ApiOperation({
summary: '根据ID数组查询菜单',
description: '根据ID数组查询菜单'
})
@Get('/getByIds')
async getByIds(@Query() dto: IdsDto) {
const result = await this.service.getByIds(dto.Ids);
return await this.restful.toJson(
RestfulHttpCodeEnum.SUCCESS, result
);
}
@ApiOperation({
summary: '新增菜单',
description: '新增菜单'
})
@Post('/add')
async add(@Body() dto: MenuDto) {
const model = plainToClass(SysMenu, dto);
const isRepeat = await this.service.repository.createQueryBuilder()
.orWhere({ Name: Equal(model.Name.trim()), })
.orWhere({ Permission: Equal(model.Permission.trim()) }).getCount();
if (isRepeat > 0) {
return await this.restful.toJson(
RestfulHttpCodeEnum.FAIL, "路由名称或者权限标识重复!"
);
} else {
const result = await this.service.save(model);
return await this.restful.toJson(
RestfulHttpCodeEnum.SUCCESS, result
);
}
}
@ApiOperation({
summary: '修改菜单',
description: '修改菜单'
})
@Post('/edit')
async edit(@Body() dto: MenuDto) {
const model = plainToClass(SysMenu, dto);
const isRepeat = await this.service.repository.createQueryBuilder()
.where({ Id: Not(model.Id) })
.andWhere([{ Name: Equal(model.Name.trim()) }, { Permission: Equal(model.Permission.trim()) }])
.getCount();
if (isRepeat > 0) {
return await this.restful.toJson(
RestfulHttpCodeEnum.FAIL, "路由名称或者权限标识重复!"
);
} else {
const result = await this.service.save(model);
return await this.restful.toJson(
RestfulHttpCodeEnum.SUCCESS, result
);
}
}
@ApiOperation({
summary: '假删除菜单',
description: '假删除菜单'
})
@Post('/del')
async del(@Body() dto: IdDto) {
const result = await this.service.destroy(dto.Id);
return await this.restful.toJson(
RestfulHttpCodeEnum.SUCCESS, result
);
}
@ApiOperation({
summary: '修改菜单状态',
description: '修改菜单状态'
})
@Post('/setStatus')
async setStatus(@Body() dto: IdStatusDto) {
const result = await this.service.repository.createQueryBuilder()
.update()
.set({
Status: dto.Status
})
.where("Id = :Id", { Id: dto.Id })
.execute();
if (result.affected > 0) {
return await this.restful.toJson(
RestfulHttpCodeEnum.SUCCESS, result
);
} else {
return await this.restful.toJson(
RestfulHttpCodeEnum.FAIL, result
);
}
}
//#endregion
}

View File

@ -1,189 +0,0 @@
/*
* @Author: '490912587@qq.com' '490912587@qq.com'
* @Date: 2022-11-17 17:05:40
* @LastEditors: '490912587@qq.com' '490912587@qq.com'
* @LastEditTime: 2022-11-23 22:32:29
* @FilePath: \tsplatform\backend\src\Controller\RoleController.ts
* @Description: 系统角色控制器
*/
import { Body, Controller, Get, Post, Query } from '@nestjs/common';
import { RestfulReturn } from 'src/Expand/RestfulReturn';
import {
ApiBearerAuth,
ApiOperation,
ApiTags,
} from '@nestjs/swagger';
import { RoleService } from 'src/Service/RoleService';
import { IdDto, IdsDto, IdStatusDto, ListDto, PageDto } from 'src/EntiyDto/CommonDto';
import { RestfulHttpCodeEnum } from 'src/Enum/Global';
import { SysRole } from 'src/Entity/SysRole';
import { RoleDto } from 'src/EntiyDto/RoleDto';
import { plainToClass } from 'class-transformer';
import { Not } from 'typeorm';
@ApiBearerAuth()
@ApiTags('系统角色管理')
@Controller('/role')
export class RoleController {
constructor(
public readonly restful: RestfulReturn,
public readonly service: RoleService
) {
}
//#region 基础控制器
@ApiOperation({
summary: '分页查询角色列表',
description: '分页查询角色列表'
})
@Get('/getPage')
async getPage(@Query() dto: PageDto) {
const result = await this.service.getPage(dto.Page, dto.PageSize, dto.Keywords, dto.OrderBy);
return await this.restful.toJson(
RestfulHttpCodeEnum.SUCCESS,
{
total: result[1],
page: 1,
pageSize: 10,
rows: result[0],
}
);
}
@ApiOperation({
summary: '查询角色列表',
description: '查询角色列表'
})
@Get('/getList')
async getList(@Query() dto: ListDto) {
const result = await this.service.getList(dto.Keywords, dto.OrderBy);
return await this.restful.toJson(
RestfulHttpCodeEnum.SUCCESS, result
);
}
@ApiOperation({
summary: '根据ID查询角色',
description: '根据ID查询角色'
})
@Get('/getById')
async getById(@Query() dto: IdDto) {
const result = await this.service.getById(dto.Id);
return await this.restful.toJson(
RestfulHttpCodeEnum.SUCCESS, result
);
}
@ApiOperation({
summary: '根据ID数组查询角色',
description: '根据ID数组查询角色'
})
@Get('/getByIds')
async getByIds(@Query() dto: IdsDto) {
const result = await this.service.getByIds(dto.Ids);
return await this.restful.toJson(
RestfulHttpCodeEnum.SUCCESS, result
);
}
@ApiOperation({
summary: '新增角色',
description: '新增角色'
})
@Post('/add')
async add(@Body() dto: RoleDto) {
const model = plainToClass(SysRole, dto);
const isRepeat = await this.service.repository.count({
where: { Name: model.Name.trim() }
});
if (isRepeat > 0) {
return await this.restful.toJson(
RestfulHttpCodeEnum.FAIL, "角色名称重复!"
);
} else {
const result = await this.service.save(model);
if (result) {
return await this.restful.toJson(
RestfulHttpCodeEnum.SUCCESS, result
);
} else {
return await this.restful.toJson(
RestfulHttpCodeEnum.FAIL, result
);
}
}
}
@ApiOperation({
summary: '修改角色',
description: '修改角色'
})
@Post('/edit')
async edit(@Body() dto: RoleDto) {
const model = plainToClass(SysRole, dto);
const isRepeat = await this.service.repository.count({
where: { Id: Not(model.Id), Name: model.Name.trim() }
});
if (isRepeat > 0) {
return await this.restful.toJson(
RestfulHttpCodeEnum.FAIL, "角色名称重复!"
);
} else {
const result = await this.service.save(model);
if (result) {
return await this.restful.toJson(
RestfulHttpCodeEnum.SUCCESS, result
);
} else {
return await this.restful.toJson(
RestfulHttpCodeEnum.FAIL, result
);
}
}
}
@ApiOperation({
summary: '删除角色',
description: '删除角色'
})
@Post('/del')
async del(@Body() dto: IdDto) {
const result = await this.service.destroy(dto.Id);
if (result) {
return await this.restful.toJson(
RestfulHttpCodeEnum.SUCCESS, result
);
} else {
return await this.restful.toJson(
RestfulHttpCodeEnum.FAIL, result
);
}
}
@ApiOperation({
summary: '修改角色状态',
description: '修改角色状态'
})
@Post('/setStatus')
async setStatus(@Body() dto: IdStatusDto) {
const result = await this.service.repository.createQueryBuilder()
.update()
.set({
Status: dto.Status
})
.where("Id = :Id", { Id: dto.Id })
.execute();
if (result.affected > 0) {
return await this.restful.toJson(
RestfulHttpCodeEnum.SUCCESS, result
);
} else {
return await this.restful.toJson(
RestfulHttpCodeEnum.FAIL, result
);
}
}
//#endregion
}

View File

@ -1,188 +0,0 @@
/*
* @Author: '490912587@qq.com' '490912587@qq.com'
* @Date: 2022-11-17 17:05:41
* @LastEditors: '490912587@qq.com' '490912587@qq.com'
* @LastEditTime: 2022-11-23 22:49:42
* @FilePath: \tsplatform\backend\src\Controller\UserController.ts
* @Description: 系统用户控制器
*/
import { Body, Controller, Get, Post, Query } from '@nestjs/common';
import { RestfulReturn } from 'src/Expand/RestfulReturn';
import {
ApiBearerAuth,
ApiOperation,
ApiTags,
} from '@nestjs/swagger';
import { UserService } from 'src/Service/UserService';
import { SysUser } from 'src/Entity/SysUser';
import { IdDto, IdsDto, IdStatusDto, ListDto, PageDto } from 'src/EntiyDto/CommonDto';
import { RestfulHttpCodeEnum } from 'src/Enum/Global';
import { plainToClass } from 'class-transformer';
import { AppConfig } from 'src/Config/Index';
import { Md5 } from 'ts-md5';
import { UserDto } from 'src/EntiyDto/UserDto';
import { Equal, Not } from 'typeorm';
@ApiBearerAuth()
@ApiTags('系统用户管理')
@Controller('/user')
export class UserController {
constructor(
public readonly restful: RestfulReturn,
public readonly service: UserService
) {
}
//#region 基础控制器
@ApiOperation({
summary: '分页查询用户列表',
description: '分页查询用户列表'
})
@Get('/getPage')
async getPage(@Query() dto: PageDto) {
const result = await this.service.getPage(dto.Page, dto.PageSize, dto.Keywords, dto.OrderBy);
return await this.restful.toJson(
RestfulHttpCodeEnum.SUCCESS,
{
total: result[1],
page: 1,
pageSize: 10,
rows: result[0],
}
);
}
@ApiOperation({
summary: '查询用户列表',
description: '查询用户列表'
})
@Get('/getList')
async getList(@Query() dto: ListDto) {
const result = await this.service.getList(dto.Keywords, dto.OrderBy);
return await this.restful.toJson(
RestfulHttpCodeEnum.SUCCESS, result
);
}
@ApiOperation({
summary: '根据ID查询用户',
description: '根据ID查询用户'
})
@Get('/getById')
async getById(@Query() dto: IdDto) {
const result = await this.service.getById(dto.Id);
return await this.restful.toJson(
RestfulHttpCodeEnum.SUCCESS, result
);
}
@ApiOperation({
summary: '根据ID数组查询用户',
description: '根据ID数组查询用户'
})
@Get('/getByIds')
async getByIds(@Query() dto: IdsDto) {
const result = await this.service.getByIds(dto.Ids);
return await this.restful.toJson(
RestfulHttpCodeEnum.SUCCESS, result
);
}
@ApiOperation({
summary: '新增用户',
description: '新增用户'
})
@Post('/add')
async add(@Body() dto: UserDto) {
const model = plainToClass(SysUser, dto);
const isRepeat = await this.service.repository.createQueryBuilder()
.orWhere({ UserName: Equal(model.UserName.trim()), })
.orWhere({ Phone: Equal(model.Phone.trim()) })
.orWhere({ Email: Equal(model.Email.trim()) }).getCount();
if (isRepeat > 0) {
return await this.restful.toJson(
RestfulHttpCodeEnum.FAIL, "账号/手机号/邮箱重复!"
);
} else {
//给新用户设置个默认密码888888用户登录后可以自行修改密码
model.Password = Md5.hashStr(Md5.hashStr("888888") + AppConfig.md5Key);
const result = await this.service.save(model);
if (result) {
return await this.restful.toJson(
RestfulHttpCodeEnum.SUCCESS, result
);
} else {
return await this.restful.toJson(
RestfulHttpCodeEnum.FAIL, result
);
}
}
}
@ApiOperation({
summary: '修改用户',
description: '修改用户'
})
@Post('/edit')
async edit(@Body() dto: UserDto) {
const model = plainToClass(SysUser, dto);
const isRepeat = await this.service.repository.createQueryBuilder()
.where({ Id: Not(model.Id) })
.andWhere([{ UserName: Equal(model.UserName.trim()) }, { Phone: Equal(model.Phone.trim()) }, { Email: Equal(model.Email.trim()) }])
.getCount();
if (isRepeat > 0) {
return await this.restful.toJson(
RestfulHttpCodeEnum.FAIL, "账号/手机号/邮箱重复!"
);
} else {
//给新用户设置个默认密码888888用户登录后可以自行修改密码
model.Password = Md5.hashStr(Md5.hashStr("888888") + AppConfig.md5Key);
const result = await this.service.save(model);
if (result) {
return await this.restful.toJson(
RestfulHttpCodeEnum.SUCCESS, result
);
} else {
return await this.restful.toJson(
RestfulHttpCodeEnum.FAIL, result
);
}
}
}
@ApiOperation({
summary: '假删除用户',
description: '假删除用户'
})
@Post('/del')
async del(@Body() dto: IdDto) {
const result = await this.service.destroy(dto.Id);
return await this.restful.toJson(
RestfulHttpCodeEnum.SUCCESS, result
);
}
@ApiOperation({
summary: '修改用户状态',
description: '修改用户状态'
})
@Post('/setStatus')
async setStatus(@Body() dto: IdStatusDto) {
const result = await this.service.repository.createQueryBuilder()
.update()
.set({
Status: dto.Status
})
.where("Id = :Id", { Id: dto.Id })
.execute();
if (result.affected > 0) {
return await this.restful.toJson(
RestfulHttpCodeEnum.SUCCESS, result
);
} else {
return await this.restful.toJson(
RestfulHttpCodeEnum.FAIL, result
);
}
}
//#endregion
}

View File

@ -1,43 +0,0 @@
/*
* @Author: '490912587@qq.com' '490912587@qq.com'
* @Date: 2022-11-17 11:26:13
* @LastEditors: '490912587@qq.com' '490912587@qq.com'
* @LastEditTime: 2022-11-22 21:57:27
* @FilePath: \tsplatform\backend\src\Entity\SysBase.ts
* @Description: 系统基类实体模型
*/
import { Entity, Column, PrimaryColumn, PrimaryGeneratedColumn, CreateDateColumn, UpdateDateColumn, VersionColumn } from 'typeorm';
@Entity()
export class SysBase {
@PrimaryGeneratedColumn()
@PrimaryColumn({ comment: "ID" })
Id: number;
@Column({ comment: "状态", default: 0, nullable: true })
Status: number;
@Column({ comment: "商户/站点ID", default: 0, nullable: true })
MerchantId: number;
//自动为实体插入日期
@CreateDateColumn()
CreateTime: Date;
//每次调用实体管理器或存储库的save时自动更新实体日期
@UpdateDateColumn()
UpdateTime: Date;
@Column({ comment: "操作人ID", default: 0, nullable: true })
OperatorId: number;
@Column({ comment: "修改人ID", default: 0, nullable: true })
UpdateUserId: number;
@Column({ comment: "是否删除", default: false, nullable: true })
IsDelete: boolean;
//每次调用实体管理器或存储库的save时自动增长实体版本
@VersionColumn()
Version: number;
}

View File

@ -1,35 +0,0 @@
/*
* @Author: '490912587@qq.com' '490912587@qq.com'
* @Date: 2022-11-17 13:12:19
* @LastEditors: '490912587@qq.com' '490912587@qq.com'
* @LastEditTime: 2022-11-18 14:18:50
* @FilePath: \tsplatform\backend\src\Entity\SysCity.ts
* @Description: 系统城市实体模型
*/
import { Entity, Column, PrimaryColumn, PrimaryGeneratedColumn } from 'typeorm';
@Entity()
export class SysCity {
@PrimaryGeneratedColumn()
@PrimaryColumn({ comment: "ID" })
Id: number;
@Column({ comment: "地区编号" })
RegionId: string;
@Column({ comment: "地区名称" })
RegionName: string;
@Column({ comment: "地区简称", nullable: true })
RegionShortName: string;
@Column({ comment: "地区行政编号", nullable: true })
RegionCode: string;
@Column({ comment: "地区父级ID" })
RegionParentId: string;
@Column({ comment: "地区级别" })
RegionLevel: number;
}

View File

@ -1,19 +0,0 @@
/*
* @Author: '490912587@qq.com' '490912587@qq.com'
* @Date: 2022-11-17 13:10:02
* @LastEditors: '490912587@qq.com' '490912587@qq.com'
* @LastEditTime: 2022-11-22 15:08:00
* @FilePath: \tsplatform\backend\src\Entity\SysDictionaries.ts
* @Description: 系统字典实体模型
*/
import { Entity, Column } from 'typeorm';
import { SysBase } from 'src/Entity/SysBase';
@Entity()
export class SysDictionaries extends SysBase {
@Column({ comment: "字典名称" })
Name: string;
@Column({ comment: "备注", nullable: true })
Remark: string;
}

View File

@ -1,61 +0,0 @@
/*
* @Author: '490912587@qq.com' '490912587@qq.com'
* @Date: 2022-11-17 11:21:40
* @LastEditors: '490912587@qq.com' '490912587@qq.com'
* @LastEditTime: 2022-11-23 21:52:49
* @FilePath: \tsplatform\backend\src\Entity\SysMenu.ts
* @Description: 系统菜单实体模型
*/
import { Entity, Column } from 'typeorm';
import { SysBase } from 'src/Entity/SysBase';
import { MenuEnum } from 'src/Enum/Global';
@Entity()
export class SysMenu extends SysBase {
@Column({ comment: "父级ID", default: 0 })
ParentId: number;
@Column({ comment: "菜单类型", default: 0 })
Type: MenuEnum;
@Column({ comment: "路由名称", unique: true })
Name: string;
@Column({ comment: "路由地址", nullable: true })
Path: string;
@Column({ comment: "组件名称", nullable: true })
Component: string;
@Column({ comment: "重定向路径", nullable: true })
Redirect: string;
@Column({ comment: "菜单名称" })
Title: string;
@Column({ comment: "是否外链,开启外链条件,`1、isLink: 链接地址不为空 2、isIframe:false`", nullable: true })
IsLink: string;
@Column({ comment: "是否隐藏此路由" })
IsHide: boolean;
@Column({ comment: "是否缓存组件状态" })
IsKeepAlive: boolean;
@Column({ comment: "是否固定在 tagsView 栏上" })
IsAffix: boolean;
@Column({ comment: "是否内嵌窗口,开启条件,`1、isIframe:true 2、isLink链接地址不为空`" })
IsIframe: boolean;
@Column({ comment: "路由权限标识", unique: true })
Permission: string;
@Column({ comment: "菜单图标", nullable: true })
Icon: string;
@Column({ comment: "排序", nullable: true, default: 0 })
Sort: number;
Children: SysMenu[];
}

View File

@ -1,22 +0,0 @@
/*
* @Author: '490912587@qq.com' '490912587@qq.com'
* @Date: 2022-11-17 13:08:01
* @LastEditors: '490912587@qq.com' '490912587@qq.com'
* @LastEditTime: 2022-11-23 16:46:20
* @FilePath: \tsplatform\backend\src\Entity\SysRole.ts
* @Description: 系统角色实体模型
*/
import { Entity, Column } from 'typeorm';
import { SysBase } from 'src/Entity/SysBase';
import { SysRoleMenu } from 'src/Entity/SysRoleMenu';
@Entity()
export class SysRole extends SysBase {
@Column({ comment: "角色名称", unique: true })
Name: string;
@Column({ comment: "备注", nullable: true })
Remark: string;
SysRoleMenu: SysRoleMenu[];
}

View File

@ -1,18 +0,0 @@
/*
* @Author: '490912587@qq.com' '490912587@qq.com'
* @Date: 2022-11-17 13:54:50
* @LastEditors: '490912587@qq.com' '490912587@qq.com'
* @LastEditTime: 2022-11-23 17:32:38
* @FilePath: \tsplatform\backend\src\Entity\SysRoleMenu.ts
* @Description: 系统角色菜单映射实体模型
*/
import { Entity, Column, ManyToOne } from 'typeorm';
import { SysBase } from 'src/Entity/SysBase';
@Entity()
export class SysRoleMenu extends SysBase {
@Column({ comment: "菜单Id", default: 0 })
MenuId: number;
@Column({ comment: "角色Id", default: 0 })
RoleId: number;
}

View File

@ -1,57 +0,0 @@
/*
* @Author: '490912587@qq.com' '490912587@qq.com'
* @Date: 2022-11-17 13:55:35
* @LastEditors: '490912587@qq.com' '490912587@qq.com'
* @LastEditTime: 2022-11-23 23:13:45
* @FilePath: \tsplatform\backend\src\Entity\SysUser.ts
* @Description: 系统用户映射实体模型
*/
import { Entity, Column, Index } from 'typeorm';
import { SysBase } from 'src/Entity/SysBase';
import { SexEnum, UserTypeEnum } from 'src/Enum/Global';
@Entity()
export class SysUser extends SysBase {
@Column({ comment: "账号类型", default: 1 })
UserType: UserTypeEnum;
@Column({ comment: "账号", unique: true })
UserName: string;
@Column({ comment: "密码" })
Password: string;
@Column({ comment: "昵称", nullable: true })
NickName: string;
@Column({ comment: "头像", nullable: true })
Avatar: string;
@Column({ comment: "出生日期", nullable: true })
Birthday: string;
@Column({ comment: "性别", nullable: true, default: 0 })
Sex: SexEnum;
@Column({ comment: "邮箱", unique: true })
Email: string;
@Column({ comment: "手机号码", unique: true })
Phone: string;
@Column({ comment: "真实姓名", nullable: true })
RealName: string;
@Column({ comment: "身份证号", nullable: true })
IdCard: string;
@Column({ comment: "个性签名", nullable: true })
Signature: string;
@Column({ comment: "个人简介", nullable: true })
Introduction: string;
@Column({ comment: "备注", nullable: true })
Remark: string;
@Column({ comment: "角色Id", default: 0 })
RoleId: number;
}

View File

@ -1,78 +0,0 @@
/*
* @Author: '490912587@qq.com' '490912587@qq.com'
* @Date: 2022-11-18 09:02:28
* @LastEditors: '490912587@qq.com' '490912587@qq.com'
* @LastEditTime: 2022-11-24 00:20:22
* @FilePath: \tsplatform\backend\src\Expand\CommonDto.ts
* @Description: 公共DTO服务
*/
import { Injectable } from "@nestjs/common";
import { ApiProperty } from "@nestjs/swagger";
import { IsArray, IsNotEmpty, IsNumber, IsNumberString } from "class-validator";
//分页查询DTO
@Injectable()
export class PageDto {
@IsNotEmpty()
@IsNumberString()
@ApiProperty({ name: "Page", required: true })
Page: number
@IsNotEmpty()
@IsNumberString()
@ApiProperty({ name: "PageSize", required: true })
PageSize: number
@ApiProperty({ name: "Keywords", required: false })
Keywords: string
@ApiProperty({ name: "OrderBy", required: false })
OrderBy: string
}
//列表查询DTO
@Injectable()
export class ListDto {
@ApiProperty({ name: "Keywords", required: false })
Keywords: string
@ApiProperty({ name: "OrderBy", required: false })
OrderBy: string
}
//ids DTO
@Injectable()
export class IdsDto {
@IsNotEmpty()
@IsArray()
@ApiProperty({ name: "Ids", required: true })
Ids: number[]
}
//id DTO
@Injectable()
export class IdDto {
@IsNotEmpty()
@IsNumber()
@ApiProperty({ name: "Id", required: true })
Id: number
}
@Injectable()
export class RoleIdDto {
@ApiProperty({ name: "RoleId" })
RoleId: number;
}
//Id Status DTO
@Injectable()
export class IdStatusDto {
@IsNotEmpty()
@IsNumber()
@ApiProperty({ name: "Id", required: true })
Id: number
@IsNotEmpty()
@IsNumber()
@ApiProperty({ name: "Status", required: true })
Status: number
}

View File

@ -1,21 +0,0 @@
/*
* @Author: '490912587@qq.com' '490912587@qq.com'
* @Date: 2022-11-18 17:35:08
* @LastEditors: '490912587@qq.com' '490912587@qq.com'
* @LastEditTime: 2022-11-23 12:12:42
* @FilePath: \tsplatform\backend\src\EntiyDto\Login.ts
* @Description: DTO类
*/
import { ApiProperty } from "@nestjs/swagger";
import { IsNotEmpty, IsString } from "class-validator";
export class LoginDto {
@IsNotEmpty()
@IsString()
@ApiProperty({ name: "UserName", required: true })
UserName: string;
@IsNotEmpty()
@IsString()
@ApiProperty({ name: "Password", required: true })
Password: string;
}

View File

@ -1,70 +0,0 @@
/*
* @Author: '490912587@qq.com' '490912587@qq.com'
* @Date: 2022-11-18 17:35:08
* @LastEditors: '490912587@qq.com' '490912587@qq.com'
* @LastEditTime: 2022-11-24 00:14:13
* @FilePath: \tsplatform\backend\src\EntiyDto\MenuDto.ts
* @Description: SysMenu DTO类
*/
import { ApiProperty } from "@nestjs/swagger";
import { IsBoolean, IsNotEmpty, IsNumber, IsString } from "class-validator";
import { MenuEnum } from "src/Enum/Global";
export class MenuDto {
@ApiProperty({ name: "ParentId" })
ParentId: number;
@IsNotEmpty()
@IsNumber()
@ApiProperty({ name: "Type", required: true })
Type: MenuEnum;
@ApiProperty({ name: "Name", required: false })
Name: string;
@ApiProperty({ name: "Path", required: false })
Path: string;
@ApiProperty({ name: "Component", required: false })
Component: string;
@ApiProperty({ name: "Redirect", required: false })
Redirect: string;
@IsNotEmpty()
@IsString()
@ApiProperty({ name: "Title", required: true })
Title: string;
@ApiProperty({ name: "IsLink", required: false })
IsLink: string;
@IsNotEmpty()
@IsBoolean()
@ApiProperty({ name: "IsHide", required: true })
IsHide: boolean;
@IsNotEmpty()
@IsBoolean()
@ApiProperty({ name: "IsKeepAlive", required: true })
IsKeepAlive: boolean;
@IsNotEmpty()
@IsBoolean()
@ApiProperty({ name: "IsAffix", required: true })
IsAffix: boolean;
@IsNotEmpty()
@IsBoolean()
@ApiProperty({ name: "IsIframe", required: true })
IsIframe: boolean;
@IsNotEmpty()
@IsString()
@ApiProperty({ name: "Permission", required: true })
Permission: string;
@ApiProperty({ name: "Icon", required: false })
Icon: string;
}

View File

@ -1,25 +0,0 @@
/*
* @Author: '490912587@qq.com' '490912587@qq.com'
* @Date: 2022-11-22 16:16:08
* @LastEditors: '490912587@qq.com' '490912587@qq.com'
* @LastEditTime: 2022-11-23 12:12:56
* @FilePath: \backend\src\EntiyDto\RoleDto.ts
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
import { ApiProperty } from "@nestjs/swagger";
import { IsArray, IsNotEmpty } from "class-validator";
export class RoleDto {
@IsNotEmpty()
@ApiProperty({ name: "Name", required: true })
Name: string;
@ApiProperty({ name: "Remark" })
Remark: string;
@IsNotEmpty()
@IsArray()
@ApiProperty({ name: "SysRoleMenu", required: true })
SysRoleMenu: number[];
}

View File

@ -1,26 +0,0 @@
/*
* @Author: '490912587@qq.com' '490912587@qq.com'
* @Date: 2022-11-18 17:35:08
* @LastEditors: '490912587@qq.com' '490912587@qq.com'
* @LastEditTime: 2022-11-23 12:13:13
* @FilePath: \tsplatform\backend\src\EntiyDto\RouteMenu.ts
* @Description: RouteMenu类 菜单树查询不需要dto映射
*/
export class RouteMenu {
name: string;
path: string;
component: string;
redirect: string;
meta: Meta;
children: RouteMenu[];
}
export class Meta {
title: string;
isLink: string;
isHide: boolean;
isKeepAlive: boolean;
isAffix: boolean;
isIframe: boolean;
permission: string;
icon: string;
}

View File

@ -1,65 +0,0 @@
/*
* @Author: '490912587@qq.com' '490912587@qq.com'
* @Date: 2022-11-22 16:16:19
* @LastEditors: '490912587@qq.com' '490912587@qq.com'
* @LastEditTime: 2022-11-23 21:32:25
* @FilePath: \backend\src\EntiyDto\UserDto.ts
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
import { ApiProperty } from "@nestjs/swagger";
import { IsNotEmpty, IsNumber, IsNumberString } from "class-validator";
export class UserDto {
@IsNotEmpty()
@IsNumber()
@ApiProperty({ name: "UserType", required: true })
UserType: number;
@IsNotEmpty()
@ApiProperty({ name: "Name", required: true })
UserName: string;
@ApiProperty({ name: "Password" })
Password: string;
@ApiProperty({ name: "NickName" })
NickName: string;
@ApiProperty({ name: "Avatar" })
Avatar: string;
@ApiProperty({ name: "Birthday" })
Birthday: string;
@IsNotEmpty()
@IsNumber()
@ApiProperty({ name: "Sex" })
Sex: number;
@ApiProperty({ name: "Email", required: true })
Email: string;
@IsNotEmpty()
@IsNumberString()
@ApiProperty({ name: "Phone", required: true })
Phone: string;
@ApiProperty({ name: "RealName" })
RealName: string;
@ApiProperty({ name: "IdCard" })
IdCard: string;
@ApiProperty({ name: "Signature" })
Signature: string;
@ApiProperty({ name: "Introduction" })
Introduction: string;
@ApiProperty({ name: "Remark" })
Remark: string;
@ApiProperty({ name: "RoleId", required: true })
RoleId: number;
}

View File

@ -1,28 +0,0 @@
/*
* @Author: '490912587@qq.com' '490912587@qq.com'
* @Date: 2022-11-17 13:25:43
* @LastEditors: '490912587@qq.com' '490912587@qq.com'
* @LastEditTime: 2022-11-18 09:15:04
* @FilePath: \tsplatform\backend\src\Enum\Global.ts
* @Description: 全局枚举类
*/
export enum RestfulHttpCodeEnum {
SUCCESS = 200,
FAIL = 300,
NODATA = 201,
}
export enum UserTypeEnum {
Admin = 0,
None = 1,
SuperAdmin = 999,
}
export enum SexEnum {
Man = 0,
WoMan = 1
}
export enum MenuEnum {
Directory = 0,
Menu = 1,
Btn = 2
}

View File

@ -1,24 +0,0 @@
/*
* @Author: '490912587@qq.com' '490912587@qq.com'
* @Date: 2022-11-17 09:19:20
* @LastEditors: '490912587@qq.com' '490912587@qq.com'
* @LastEditTime: 2022-11-18 09:10:15
* @FilePath: \tsplatform\backend\src\Expand\RestfulReturn.ts
* @Description: RestfulAPI全局响应结构
*/
import { Injectable } from "@nestjs/common";
import { RestfulHttpCodeEnum } from "src/Enum/Global";
@Injectable()
export class RestfulReturn {
//HttpStatus=200时的状态码规则
toJson(code: RestfulHttpCodeEnum, data: any) {
return {
code: code,
msg: code === RestfulHttpCodeEnum.SUCCESS ? "操作成功!" :
code === RestfulHttpCodeEnum.FAIL ? "操作失败!" :
code === RestfulHttpCodeEnum.NODATA ? "数据为空!" : "未知错误!",
data: data,
timespan: new Date().getTime()
}
}
}

View File

@ -1,15 +0,0 @@
/*
* @Author: '490912587@qq.com' '490912587@qq.com'
* @Date: 2022-11-18 09:02:28
* @LastEditors: '490912587@qq.com' '490912587@qq.com'
* @LastEditTime: 2022-11-24 10:13:53
* @FilePath: \tsplatform\backend\src\Logging\LoggerPrint.ts
* @Description: 全局日志打印服务
*/
import { Injectable, Logger } from "@nestjs/common";
@Injectable()
export class LoggerPrint {
constructor(private readonly logger: Logger) {
}
}

View File

@ -1,33 +0,0 @@
/*
* @Author: '490912587@qq.com' '490912587@qq.com'
* @Date: 2022-11-21 11:57:30
* @LastEditors: '490912587@qq.com' '490912587@qq.com'
* @LastEditTime: 2022-11-22 10:41:09
* @FilePath: \tsplatform\backend\src\Middleware\JwtHandle.ts
* @Description: 授权中间件
*/
import { HttpException, HttpStatus, Injectable, NestMiddleware } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { NextFunction } from 'express';
import { AppConfig } from 'src/Config/Index';
@Injectable()
export class JwtHandle implements NestMiddleware {
constructor(
public readonly _jwt: JwtService
) { }
async use(req: Request, res: Response, next: NextFunction) {
try {
const token = req.headers["authorization"];
if (!token) {
throw new HttpException("Token指令牌不存在", HttpStatus.UNAUTHORIZED);
} else {
await this._jwt.verifyAsync(token, { secret: AppConfig.jwt.secret, ignoreExpiration: false })
next();
}
}
catch (ex) {
throw new HttpException(ex.message, HttpStatus.UNAUTHORIZED);
}
}
}

File diff suppressed because one or more lines are too long

View File

@ -1,216 +0,0 @@
/*
* @Author: '490912587@qq.com' '490912587@qq.com'
* @Date: 2022-11-24 09:22:50
* @LastEditors: '490912587@qq.com' '490912587@qq.com'
* @LastEditTime: 2022-11-24 09:58:45
* @FilePath: \backend\src\SeedData\Menu.ts
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
export const menus = [{
"Id": 8,
"Status": 0,
"MerchantId": 0,
"CreateTime": "2022-11-23T07:53:21.453Z",
"UpdateTime": "2022-11-24T01:29:41.000Z",
"OperatorId": 0,
"UpdateUserId": 0,
"IsDelete": false,
"Version": 5,
"ParentId": 2,
"Type": 1,
"Name": "system.city",
"Path": "/system/city",
"Component": "/system/city/index",
"Redirect": "",
"Title": "message.router.system.city",
"IsLink": "",
"IsHide": false,
"IsKeepAlive": true,
"IsAffix": false,
"IsIframe": false,
"Permission": "system.city",
"Icon": "ele-OfficeBuilding",
"Sort": 101
},
{
"Id": 7,
"Status": 0,
"MerchantId": 0,
"CreateTime": "2022-11-23T07:50:37.192Z",
"UpdateTime": "2022-11-24T01:21:19.762Z",
"OperatorId": 0,
"UpdateUserId": 0,
"IsDelete": false,
"Version": 4,
"ParentId": 2,
"Type": 1,
"Name": "system.dic",
"Path": "/system/dic",
"Component": "/system/dic/index",
"Redirect": "",
"Title": "message.router.system.dic",
"IsLink": "",
"IsHide": false,
"IsKeepAlive": true,
"IsAffix": false,
"IsIframe": false,
"Permission": "system.dic",
"Icon": "iconfont icon-zhongyingwen1",
"Sort": 100
},
{
"Id": 6,
"Status": 0,
"MerchantId": 0,
"CreateTime": "2022-11-22T13:59:37.445Z",
"UpdateTime": "2022-11-23T05:56:53.726Z",
"OperatorId": 0,
"UpdateUserId": 0,
"IsDelete": false,
"Version": 0,
"ParentId": 0,
"Type": 0,
"Name": "personal",
"Path": "/personal",
"Component": "personal/index",
"Redirect": null,
"Title": "message.router.personal",
"IsLink": "",
"IsHide": true,
"IsKeepAlive": false,
"IsAffix": false,
"IsIframe": false,
"Permission": "personal",
"Icon": "iconfont icon-gerenzhongxin",
"Sort": 6
},
{
"Id": 5,
"Status": 0,
"MerchantId": 0,
"CreateTime": "2022-11-22T13:59:37.445Z",
"UpdateTime": "2022-11-23T08:05:06.779Z",
"OperatorId": 0,
"UpdateUserId": 0,
"IsDelete": false,
"Version": 0,
"ParentId": 2,
"Type": 1,
"Name": "system.role",
"Path": "/system/role",
"Component": "system/role/index",
"Redirect": null,
"Title": "message.router.system.role",
"IsLink": "",
"IsHide": false,
"IsKeepAlive": true,
"IsAffix": false,
"IsIframe": false,
"Permission": "system.role",
"Icon": "fa fa-street-view",
"Sort": 5
},
{
"Id": 4,
"Status": 0,
"MerchantId": 0,
"CreateTime": "2022-11-22T13:59:37.445Z",
"UpdateTime": "2022-11-23T08:05:03.689Z",
"OperatorId": 0,
"UpdateUserId": 0,
"IsDelete": false,
"Version": 0,
"ParentId": 2,
"Type": 1,
"Name": "system.user",
"Path": "/system/user",
"Component": "system/user/index",
"Redirect": null,
"Title": "message.router.system.user",
"IsLink": null,
"IsHide": false,
"IsKeepAlive": true,
"IsAffix": false,
"IsIframe": false,
"Permission": "system.user",
"Icon": "iconfont icon-icon-",
"Sort": 4
},
{
"Id": 3,
"Status": 0,
"MerchantId": 0,
"CreateTime": "2022-11-22T13:59:37.445Z",
"UpdateTime": "2022-11-23T08:05:00.650Z",
"OperatorId": 0,
"UpdateUserId": 0,
"IsDelete": false,
"Version": 0,
"ParentId": 2,
"Type": 1,
"Name": "system.menu",
"Path": "/system/menu",
"Component": "system/menu/index",
"Redirect": null,
"Title": "message.router.system.menu",
"IsLink": "",
"IsHide": false,
"IsKeepAlive": true,
"IsAffix": false,
"IsIframe": false,
"Permission": "system.menu",
"Icon": "iconfont icon-caidan",
"Sort": 3
},
{
"Id": 2,
"Status": 0,
"MerchantId": 0,
"CreateTime": "2022-11-22T13:59:37.445Z",
"UpdateTime": "2022-11-23T08:05:16.188Z",
"OperatorId": 0,
"UpdateUserId": 0,
"IsDelete": false,
"Version": 0,
"ParentId": 0,
"Type": 0,
"Name": "system",
"Path": "/system",
"Component": "layout/routerView/parent",
"Redirect": "/system/menu",
"Title": "message.router.system.system",
"IsLink": "",
"IsHide": false,
"IsKeepAlive": true,
"IsAffix": false,
"IsIframe": false,
"Permission": "system",
"Icon": "iconfont icon-xitongshezhi",
"Sort": 2
},
{
"Id": 1,
"Status": 0,
"MerchantId": 0,
"CreateTime": "2022-11-22T13:59:37.445Z",
"UpdateTime": "2022-11-22T13:59:37.471Z",
"OperatorId": 0,
"UpdateUserId": 0,
"IsDelete": false,
"Version": 0,
"ParentId": 0,
"Type": 0,
"Name": "home",
"Path": "/home",
"Component": "home/index",
"Redirect": "",
"Title": "message.router.home",
"IsLink": "",
"IsHide": false,
"IsKeepAlive": true,
"IsAffix": true,
"IsIframe": false,
"Permission": "home",
"Icon": "iconfont icon-shouye",
"Sort": 1
}];

View File

@ -1,179 +0,0 @@
/*
* @Author: '490912587@qq.com' '490912587@qq.com'
* @Date: 2022-11-24 09:23:07
* @LastEditors: '490912587@qq.com' '490912587@qq.com'
* @LastEditTime: 2022-11-24 10:04:17
* @FilePath: \backend\src\SeedData\Role.ts
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
export const roles = [
{
"Id": 1,
"Status": 0,
"MerchantId": 0,
"CreateTime": "2022-11-22T13:59:37.567Z",
"UpdateTime": "2022-11-24T01:35:03.000Z",
"OperatorId": 0,
"UpdateUserId": 0,
"IsDelete": false,
"Version": 4,
"Name": "超级管理员",
"Remark": null
},
{
"Id": 2,
"Status": 0,
"MerchantId": 0,
"CreateTime": "2022-11-22T13:59:37.567Z",
"UpdateTime": "2022-11-24T01:36:45.000Z",
"OperatorId": 0,
"UpdateUserId": 0,
"IsDelete": false,
"Version": 3,
"Name": "普通用户",
"Remark": null
}
];
export const roleMenus = [{
"Id": 1,
"Status": 0,
"MerchantId": 0,
"CreateTime": "2022-11-24T01:35:03.437Z",
"UpdateTime": "2022-11-24T01:35:03.437Z",
"OperatorId": 0,
"UpdateUserId": 0,
"IsDelete": false,
"Version": 1,
"MenuId": 1,
"RoleId": 1
},
{
"Id": 2,
"Status": 0,
"MerchantId": 0,
"CreateTime": "2022-11-24T01:35:03.437Z",
"UpdateTime": "2022-11-24T01:35:03.437Z",
"OperatorId": 0,
"UpdateUserId": 0,
"IsDelete": false,
"Version": 1,
"MenuId": 2,
"RoleId": 1
},
{
"Id": 3,
"Status": 0,
"MerchantId": 0,
"CreateTime": "2022-11-24T01:35:03.437Z",
"UpdateTime": "2022-11-24T01:35:03.437Z",
"OperatorId": 0,
"UpdateUserId": 0,
"IsDelete": false,
"Version": 1,
"MenuId": 3,
"RoleId": 1
},
{
"Id": 4,
"Status": 0,
"MerchantId": 0,
"CreateTime": "2022-11-24T01:35:03.437Z",
"UpdateTime": "2022-11-24T01:35:03.437Z",
"OperatorId": 0,
"UpdateUserId": 0,
"IsDelete": false,
"Version": 1,
"MenuId": 4,
"RoleId": 1
},
{
"Id": 5,
"Status": 0,
"MerchantId": 0,
"CreateTime": "2022-11-24T01:35:03.437Z",
"UpdateTime": "2022-11-24T01:35:03.437Z",
"OperatorId": 0,
"UpdateUserId": 0,
"IsDelete": false,
"Version": 1,
"MenuId": 5,
"RoleId": 1
},
{
"Id": 6,
"Status": 0,
"MerchantId": 0,
"CreateTime": "2022-11-24T01:35:03.437Z",
"UpdateTime": "2022-11-24T01:35:03.437Z",
"OperatorId": 0,
"UpdateUserId": 0,
"IsDelete": false,
"Version": 1,
"MenuId": 6,
"RoleId": 1
},
{
"Id": 7,
"Status": 0,
"MerchantId": 0,
"CreateTime": "2022-11-24T01:35:03.437Z",
"UpdateTime": "2022-11-24T01:35:03.437Z",
"OperatorId": 0,
"UpdateUserId": 0,
"IsDelete": false,
"Version": 1,
"MenuId": 7,
"RoleId": 1
},
{
"Id": 8,
"Status": 0,
"MerchantId": 0,
"CreateTime": "2022-11-24T01:35:03.437Z",
"UpdateTime": "2022-11-24T01:35:03.437Z",
"OperatorId": 0,
"UpdateUserId": 0,
"IsDelete": false,
"Version": 1,
"MenuId": 8,
"RoleId": 1
},
{
"Id": 9,
"Status": 0,
"MerchantId": 0,
"CreateTime": "2022-11-24T01:36:45.486Z",
"UpdateTime": "2022-11-24T01:36:45.486Z",
"OperatorId": 0,
"UpdateUserId": 0,
"IsDelete": false,
"Version": 1,
"MenuId": 1,
"RoleId": 2
},
{
"Id": 10,
"Status": 0,
"MerchantId": 0,
"CreateTime": "2022-11-24T01:36:45.486Z",
"UpdateTime": "2022-11-24T01:36:45.486Z",
"OperatorId": 0,
"UpdateUserId": 0,
"IsDelete": false,
"Version": 1,
"MenuId": 2,
"RoleId": 2
},
{
"Id": 11,
"Status": 0,
"MerchantId": 0,
"CreateTime": "2022-11-24T01:36:45.486Z",
"UpdateTime": "2022-11-24T01:36:45.486Z",
"OperatorId": 0,
"UpdateUserId": 0,
"IsDelete": false,
"Version": 1,
"MenuId": 4,
"RoleId": 2
}];

View File

@ -1,60 +0,0 @@
/*
* @Author: '490912587@qq.com' '490912587@qq.com'
* @Date: 2022-11-24 09:22:58
* @LastEditors: '490912587@qq.com' '490912587@qq.com'
* @LastEditTime: 2022-11-24 10:04:55
* @FilePath: \backend\src\SeedData\User.ts
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
export const users = [{
"Id": 1,
"Status": 0,
"MerchantId": 0,
"CreateTime": "2022-11-22T13:59:37.496Z",
"UpdateTime": "2022-11-24T01:21:53.423Z",
"OperatorId": 0,
"UpdateUserId": 0,
"IsDelete": false,
"Version": 0,
"UserType": 999,
"UserName": "admin",
"Password": "1a23c5066d05474304c03342e57850d9",
"NickName": "甜蜜蜜",
"Avatar": "https://img2.baidu.com/it/u=1978192862,2048448374&fm=253&fmt=auto&app=138&f=JPEG?w=504&h=500",
"Birthday": null,
"Sex": 0,
"Email": "490912587@qq.com",
"Phone": "13000000000",
"RealName": null,
"IdCard": null,
"Signature": null,
"Introduction": null,
"Remark": null,
"RoleId": 1
},
{
"Id": 2,
"Status": 0,
"MerchantId": 0,
"CreateTime": "2022-11-23T08:45:37.321Z",
"UpdateTime": "2022-11-24T01:39:33.000Z",
"OperatorId": 0,
"UpdateUserId": 0,
"IsDelete": false,
"Version": 4,
"UserType": 0,
"UserName": "test",
"Password": "7b0ea1aa91470cd870111415a94b475b",
"NickName": "甜蜜蜜的小号",
"Avatar": "https://img2.baidu.com/it/u=1978192862,2048448374&fm=253&fmt=auto&app=138&f=JPEG?w=504&h=500",
"Birthday": null,
"Sex": 1,
"Email": "1844045442@qq.com",
"Phone": "15000000000",
"RealName": null,
"IdCard": null,
"Signature": null,
"Introduction": null,
"Remark": null,
"RoleId": 2
}];

View File

@ -1,94 +0,0 @@
/*
* @Author: '490912587@qq.com' '490912587@qq.com'
* @Date: 2022-11-17 17:08:52
* @LastEditors: '490912587@qq.com' '490912587@qq.com'
* @LastEditTime: 2022-11-24 11:12:25
* @FilePath: \tsplatform\backend\src\Service\UserService.ts
* @Description: 省市区服务
*/
import { Injectable, Logger } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { DeleteResult, In, InsertResult, Like, Repository } from 'typeorm';
import { LoggerPrint } from 'src/Logging/LoggerPrint';
import { SysCity } from 'src/Entity/SysCity';
import { citys } from 'src/SeedData/City';
@Injectable()
export class CityService {
private readonly tableName: string = "省市区";
constructor(
public readonly loggerPrint: LoggerPrint,
public readonly logger: Logger,
@InjectRepository(SysCity)
public readonly repository: Repository<SysCity>
) {
}
//#region 基础控制器
// 初始化数据
async seedData(): Promise<number> {
let result: InsertResult;
await this.repository.queryRunner?.startTransaction();
try {
await this.repository.clear();
result = await this.repository.createQueryBuilder().insert().values(citys).execute();
await this.repository.queryRunner?.commitTransaction();
await this.repository.createQueryBuilder().useTransaction(true);
return result.identifiers.length;
} catch (err) {
//如果遇到错误,可以回滚事务
await this.repository.queryRunner?.rollbackTransaction();
this.logger.warn(err);
return 0;
}
}
async getPage(
page: number = 1,
pageSize: number = 10,
keywords: string = "",
orderBy: string = ""
): Promise<[SysCity[], number]> {
const result = await this.repository.findAndCount({
where: [{ RegionName: Like("%" + keywords + "%") }, { RegionShortName: Like("%" + keywords + "%") }],
order: {
Id: "ASC"
},
skip: page - 1,
take: pageSize
})
return result;
}
async getList(
keywords: string = "",
orderBy: string = "",
): Promise<SysCity[]> {
const result = await this.repository.find({
where: [{ RegionName: Like("%" + keywords + "%") }, { RegionShortName: Like("%" + keywords + "%") }],
order: {
Id: "ASC"
},
})
return result;
}
async getById(id: number): Promise<SysCity> {
const result = await this.repository.findOne({ where: { Id: id } });
return result;
}
async getByIds(ids: number[]): Promise<SysCity[]> {
const result = await this.repository.find({
where: { Id: In(ids) },
})
return result;
}
async save(model: SysCity): Promise<SysCity> {
const result = await this.repository.save(model);
return result;
}
async destroy(id: number): Promise<DeleteResult> {
const result = await this.repository.delete(id);
return result;
}
//#endregion
}

View File

@ -1,94 +0,0 @@
/*
* @Author: '490912587@qq.com' '490912587@qq.com'
* @Date: 2022-11-17 17:08:52
* @LastEditors: '490912587@qq.com' '490912587@qq.com'
* @LastEditSysMenuime: 2022-11-18 11:31:43
* @FilePath: \tsplatform\backend\src\Service\MenuService.ts
* @Description: 系统菜单服务
*/
import { Injectable, Logger } from '@nestjs/common';
import { SysMenu } from 'src/Entity/SysMenu';
import { InjectRepository } from '@nestjs/typeorm';
import { DeleteResult, In, InsertResult, Like, Repository } from 'typeorm';
import { LoggerPrint } from 'src/Logging/LoggerPrint';
import { menus } from 'src/SeedData/Menu';
@Injectable()
export class MenuService {
private readonly tableName: string = "系统菜单";
constructor(
public readonly loggerPrint: LoggerPrint,
public readonly logger: Logger,
@InjectRepository(SysMenu)
public readonly repository: Repository<SysMenu>
) {
}
//#region 基础控制器
// 初始化数据
async seedData(): Promise<number> {
let result: InsertResult;
await this.repository.queryRunner?.startTransaction();
try {
await this.repository.clear();
result = await this.repository.createQueryBuilder().insert().values(menus).execute();
await this.repository.queryRunner?.commitTransaction();
await this.repository.createQueryBuilder().useTransaction(true);
return result.identifiers.length;
} catch (err) {
//如果遇到错误,可以回滚事务
await this.repository.queryRunner?.rollbackTransaction();
this.logger.warn(err);
return 0;
}
}
async getPage(
page: number = 1,
pageSize: number = 10,
keywords: string = "",
orderBy: string = ""
): Promise<[SysMenu[], number]> {
const result = await this.repository.findAndCount({
where: [{ Title: Like("%" + keywords + "%") }, { Name: Like("%" + keywords + "%") }],
order: {
Id: "DESC"
},
skip: page - 1,
take: pageSize
})
return result;
}
async getList(
keywords: string = "",
orderBy: string = ""
): Promise<SysMenu[]> {
const result = await this.repository.find({
where: [{ Name: Like("%" + keywords + "%") }],
order: {
Id: "DESC"
},
})
return result;
}
async getById(id: number): Promise<SysMenu> {
const result = await this.repository.findOne({ where: { Id: id } });
return result;
}
async getByIds(ids: number[]): Promise<SysMenu[]> {
const result = await this.repository.find({
where: { Id: In(ids) },
})
return result;
}
async save(model: SysMenu): Promise<SysMenu> {
const result = await this.repository.save(model);
return result;
}
async destroy(id: number): Promise<DeleteResult> {
const result = await this.repository.delete(id);
return result;
}
//#endregion
}

View File

@ -1,156 +0,0 @@
/*
* @Author: '490912587@qq.com' '490912587@qq.com'
* @Date: 2022-11-17 17:08:52
* @LastEditors: '490912587@qq.com' '490912587@qq.com'
* @LastEditTime: 2022-11-24 10:15:40
* @FilePath: \tsplatform\backend\src\Service\RoleService.ts
* @Description: 系统角色服务
*/
import { Injectable, Logger } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { DeleteResult, In, InsertResult, Like, Repository } from 'typeorm';
import { SysRole } from 'src/Entity/SysRole';
import { LoggerPrint } from 'src/Logging/LoggerPrint';
import { SysRoleMenu } from 'src/Entity/SysRoleMenu';
import { roleMenus, roles } from 'src/SeedData/Role';
// where: { Name: keywords },//and查询
// where: [{ Name: keywords }],//or查询
// where: { Name: Like("%out #%") },//like查询
// where: { Id: In([0,1]) },//in查询
// where: { Name: Like("%out #%") },//like查询
@Injectable()
export class RoleService {
private readonly tableName: string = "系统角色";
constructor(
public readonly loggerPrint: LoggerPrint,
public readonly logger: Logger,
@InjectRepository(SysRole)
public readonly repository: Repository<SysRole>,
@InjectRepository(SysRoleMenu)
public readonly roleMenuRepository: Repository<SysRoleMenu>,
) {
}
//根据角色Id获得路由菜单
async getMenusByRoleId(id: number): Promise<SysRoleMenu[]> {
//根据角色Id获得角色菜单映射数据
const result = await this.roleMenuRepository.find({
where: { RoleId: id }
});
return result;
}
//#region 基础控制器
// 初始化数据
async seedData(): Promise<number[]> {
let result: InsertResult;
let result1: InsertResult;
await this.repository.queryRunner?.startTransaction();
try {
await this.repository.clear();
result = await this.repository.createQueryBuilder().insert().values(roles).execute();
result1 = await this.roleMenuRepository.createQueryBuilder().insert().values(roleMenus).execute();
await this.repository.queryRunner?.commitTransaction();
await this.repository.createQueryBuilder().useTransaction(true);
return [result.identifiers.length, result1.identifiers.length]
} catch (err) {
//如果遇到错误,可以回滚事务
await this.repository.queryRunner?.rollbackTransaction();
this.logger.warn(err);
return [0, 0];
}
}
async getPage(
page: number = 1,
pageSize: number = 10,
keywords: string = "",
orderBy: string = ""
): Promise<[SysRole[], number]> {
const result = await this.repository.findAndCount({
where: [{ Name: Like("%" + keywords + "%") }],
order: {
Id: "ASC"
},
skip: page - 1,
take: pageSize
})
for await (let item of result[0]) {
const roleMenuResult = await this.roleMenuRepository.find({
where: { RoleId: item.Id },
})
item.SysRoleMenu = roleMenuResult;
}
return result;
}
async getList(
keywords: string = "",
orderBy: string = ""
): Promise<SysRole[]> {
const result = await this.repository.find({
where: [{ Name: Like("%" + keywords + "%") }],
order: {
Id: "ASC"
},
})
for await (let item of result) {
const roleMenuResult = await this.roleMenuRepository.find({
where: { RoleId: item.Id },
})
item.SysRoleMenu = roleMenuResult;
}
return result;
}
async getById(id: number): Promise<SysRole> {
const result = await this.repository.findOne({ where: { Id: id } });
return result;
}
async getByIds(ids: number[]): Promise<SysRole[]> {
const result = await this.repository.find({
where: { Id: In(ids) }
})
return result;
}
async save(model: SysRole): Promise<boolean> {
await this.repository.queryRunner?.startTransaction();
try {
//如果是编辑先删除主子表后,修改主表,新增子表
if (model.Id > 0) {
await this.repository.createQueryBuilder().update().set({ Name: model.Name, Remark: model.Remark, Status: model.Status }).where("Id = :Id", { Id: model.Id }).execute();
await this.roleMenuRepository.delete({ RoleId: model.Id });
for await (let item of model.SysRoleMenu) {
item.RoleId = model.Id
}
} else {
const result = await this.repository.createQueryBuilder().insert().values(model).execute();
for await (let item of model.SysRoleMenu) {
item.RoleId = result.identifiers[0].Id
}
}
await this.roleMenuRepository.createQueryBuilder().insert().values(model.SysRoleMenu).execute();
await this.repository.queryRunner?.commitTransaction();
await this.repository.createQueryBuilder().useTransaction(true);
return true;
} catch (err) {
await this.repository.queryRunner?.rollbackTransaction();
this.logger.warn(err);
return false;
}
}
async destroy(id: number): Promise<boolean> {
await this.repository.queryRunner?.startTransaction();
try {
//删除主子表
await this.repository.delete({ Id: id });
await this.roleMenuRepository.delete({ RoleId: id });
await this.repository.queryRunner?.commitTransaction();
await this.repository.createQueryBuilder().useTransaction(true);
return true;
} catch (err) {
await this.repository.queryRunner?.rollbackTransaction();
this.logger.warn(err);
return false;
}
}
//#endregion
}

View File

@ -1,93 +0,0 @@
/*
* @Author: '490912587@qq.com' '490912587@qq.com'
* @Date: 2022-11-17 17:08:52
* @LastEditors: '490912587@qq.com' '490912587@qq.com'
* @LastEditTime: 2022-11-24 10:15:57
* @FilePath: \tsplatform\backend\src\Service\UserService.ts
* @Description: 系统用户服务
*/
import { Injectable, Logger } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { DeleteResult, In, InsertResult, Like, Repository } from 'typeorm';
import { LoggerPrint } from 'src/Logging/LoggerPrint';
import { SysUser } from 'src/Entity/SysUser';
import { users } from 'src/SeedData/User';
@Injectable()
export class UserService {
private readonly tableName: string = "系统用户";
constructor(
public readonly loggerPrint: LoggerPrint,
public readonly logger: Logger,
@InjectRepository(SysUser)
public readonly repository: Repository<SysUser>
) {
}
//#region 基础控制器
// 初始化数据
async seedData(): Promise<number> {
let result: InsertResult;
await this.repository.queryRunner?.startTransaction();
try {
await this.repository.clear();
result = await this.repository.createQueryBuilder().insert().values(users).execute();
await this.repository.queryRunner?.commitTransaction();
await this.repository.createQueryBuilder().useTransaction(true);
return result.identifiers.length;
} catch (err) {
//如果遇到错误,可以回滚事务
await this.repository.queryRunner?.rollbackTransaction();
this.logger.warn(err);
return 0;
}
}
async getPage(
page: number = 1,
pageSize: number = 10,
keywords: string = "",
orderBy: string = ""
): Promise<[SysUser[], number]> {
const result = await this.repository.findAndCount({
where: [{ Phone: Like("%" + keywords + "%") }, { UserName: Like("%" + keywords + "%") }, { NickName: Like("%" + keywords + "%") }],
order: {
Id: "ASC"
},
skip: page - 1,
take: pageSize
})
return result;
}
async getList(
keywords: string = "",
orderBy: string = ""
): Promise<SysUser[]> {
const result = await this.repository.find({
where: [{ Phone: Like("%" + keywords + "%") }, { UserName: Like("%" + keywords + "%") }, { NickName: Like("%" + keywords + "%") }],
order: {
Id: "ASC"
},
})
return result;
}
async getById(id: number): Promise<SysUser> {
const result = await this.repository.findOne({ where: { Id: id } });
return result;
}
async getByIds(ids: number[]): Promise<SysUser[]> {
const result = await this.repository.find({
where: { Id: In(ids) },
})
return result;
}
async save(model: SysUser): Promise<SysUser> {
const result = await this.repository.save(model);
return result;
}
async destroy(id: number): Promise<DeleteResult> {
const result = await this.repository.delete(id);
return result;
}
//#endregion
}

View File

@ -1,50 +0,0 @@
/*
* @Author: '490912587@qq.com' '490912587@qq.com'
* @Date: 2022-11-17 11:44:48
* @LastEditors: '490912587@qq.com' '490912587@qq.com'
* @LastEditTime: 2022-11-23 17:51:54
* @FilePath: \tsplatform\backend\src\Utils\LoadModules.ts
* @Description: 全局加载模块
*/
import { Logger } from '@nestjs/common';
import { RestfulReturn } from 'src/Expand/RestfulReturn';
import { LoggerPrint } from 'src/Logging/LoggerPrint';
import { JwtService } from '@nestjs/jwt';
import { SysMenu } from 'src/Entity/SysMenu';
import { SysCity } from 'src/Entity/SysCity';
import { SysUser } from 'src/Entity/SysUser';
import { SysRole } from 'src/Entity/SysRole';
import { SysRoleMenu } from 'src/Entity/SysRoleMenu';
import { IndexController } from 'src/Controller/IndexController';
import { MenuController } from 'src/Controller/MenuController';
import { AuthController } from 'src/Controller/AuthController';
import { UserController } from 'src/Controller/UserController';
import { RoleController } from 'src/Controller/RoleController';
import { CityController } from 'src/Controller/CityController';
import { MenuService } from 'src/Service/MenuService';
import { UserService } from 'src/Service/UserService';
import { RoleService } from 'src/Service/RoleService';
import { Repository } from 'typeorm';
import { CityService } from 'src/Service/CityService';
//自动导入Entity
export function LoadPlatFormEntity() {
return [SysCity, SysMenu, SysUser, SysRole, SysRoleMenu];
}
//自动导入Controller
export function LoadController() {
return [IndexController, CityController, MenuController, UserController, AuthController, RoleController,];
}
//自动导入Service服务
export function LoadService() {
return [
//特殊服务提供者
RestfulReturn, Logger, LoggerPrint, Repository,JwtService,
//Service服务提供者
MenuService, UserService, RoleService, CityService
];
}

View File

@ -1,61 +0,0 @@
/*
* @Author: '490912587@qq.com' '490912587@qq.com'
* @Date: 2022-11-17 09:19:20
* @LastEditors: '490912587@qq.com' '490912587@qq.com'
* @LastEditTime: 2022-11-24 10:16:52
* @FilePath: \tsplatform\backend\src\app.module.ts
* @Description: 全局模块入口
*/
import { MiddlewareConsumer, Module, NestModule, RequestMethod } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { TypeOrmModule } from '@nestjs/typeorm';
import { LoadController, LoadPlatFormEntity, LoadService } from 'src/Utils/LoadModules';
import { AppConfig, DataBaseConfig } from 'src/Config/Index';
import { JwtHandle } from 'src/Middleware/JwtHandle';
@Module({
imports: [
TypeOrmModule.forFeature(LoadPlatFormEntity()),
TypeOrmModule.forRootAsync({
useFactory: () => ({
debug: false,
//重试连接数据库的次数
retryAttempts: 10,
//两次重试连接的间隔(ms)
retryDelay: 3000,
//自动加载实体
autoLoadEntities: true,
type: 'mysql',
host: DataBaseConfig.DataBase.host,
port: DataBaseConfig.DataBase.port,
username: DataBaseConfig.DataBase.username,
password: DataBaseConfig.DataBase.password,
database: DataBaseConfig.DataBase.database,
entities: LoadPlatFormEntity(),
logging: AppConfig.debug,
synchronize: AppConfig.debug,
})
}),
ConfigModule.forRoot({
isGlobal: true,
envFilePath: ['.env', '.env.development', '.env.production'],
}),
],
controllers: LoadController(),
providers: LoadService()
})
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer
.apply(JwtHandle)
.exclude(
{ path: 'auth/login', method: RequestMethod.POST },
{ path: 'auth/getUserInfo', method: RequestMethod.GET },
{ path: '/seed', method: RequestMethod.GET },
)
.forRoutes("*");
}
}

View File

@ -1,33 +0,0 @@
/*
* @Author: '490912587@qq.com' '490912587@qq.com'
* @Date: 2022-11-17 09:19:20
* @LastEditors: '490912587@qq.com' '490912587@qq.com'
* @LastEditTime: 2022-11-24 11:17:23
* @FilePath: \tsplatform\backend\src\main.ts
* @Description: 主程序入口
*/
import { NestFactory } from '@nestjs/core';
import { AppModule } from 'src/app.module';
import { NestExpressApplication } from '@nestjs/platform-express';
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
import { AppConfig } from 'src/Config/Index';
import { ValidationPipe } from '@nestjs/common';
async function bootstrap() {
const app = await NestFactory.create<NestExpressApplication>(AppModule, { logger: ['error', 'warn', "log", "debug", "verbose"], cors: true });
//全局Dto参数校验管道
app.useGlobalPipes(new ValidationPipe());
const config = new DocumentBuilder()
//基础文档里添加安全定义
.addBearerAuth()
.setTitle('甜蜜蜜TS开发总平台')
.setDescription('甜蜜蜜TS开发总平台')
.setContact("甜蜜蜜", "https://gitee.com/tmm-top/vue-next-admin-ts", "490912587@qq.com")
.setVersion('1.0')
.build();
const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup('/api', app, document);
await app.listen(AppConfig.port, '0.0.0.0');
}
bootstrap();

View File

@ -1,24 +0,0 @@
import { Test, TestingModule } from '@nestjs/testing';
import { INestApplication } from '@nestjs/common';
import * as request from 'supertest';
import { AppModule } from './../src/app.module';
describe('AppController (e2e)', () => {
let app: INestApplication;
beforeEach(async () => {
const moduleFixture: TestingModule = await Test.createTestingModule({
imports: [AppModule],
}).compile();
app = moduleFixture.createNestApplication();
await app.init();
});
it('/ (GET)', () => {
return request(app.getHttpServer())
.get('/')
.expect(200)
.expect('Hello World!');
});
});

View File

@ -1,9 +0,0 @@
{
"moduleFileExtensions": ["js", "json", "ts"],
"rootDir": ".",
"testEnvironment": "node",
"testRegex": ".e2e-spec.ts$",
"transform": {
"^.+\\.(t|j)s$": "ts-jest"
}
}

View File

@ -1,4 +0,0 @@
{
"extends": "./tsconfig.json",
"exclude": ["node_modules", "test", "dist", "**/*spec.ts"],
}

View File

@ -1,21 +0,0 @@
{
"compilerOptions": {
"module": "commonjs",
"declaration": true,
"removeComments": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"allowSyntheticDefaultImports": true,
"target": "es2022",
"sourceMap": true,
"outDir": "./dist",
"baseUrl": "./",
"incremental": true,
"skipLibCheck": true,
"strictNullChecks": false,
"noImplicitAny": false,
"strictBindCallApply": false,
"forceConsistentCasingInFileNames": false,
"noFallthroughCasesInSwitch": false
}
}

9
doc/.gitignore vendored
View File

@ -1,9 +0,0 @@
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
*.code-workspace
# Local History for Visual Studio Code
.history/

Binary file not shown.

Before

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 149 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

View File

@ -1,63 +0,0 @@
module.exports = {
root: true,
env: {
browser: true,
es2021: true,
node: true,
},
parser: 'vue-eslint-parser',
parserOptions: {
ecmaVersion: 12,
parser: '@typescript-eslint/parser',
sourceType: 'module',
},
extends: ['plugin:vue/vue3-essential', 'plugin:vue/essential', 'eslint:recommended'],
plugins: ['vue', '@typescript-eslint'],
rules: {
// http://eslint.cn/docs/rules/
// https://eslint.vuejs.org/rules/
'@typescript-eslint/ban-ts-ignore': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-var-requires': 'off',
'@typescript-eslint/no-empty-function': 'off',
'@typescript-eslint/no-use-before-define': 'off',
'@typescript-eslint/ban-ts-comment': 'off',
'@typescript-eslint/ban-types': 'off',
'@typescript-eslint/no-non-null-assertion': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'vue/custom-event-name-casing': 'off',
'vue/attributes-order': 'off',
'vue/one-component-per-file': 'off',
'vue/html-closing-bracket-newline': 'off',
'vue/max-attributes-per-line': 'off',
'vue/multiline-html-element-content-newline': 'off',
'vue/singleline-html-element-content-newline': 'off',
'vue/attribute-hyphenation': 'off',
'vue/html-self-closing': 'off',
'vue/no-multiple-template-root': 'off',
'vue/require-default-prop': 'off',
'vue/no-v-model-argument': 'off',
'vue/no-arrow-functions-in-watch': 'off',
'vue/no-template-key': 'off',
'vue/no-v-html': 'off',
'vue/comment-directive': 'off',
'vue/no-parsing-error': 'off',
'vue/no-deprecated-v-on-native-modifier': 'off',
'vue/multi-word-component-names': 'off',
'no-useless-escape': 'off',
'no-sparse-arrays': 'off',
'no-prototype-builtins': 'off',
'no-constant-condition': 'off',
'no-use-before-define': 'off',
'no-restricted-globals': 'off',
'no-restricted-syntax': 'off',
'generator-star-spacing': 'off',
'no-unreachable': 'off',
'no-multiple-template-root': 'off',
'no-unused-vars': 'error',
'no-v-model-argument': 'off',
'no-case-declarations': 'off',
'no-console': 'error',
},
};

25
frontend/.gitignore vendored
View File

@ -1,25 +0,0 @@
.DS_Store
node_modules
/dist
# local env files
.env
.env.development
.env.production
*.lock
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
package-lock.json
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

View File

@ -1,82 +0,0 @@
{
"name": "tsplatform",
"version": "1.1.0",
"description": "vue3 vite next admin template",
"author": "SweetHoney",
"license": "MIT",
"scripts": {
"dev": "vite --force",
"build": "vite build",
"lint-fix": "eslint --fix --ext .js --ext .jsx --ext .vue src/"
},
"dependencies": {
"@element-plus/icons-vue": "^2.0.10",
"@wangeditor/editor-for-vue": "^5.1.11",
"axios": "^1.1.3",
"countup.js": "^2.3.2",
"cropperjs": "^1.5.12",
"echarts": "^5.4.0",
"echarts-gl": "^2.0.9",
"echarts-wordcloud": "^2.0.0",
"element-plus": "^2.2.21",
"js-cookie": "^3.0.1",
"jsplumb": "^2.15.6",
"mitt": "^3.0.0",
"nprogress": "^0.2.0",
"pinia": "^2.0.23",
"print-js": "^1.6.0",
"qrcodejs2-fixes": "^0.0.2",
"screenfull": "^6.0.2",
"sortablejs": "^1.15.0",
"splitpanes": "^3.1.5",
"ts-md5": "^1.3.1",
"vue": "^3.2.45",
"vue-clipboard3": "^2.0.0",
"vue-grid-layout": "^3.0.0-beta1",
"vue-i18n": "^9.2.2",
"vue-router": "^4.1.6"
},
"devDependencies": {
"@types/node": "^18.11.9",
"@types/nprogress": "^0.2.0",
"@types/sortablejs": "^1.15.0",
"@typescript-eslint/eslint-plugin": "^5.43.0",
"@typescript-eslint/parser": "^5.43.0",
"@vitejs/plugin-vue": "^3.2.0",
"@vue/compiler-sfc": "^3.2.45",
"dotenv": "^16.0.3",
"eslint": "^8.27.0",
"eslint-plugin-vue": "^9.7.0",
"prettier": "^2.7.1",
"sass": "^1.56.1",
"sass-loader": "^13.2.0",
"typescript": "^4.9.3",
"vite": "^3.2.4",
"vue-eslint-parser": "^9.1.0"
},
"browserslist": [
"> 1%",
"last 2 versions",
"not dead"
],
"bugs": {
"url": "https://gitee.com/lyt-top/vue-next-admin/issues"
},
"engines": {
"node": ">=12.0.0",
"npm": ">= 6.0.0"
},
"keywords": [
"vue",
"vue3",
"vuejs/vue-next",
"element-ui",
"element-plus",
"vue-next-admin",
"next-admin"
],
"repository": {
"type": "git",
"url": "https://gitee.com/lyt-top/vue-next-admin.git"
}
}

View File

@ -1,4 +0,0 @@
declare module 'vue-grid-layout';
declare module 'qrcodejs2-fixes';
declare module 'splitpanes';
declare module 'js-cookie';

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

13
frontend/shim.d.ts vendored
View File

@ -1,13 +0,0 @@
/* eslint-disable */
// 声明文件,*.vue 后缀的文件交给 vue 模块来处理
declare module '*.vue' {
import type { DefineComponent } from 'vue';
const component: DefineComponent<{}, {}, any>;
export default component;
}
// 声明文件,定义全局变量。其它 app.config.globalProperties.xxx使用 getCurrentInstance() 来获取
interface Window {
nextLoading: boolean;
}

View File

@ -1,6 +0,0 @@
declare module '*.json';
declare module '*.png';
declare module '*.jpg';
declare module '*.scss';
declare module '*.ts';
declare module '*.js';

View File

@ -1,107 +0,0 @@
<!--
* @Author: '490912587@qq.com' '490912587@qq.com'
* @Date: 2022-11-17 09:19:20
* @LastEditors: '490912587@qq.com' '490912587@qq.com'
* @LastEditTime: 2022-11-23 17:25:54
* @FilePath: \frontend\src\App.vue
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
-->
<template>
<el-config-provider :size="getGlobalComponentSize" :locale="getGlobalI18n">
<router-view v-show="themeConfig.lockScreenTime > 1" />
<LockScreen v-if="themeConfig.isLockScreen" />
<Setings ref="setingsRef" v-show="themeConfig.lockScreenTime > 1" />
<CloseFull v-if="!themeConfig.isLockScreen" />
</el-config-provider>
</template>
<script lang="ts">
import { defineAsyncComponent, computed, ref, onBeforeMount, onMounted, onUnmounted, nextTick, defineComponent, watch } from 'vue';
import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n';
import { storeToRefs } from 'pinia';
import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes';
import { useThemeConfig } from '/@/stores/themeConfig';
import other from '/@/utils/other';
import { Local, Session } from '/@/utils/storage';
import mittBus from '/@/utils/mitt';
import setIntroduction from '/@/utils/setIconfont';
export default defineComponent({
name: 'app',
components: {
LockScreen: defineAsyncComponent(() => import('/@/layout/lockScreen/index.vue')),
Setings: defineAsyncComponent(() => import('/@/layout/navBars/breadcrumb/setings.vue')),
CloseFull: defineAsyncComponent(() => import('/@/layout/navBars/breadcrumb/closeFull.vue')),
},
setup() {
const { messages, locale } = useI18n();
const setingsRef = ref();
const route = useRoute();
const stores = useTagsViewRoutes();
const storesThemeConfig = useThemeConfig();
const { themeConfig } = storeToRefs(storesThemeConfig);
// 获取全局组件大小
const getGlobalComponentSize = computed(() => {
return other.globalComponentSize();
});
// 获取全局 i18n
const getGlobalI18n = computed(() => {
return messages.value[locale.value];
});
// 设置初始化,防止刷新时恢复默认
onBeforeMount(() => {
// 设置批量第三方 icon 图标
setIntroduction.cssCdn();
// 设置批量第三方 js
setIntroduction.jsCdn();
});
// 页面加载时
onMounted(() => {
nextTick(() => {
// 监听布局配置弹窗点击打开
mittBus.on('openSetingsDrawer', () => {
setingsRef.value.openDrawer();
});
// 获取缓存中的布局配置
if (Local.get('themeConfig')) {
storesThemeConfig.setThemeConfig(Local.get('themeConfig'));
document.documentElement.style.cssText = Local.get('themeConfigStyle');
}
// 获取缓存中的全屏配置
if (Session.get('isTagsViewCurrenFull')) {
stores.setCurrenFullscreen(Session.get('isTagsViewCurrenFull'));
}
});
});
// 页面销毁时,关闭监听布局配置/i18n监听
onUnmounted(() => {
mittBus.off('openSetingsDrawer', () => {});
});
// 监听路由的变化,设置网站标题
watch(
() => route.path,
() => {
other.useTitle();
},
{
deep: true,
}
);
return {
themeConfig,
setingsRef,
getGlobalComponentSize,
getGlobalI18n,
};
},
});
</script>
<style>
.searchBox {
display: flex;
flex-direction: row;
justify-content: flex-start;
}
</style>

View File

@ -1,23 +0,0 @@
/*
* @Author: '490912587@qq.com' '490912587@qq.com'
* @Date: 2022-11-17 09:19:20
* @LastEditors: '490912587@qq.com' '490912587@qq.com'
* @LastEditTime: 2022-11-24 09:43:23
* @FilePath: \tsplatform\frontend\src\api\menu\index.ts
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
import request from '/@/utils/request';
export function getPage(params: object) {
return request({
url: '/city/getPage',
method: 'get',
params
});
}
export function getList(params: object) {
return request({
url: '/city/getList',
method: 'get',
params
});
}

View File

@ -1,34 +0,0 @@
/*
* @Author: '490912587@qq.com' '490912587@qq.com'
* @Date: 2022-11-17 09:19:20
* @LastEditors: '490912587@qq.com' '490912587@qq.com'
* @LastEditTime: 2022-11-23 17:01:13
* @FilePath: \tsplatform\frontend\src\api\login\index.ts
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
import request from '/@/utils/request';
/**
* 登录api接口集合
* @method signIn 用户登录
* @method signOut 用户退出登录
*/
export function signIn(params: object) {
return request({
url: '/auth/login',
method: 'post',
data: params,
});
}
export function getUserInfo() {
return request({
url: '/auth/getUserInfo',
method: 'get'
});
}
export function signOut() {
return request({
url: '/auth/loginOut',
method: 'get'
});
}

View File

@ -1,51 +0,0 @@
/*
* @Author: '490912587@qq.com' '490912587@qq.com'
* @Date: 2022-11-17 09:19:20
* @LastEditors: '490912587@qq.com' '490912587@qq.com'
* @LastEditTime: 2022-11-24 00:24:11
* @FilePath: \tsplatform\frontend\src\api\menu\index.ts
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
import request from '/@/utils/request';
export function getAuthMenu(params: object) {
return request({
url: '/menu/getAuthMenuTree',
method: 'get',
params,
});
}
export function getMenuTree(params: object) {
return request({
url: '/menu/getMenuTree',
method: 'get',
params,
});
}
export function add(params: object) {
return request({
url: '/menu/add',
method: 'post',
data: params
});
}
export function edit(params: object) {
return request({
url: '/menu/edit',
method: 'post',
data: params
});
}
export function del(params: object) {
return request({
url: '/menu/del',
method: 'post',
data: params
});
}
export function setStatus(params: object) {
return request({
url: '/menu/setStatus',
method: 'post',
data: params
});
}

View File

@ -1,52 +0,0 @@
/*
* @Author: '490912587@qq.com' '490912587@qq.com'
* @Date: 2022-11-17 09:19:20
* @LastEditors: '490912587@qq.com' '490912587@qq.com'
* @LastEditTime: 2022-11-23 21:35:46
* @FilePath: \tsplatform\frontend\src\api\menu\index.ts
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
import request from '/@/utils/request';
export function getPage(params: object) {
return request({
url: '/role/getPage',
method: 'get',
params
});
}
export function getList(params: object) {
return request({
url: '/role/getList',
method: 'get',
params
});
}
export function add(params: object) {
return request({
url: '/role/add',
method: 'post',
data: params
});
}
export function edit(params: object) {
return request({
url: '/role/edit',
method: 'post',
data: params
});
}
export function del(params: object) {
return request({
url: '/role/del',
method: 'post',
data: params
});
}
export function setStatus(params: object) {
return request({
url: '/role/setStatus',
method: 'post',
data: params
});
}

View File

@ -1,51 +0,0 @@
/*
* @Author: '490912587@qq.com' '490912587@qq.com'
* @Date: 2022-11-17 09:19:20
* @LastEditors: '490912587@qq.com' '490912587@qq.com'
* @LastEditTime: 2022-11-23 21:35:53
* @FilePath: \tsplatform\frontend\src\api\menu\index.ts
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
import request from '/@/utils/request';
export function getPage(params: object) {
return request({
url: '/user/getPage',
method: 'get',
params
});
}
export function getList(params: object) {
return request({
url: '/role/getList',
method: 'get',
params
});
}
export function add(params: object) {
return request({
url: '/user/add',
method: 'post',
data: params
});
}
export function edit(params: object) {
return request({
url: '/user/edit',
method: 'post',
data: params
});
}
export function del(params: object) {
return request({
url: '/user/del',
method: 'post',
data: params
});
}
export function setStatus(params: object) {
return request({
url: '/user/setStatus',
method: 'post',
data: params
});
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 8.4 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 26 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 36 KiB

View File

@ -1,9 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 50" width="64" height="50">
<defs>
<image width="64" height="50" id="img1" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAAAyCAYAAADsg90UAAAAAXNSR0IB2cksfwAACI5JREFUeJy1WgtsW9UZdvNq0xU6WhZoCCVx7Gunbld1GSsMdYpGREhwr+2IMbQWqRoTk+iWPZi2wWhm1kwEmqV52feRJrbvvd6DiUnbQCAemzY2xh4tSB0wOqZIqAtLYzultIWEpt13btLq+sap/R8nRzpK4vh+5/++85///8851yEk1V+hX6B0tyE3OWwt0x789VR78AKlZ0KBz1oxBE3+BdUW9PNuQ7nJbk/BDQ/v4hi0x44z1R64jyrAVCjQ/fLNN8/ZoUWdgqGc57AFE6I86giH+QRw6XI9QE4RBz3iTAyVW3EyQdEDUmeIIhyeFNtMHO/o0B4e8qYASfVvLk2p4BKgdnioFCAvEQeddhnyFivOpOgvBaFXiAKcygQDrk927S/zjkae5xUA/X3YI/C5AFwHLrSPw+2+YYfCMugiCvDaCbGt0hc9uAXuP1OEAPACZQ+fAGguQ9nGgglx0OfsOAhq24lBcG/YYQa/kWLIz3XlCW4B6mKRCoCMEQdNu3VpnRVnMhBYA2L/LVCATCooXuNJSHXFzv58P+mMyyu5RQDAKNntdLnNjoN0+NMCM0D8901NDkGXuyBAseRZn3Ubagu3AFjTd1GXAdZdpCqurMgSIBS4BwRn8wgwje/d4pV6yz2adGQJyM/bo/ZyC+DSlWqApIiDHqtPyFdlCyBeD4Lv5xHgr5mAWO4ZjTRh9s8tlQDoryIbrOISoLYvvAIALxIHnIHn3GnFmfDfztLhH/IEv/vYd72xyKElJM/6Gdjj4fYCuNA3yYMa6ogdBwQfvIwAk+mguHZz3+MbMPsfLrEALD3v5RfAkH3UOID+Jqqwj2ULIDZeJvhF2He8I0NfX2ry8wI85VSy41LBzaUPsXT4L/Iy0OUbrTgpsXUlyI7lEOAsvGOboPRdKejK28shAPqpek1etxjHArxAiXCo/pAdB2QPLRQg8BLcv8ITi4h4bnaZBGD2+IsQQG0DCDUyv2LfjcHVQyB93iLAecz+bvY/T1x6YrnImwIkVakIAeSrAfIucdCz7qRcY8VJh8RrQDplWfvHxttaVvkGe6vg/h8tpwDoR926wpcOb9CkEhQ4Mbrqym4rTkrcydLhs5bU95Wwwwx+311m8qxPQ4CtvE6AdKjcLlCrQkNJXNXdnYUD0t+eF+AE1v76rV0/qvTEo/8kkkGJq/yFLIKhPsgtgEszl8E4cdAxPHdllgDBwGZW9k6Fguaa9A4PtMEwkrDe0chhCPAZ/E5dNn/kPiWqGe5mVSH1rJCdze2w4rDNDsi/gdn/FPtb0KTfUmeyQenvuE45WCLQd6unsc3fwKeAw0yHX+Zwu247DpbB3emQv3R7x7du8GgybdtrKGc39Ty23rQnqfKk5y9wCwD1XACZJg56xGUMZFVhx1taytjPBnWAfuihyT+3TEiAQwC1Mhzmqwrr9QhbBoeJg36A6Ou0Y/kGe2qQ+mhiGspHDcODTZfs0eRr8fkE0Z4xpyGt4RJgTnX1carq8Jw9dhzv6BB5k+VJyK9t6+y8dNK74bGHMSHK00Scc/CC7fwC6MotAjX6GuqTzsTBkosYW/f9YKUnIb1OFiAW/c4Ce5Lq18jLKKnu5xaApTWBHn0n8Nz6ixhw4zvJ5HXlvU2R3gWui02XizwhrEznbTW9vQ64nUEckBUut13EQOHzFFUA70jErBv+09xcYrXHqUXK8H9qIXXapSs1dm4FN1SF95DdzlD72LMNUt/15CMvXT65NfzIRtQOq5FCv7jAHkPppdqDZ3YvZFZgY8WEQN8dvvFxpB8hLvWT3T8uyWxckG9CEfX38fk0ahGgmboMMIk/2xg5UJKbYZ62sf9RbI7UPxGJzLgT0R2Y/RM0z1HO+QZ6Gl/3+dh2Wmdb6HQwUJc9IfI6fPc40Z5xCLeW2wvw8Pfoy0B5mfoMAuYLn+7oKE0FxZqp+YvWTHugw24PvvtLIjZLh83cAghzmxHqASb5qntz/4EvsfEy7UHroepvJoKtWdUcPPKrVGwsA6k2FuYTAPXAGoC8RfYCStflqRvv3VuB4Hc1SI9bBJjAZ1VWe+p1+TqBHpfG+M8Ksa0EgLacAnhiETNzIPjdbztLPIfPWrME0CSkQ+UfxDFmkQ5v5RPAYcYBckFTcDfUWc+hwZsw06tA+EiOi5RoDns66ctA/Qm3AE4tuhYgZ5Zl9uPR32165PtlINoMwjM5jtPfSvn9WTe/iEufw7PUW+U3a2NSKZ8CTU0s+DyzHAJgq9yuNDaywxNtkQuVWaTDBqs5SIdsQt4hjsXOCvmvzrDu6Fdnebo3Hj3u69xXngoFqkH09KL3ie2BB6y2XCsfZNt1apnOqsL7uY/KoB57k+SDJRUhIZlX2iD4UJ4b5ef+3dqabY9hlunUdPt0XXyIryqs1yKVAv3qbPFuKNNedaAR5FeD4NE8AqRTwZ1ZmxqnHv0EcI4Rxz3hNqSqxThevrEXqpJq31IJgOD3TN3+h0tYmmPpLt9bJex80W4SRBzmEF7kE8Bhbo5aONwutwCx6K4JUVyByu/JfOTn+6EFAiTNN1uoAgxyC1BvqFcAZLJo8pr8rlvuq8wExfpFUl+u/s7/dt6R9UKkS5ergHeaOP6Yc2SQLw7Mqa6SDznsHakvzLAyoeAPCyRvVoXpUGCb1ZZqRWFnhdQXPWcg3Jac5App7C2MImf/5Kb+nupJ0X8FSL1NEOACEyyHPQ9QbWA73CIEkBuEIqrCzUO9CsNB6esCqQ8pAqD/Oe33l9vs2SLQd6svuhJSWW6GeVptLFKGbMD9eltjZ2cjw5m4o60ChF4lCvBeJhjIuntAYF4N3KNEO9Lwgmo+F/D5mNt1cbr/2OeD916qx+HSB4gCsDdNdmXZM7dbjRJtYXeZd/EJ4DDX3Q4uARLSj604yO23UgVA2jRy2EO+OkNX/w+fZNm8pw5QbAAAAABJRU5ErkJggg=="/>
</defs>
<style>
tspan { white-space:pre }
</style>
<use id="Background" href="#img1" x="0" y="0" />
</svg>

Before

Width:  |  Height:  |  Size: 3.2 KiB

View File

@ -1,30 +0,0 @@
<template>
<slot v-if="getUserAuthBtnList" />
</template>
<script lang="ts">
import { computed, defineComponent } from 'vue';
import { storeToRefs } from 'pinia';
import { useUserInfo } from '/@/stores/userInfo';
export default defineComponent({
name: 'auth',
props: {
value: {
type: String,
default: () => '',
},
},
setup(props) {
const stores = useUserInfo();
const { userInfos } = storeToRefs(stores);
// 获取 vuex 中的用户权限
const getUserAuthBtnList = computed(() => {
return userInfos.value.authBtnList.some((v: string) => v === props.value);
});
return {
getUserAuthBtnList,
};
},
});
</script>

View File

@ -1,31 +0,0 @@
<template>
<slot v-if="getUserAuthBtnList" />
</template>
<script lang="ts">
import { computed, defineComponent } from 'vue';
import { storeToRefs } from 'pinia';
import { useUserInfo } from '/@/stores/userInfo';
import { judementSameArr } from '/@/utils/arrayOperation';
export default defineComponent({
name: 'authAll',
props: {
value: {
type: Array,
default: () => [],
},
},
setup(props) {
const stores = useUserInfo();
const { userInfos } = storeToRefs(stores);
// 获取 pinia 中的用户权限
const getUserAuthBtnList = computed(() => {
return judementSameArr(props.value, userInfos.value.authBtnList);
});
return {
getUserAuthBtnList,
};
},
});
</script>

View File

@ -1,36 +0,0 @@
<template>
<slot v-if="getUserAuthBtnList" />
</template>
<script lang="ts">
import { computed, defineComponent } from 'vue';
import { storeToRefs } from 'pinia';
import { useUserInfo } from '/@/stores/userInfo';
export default defineComponent({
name: 'auths',
props: {
value: {
type: Array,
default: () => [],
},
},
setup(props) {
const stores = useUserInfo();
const { userInfos } = storeToRefs(stores);
// 获取 vuex 中的用户权限
const getUserAuthBtnList = computed(() => {
let flag = false;
userInfos.value.authBtnList.map((val: string) => {
props.value.map((v) => {
if (val === v) flag = true;
});
});
return flag;
});
return {
getUserAuthBtnList,
};
},
});
</script>

View File

@ -1,149 +0,0 @@
<template>
<div>
<el-dialog title="更换头像" v-model="isShowDialog" width="769px">
<div class="cropper-warp">
<div class="cropper-warp-left">
<img :src="cropperImg" class="cropper-warp-left-img" />
</div>
<div class="cropper-warp-right">
<div class="cropper-warp-right-title">预览</div>
<div class="cropper-warp-right-item">
<div class="cropper-warp-right-value">
<img :src="cropperImgBase64" class="cropper-warp-right-value-img" />
</div>
<div class="cropper-warp-right-label">100 x 100</div>
</div>
<div class="cropper-warp-right-item">
<div class="cropper-warp-right-value">
<img :src="cropperImgBase64" class="cropper-warp-right-value-img cropper-size" />
</div>
<div class="cropper-warp-right-label">50 x 50</div>
</div>
</div>
</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="onCancel" size="default"> </el-button>
<el-button type="primary" @click="onSubmit" size="default"> </el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script lang="ts">
import { reactive, toRefs, nextTick, defineComponent } from 'vue';
import Cropper from 'cropperjs';
import 'cropperjs/dist/cropper.css';
export default defineComponent({
name: 'cropperIndex',
setup() {
const state = reactive({
isShowDialog: false,
cropperImg: '',
cropperImgBase64: '',
cropper: null,
});
// 打开弹窗
const openDialog = (imgs: any) => {
state.cropperImg = imgs;
state.isShowDialog = true;
nextTick(() => {
initCropper();
});
};
// 关闭弹窗
const closeDialog = () => {
state.isShowDialog = false;
};
// 取消
const onCancel = () => {
closeDialog();
};
// 更换
const onSubmit = () => {
// state.cropperImgBase64 = state.cropper.getCroppedCanvas().toDataURL('image/jpeg');
};
// 初始化cropperjs图片裁剪
const initCropper = () => {
const letImg: any = document.querySelector('.cropper-warp-left-img');
(<any>state.cropper) = new Cropper(letImg, {
viewMode: 1,
dragMode: 'none',
initialAspectRatio: 1,
aspectRatio: 1,
preview: '.before',
background: false,
autoCropArea: 0.6,
zoomOnWheel: false,
crop: () => {
state.cropperImgBase64 = (<any>state.cropper).getCroppedCanvas().toDataURL('image/jpeg');
},
});
};
return {
openDialog,
closeDialog,
onCancel,
onSubmit,
initCropper,
...toRefs(state),
};
},
});
</script>
<style scoped lang="scss">
.cropper-warp {
display: flex;
.cropper-warp-left {
position: relative;
display: inline-block;
height: 350px;
flex: 1;
border: 1px solid var(--el-border-color);
background: var(--el-color-white);
overflow: hidden;
background-repeat: no-repeat;
cursor: move;
border-radius: var(--el-border-radius-base);
.cropper-warp-left-img {
width: 100%;
height: 100%;
}
}
.cropper-warp-right {
width: 150px;
height: 350px;
.cropper-warp-right-title {
text-align: center;
height: 20px;
line-height: 20px;
}
.cropper-warp-right-item {
margin: 15px 0;
.cropper-warp-right-value {
display: flex;
.cropper-warp-right-value-img {
width: 100px;
height: 100px;
border-radius: var(--el-border-radius-circle);
margin: auto;
}
.cropper-size {
width: 50px;
height: 50px;
}
}
.cropper-warp-right-label {
text-align: center;
font-size: 12px;
color: var(--el-text-color-primary);
height: 30px;
line-height: 30px;
}
}
}
}
</style>

View File

@ -1,88 +0,0 @@
<template>
<div class="editor-container">
<Toolbar :editor="editorRef" :mode="mode" />
<Editor :mode="mode" :defaultConfig="editorConfig" :style="{ height }" v-model="editorVal" @onCreated="handleCreated" @onChange="handleChange" />
</div>
</template>
<script lang="ts">
// https://www.wangeditor.com/v5/for-frame.html#vue3
import '@wangeditor/editor/dist/css/style.css';
import { defineComponent, reactive, toRefs, shallowRef, watch, onBeforeUnmount } from 'vue';
import { Toolbar, Editor } from '@wangeditor/editor-for-vue';
export default defineComponent({
name: 'wngEditor',
components: { Toolbar, Editor },
props: {
// 是否禁用
disable: {
type: Boolean,
default: () => true,
},
// 内容框默认 placeholder
placeholder: {
type: String,
default: () => '请输入内容...',
},
// 双向绑定:双向绑定值,字段名为固定,改了之后将不生效
// 参考https://v3.cn.vuejs.org/guide/migration/v-model.html#%E8%BF%81%E7%A7%BB%E7%AD%96%E7%95%A5
modelValue: String,
// https://www.wangeditor.com/v5/getting-started.html#mode-%E6%A8%A1%E5%BC%8F
// 模式,可选 <default|simple>,默认 default
mode: {
type: String,
default: () => 'default',
},
// 高度
height: {
type: String,
default: () => '310px',
},
},
setup(props, { emit }) {
const editorRef = shallowRef();
const state = reactive({
editorConfig: {
placeholder: props.placeholder,
},
editorVal: props.modelValue,
});
// 编辑器回调函数
const handleCreated = (editor: any) => {
editorRef.value = editor;
};
// 编辑器内容改变时
const handleChange = (editor: any) => {
// console.log(editor.getText());
// console.log(editor.getHtml());
emit('update:modelValue', editor.getHtml());
};
// 监听是否禁用改变
// https://gitee.com/lyt-top/vue-next-admin/issues/I4LM7I
watch(
() => props.disable,
(bool) => {
const editor = editorRef.value;
if (editor == null) return;
bool ? editor.disable() : editor.enable();
},
{
deep: true,
}
);
// 页面销毁时
onBeforeUnmount(() => {
const editor = editorRef.value;
if (editor == null) return;
editor.destroy();
});
return {
editorRef,
handleCreated,
handleChange,
...toRefs(state),
};
},
});
</script>

View File

@ -1,252 +0,0 @@
<template>
<div class="icon-selector w100 h100">
<el-popover
placement="bottom"
:width="fontIconWidth"
trigger="click"
transition="el-zoom-in-top"
popper-class="icon-selector-popper"
@show="onPopoverShow"
>
<template #reference>
<el-input
v-model="fontIconSearch"
:placeholder="fontIconPlaceholder"
:clearable="clearable"
:disabled="disabled"
:size="size"
ref="inputWidthRef"
@clear="onClearFontIcon"
@focus="onIconFocus"
@blur="onIconBlur"
>
<template #prepend>
<SvgIcon
:name="fontIconPrefix === '' ? prepend : fontIconPrefix"
class="font14"
v-if="fontIconPrefix === '' ? prepend?.indexOf('ele-') > -1 : fontIconPrefix?.indexOf('ele-') > -1"
/>
<i v-else :class="fontIconPrefix === '' ? prepend : fontIconPrefix" class="font14"></i>
</template>
</el-input>
</template>
<template #default>
<div class="icon-selector-warp">
<div class="icon-selector-warp-title flex">
<div class="flex-auto">{{ title }}</div>
<div class="icon-selector-warp-title-tab" v-if="type === 'all'">
<span :class="{ 'span-active': fontIconType === 'ali' }" @click="onIconChange('ali')" class="ml10" title="iconfont 图标">ali</span>
<span :class="{ 'span-active': fontIconType === 'ele' }" @click="onIconChange('ele')" class="ml10" title="elementPlus 图标">ele</span>
<span :class="{ 'span-active': fontIconType === 'awe' }" @click="onIconChange('awe')" class="ml10" title="fontawesome 图标">awe</span>
</div>
</div>
<div class="icon-selector-warp-row">
<el-scrollbar ref="selectorScrollbarRef">
<el-row :gutter="10" v-if="fontIconSheetsFilterList.length > 0">
<el-col :xs="6" :sm="4" :md="4" :lg="4" :xl="4" @click="onColClick(v)" v-for="(v, k) in fontIconSheetsFilterList" :key="k">
<div class="icon-selector-warp-item" :class="{ 'icon-selector-active': fontIconPrefix === v }">
<div class="flex-margin">
<div class="icon-selector-warp-item-value">
<SvgIcon :name="v" />
</div>
</div>
</div>
</el-col>
</el-row>
<el-empty :image-size="100" v-if="fontIconSheetsFilterList.length <= 0" :description="emptyDescription"></el-empty>
</el-scrollbar>
</div>
</div>
</template>
</el-popover>
</div>
</template>
<script lang="ts">
import { ref, toRefs, reactive, onMounted, nextTick, computed, watch, defineComponent } from 'vue';
import initIconfont from '/@/utils/getStyleSheets';
export default defineComponent({
name: 'iconSelector',
emits: ['update:modelValue', 'get', 'clear'],
props: {
// 输入框前置内容
prepend: {
type: String,
default: () => 'ele-Pointer',
},
// 输入框占位文本
placeholder: {
type: String,
default: () => '请输入内容搜索图标或者选择图标',
},
// 输入框占位文本
size: {
type: String,
default: () => 'default',
},
// 弹窗标题
title: {
type: String,
default: () => '请选择图标',
},
// icon 图标类型
type: {
type: String,
default: () => 'ele',
},
// 禁用
disabled: {
type: Boolean,
default: () => false,
},
// 是否可清空
clearable: {
type: Boolean,
default: () => true,
},
// 自定义空状态描述文字
emptyDescription: {
type: String,
default: () => '无相关图标',
},
// 双向绑定值,默认为 modelValue
// 参考https://v3.cn.vuejs.org/guide/migration/v-model.html#%E8%BF%81%E7%A7%BB%E7%AD%96%E7%95%A5
// 参考https://v3.cn.vuejs.org/guide/component-custom-events.html#%E5%A4%9A%E4%B8%AA-v-model-%E7%BB%91%E5%AE%9A
modelValue: String,
},
setup(props, { emit }) {
const inputWidthRef = ref();
const selectorScrollbarRef = ref();
const state = reactive({
fontIconPrefix: '',
fontIconWidth: 0,
fontIconSearch: '',
fontIconTabsIndex: 0,
fontIconSheetsList: [],
fontIconPlaceholder: '',
fontIconType: 'ali',
fontIconShow: true,
});
// 处理 input 获取焦点时modelValue 有值时,改变 input 的 placeholder 值
const onIconFocus = () => {
if (!props.modelValue) return false;
state.fontIconSearch = '';
state.fontIconPlaceholder = props.modelValue;
};
// 处理 input 失去焦点时,为空将清空 input 值,为点击选中图标时,将取原先值
const onIconBlur = () => {
setTimeout(() => {
const icon = state.fontIconSheetsList.filter((icon: string) => icon === state.fontIconSearch);
if (icon.length <= 0) state.fontIconSearch = '';
}, 300);
};
// 处理 icon 双向绑定数值回显
const initModeValueEcho = () => {
if (props.modelValue === '') return ((<string | undefined>state.fontIconPlaceholder) = props.placeholder);
(<string | undefined>state.fontIconPlaceholder) = props.modelValue;
(<string | undefined>state.fontIconPrefix) = props.modelValue;
};
// 处理 icon type 类型为 all 时,类型 ali、ele、awe 回显问题
const initFontIconTypeEcho = () => {
if ((<any>props.modelValue)?.indexOf('iconfont') > -1) onIconChange('ali');
else if ((<any>props.modelValue)?.indexOf('ele-') > -1) onIconChange('ele');
else if ((<any>props.modelValue)?.indexOf('fa') > -1) onIconChange('awe');
else onIconChange('ali');
};
// 图标搜索及图标数据显示
const fontIconSheetsFilterList = computed(() => {
if (!state.fontIconSearch) return state.fontIconSheetsList;
let search = state.fontIconSearch.trim().toLowerCase();
return state.fontIconSheetsList.filter((item: any) => {
if (item.toLowerCase().indexOf(search) !== -1) return item;
});
});
// 获取 input 的宽度
const getInputWidth = () => {
nextTick(() => {
state.fontIconWidth = inputWidthRef.value.$el.offsetWidth;
});
};
// 监听页面宽度改变
const initResize = () => {
window.addEventListener('resize', () => {
getInputWidth();
});
};
// 初始化数据
const initFontIconData = async (type: string) => {
state.fontIconSheetsList = [];
if (type === 'ali') {
await initIconfont.ali().then((res: any) => {
// 阿里字体图标使用 `iconfont xxx`
state.fontIconSheetsList = res.map((i: string) => `iconfont ${i}`);
});
} else if (type === 'ele') {
await initIconfont.ele().then((res: any) => {
state.fontIconSheetsList = res;
});
} else if (type === 'awe') {
await initIconfont.awe().then((res: any) => {
// fontawesome字体图标使用 `fa xxx`
state.fontIconSheetsList = res.map((i: string) => `fa ${i}`);
});
}
// 初始化 input 的 placeholder
// 参考单项数据流https://cn.vuejs.org/v2/guide/components-props.html?#%E5%8D%95%E5%90%91%E6%95%B0%E6%8D%AE%E6%B5%81
state.fontIconPlaceholder = props.placeholder;
// 初始化双向绑定回显
initModeValueEcho();
};
// 图标点击切换
const onIconChange = (type: string) => {
state.fontIconType = type;
initFontIconData(type);
};
// 获取当前点击的 icon 图标
const onColClick = (v: any) => {
state.fontIconPlaceholder = v;
state.fontIconPrefix = v;
emit('get', state.fontIconPrefix);
emit('update:modelValue', state.fontIconPrefix);
};
// 清空当前点击的 icon 图标
const onClearFontIcon = () => {
state.fontIconPrefix = '';
emit('clear', state.fontIconPrefix);
emit('update:modelValue', state.fontIconPrefix);
};
// 监听 Popover 打开,用于双向绑定值回显
const onPopoverShow = () => {
initModeValueEcho();
initFontIconTypeEcho();
};
// 页面加载时
onMounted(() => {
initModeValueEcho();
initResize();
getInputWidth();
});
// 监听双向绑定 modelValue 的变化
watch(
() => props.modelValue,
() => {
initModeValueEcho();
}
);
return {
inputWidthRef,
selectorScrollbarRef,
fontIconSheetsFilterList,
onColClick,
onIconChange,
onClearFontIcon,
onIconFocus,
onIconBlur,
onPopoverShow,
...toRefs(state),
};
},
});
</script>

View File

@ -1,195 +0,0 @@
<template>
<div class="notice-bar" :style="{ background, height: `${height}px` }" v-show="!isMode">
<div class="notice-bar-warp" :style="{ color, fontSize: `${size}px` }">
<i v-if="leftIcon" class="notice-bar-warp-left-icon" :class="leftIcon"></i>
<div class="notice-bar-warp-text-box" ref="noticeBarWarpRef">
<div class="notice-bar-warp-text" ref="noticeBarTextRef" v-if="!scrollable">{{ text }}</div>
<div class="notice-bar-warp-slot" v-else><slot /></div>
</div>
<SvgIcon :name="rightIcon" v-if="rightIcon" class="notice-bar-warp-right-icon" @click="onRightIconClick" />
</div>
</div>
</template>
<script lang="ts">
import { toRefs, reactive, defineComponent, ref, onMounted, nextTick } from 'vue';
export default defineComponent({
name: 'noticeBar',
props: {
// 通知栏模式,可选值为 closeable link
mode: {
type: String,
default: () => '',
},
// 通知文本内容
text: {
type: String,
default: () => '',
},
// 通知文本颜色
color: {
type: String,
default: () => 'var(--el-color-warning)',
},
// 通知背景色
background: {
type: String,
default: () => 'var(--el-color-warning-light-9)',
},
// 字体大小单位px
size: {
type: [Number, String],
default: () => 14,
},
// 通知栏高度单位px
height: {
type: Number,
default: () => 40,
},
// 动画延迟时间 (s)
delay: {
type: Number,
default: () => 1,
},
// 滚动速率 (px/s)
speed: {
type: Number,
default: () => 100,
},
// 是否开启垂直滚动
scrollable: {
type: Boolean,
default: () => false,
},
// 自定义左侧图标
leftIcon: {
type: String,
default: () => '',
},
// 自定义右侧图标
rightIcon: {
type: String,
default: () => '',
},
},
setup(props, { emit }) {
const noticeBarWarpRef = ref();
const noticeBarTextRef = ref();
const state = reactive({
order: 1,
oneTime: 0,
twoTime: 0,
warpOWidth: 0,
textOWidth: 0,
isMode: false,
});
// 初始化 animation 各项参数
const initAnimation = () => {
nextTick(() => {
state.warpOWidth = noticeBarWarpRef.value.offsetWidth;
state.textOWidth = noticeBarTextRef.value.offsetWidth;
document.styleSheets[0].insertRule(`@keyframes oneAnimation {0% {left: 0px;} 100% {left: -${state.textOWidth}px;}}`);
document.styleSheets[0].insertRule(`@keyframes twoAnimation {0% {left: ${state.warpOWidth}px;} 100% {left: -${state.textOWidth}px;}}`);
computeAnimationTime();
setTimeout(() => {
changeAnimation();
}, props.delay * 1000);
});
};
// 计算 animation 滚动时长
const computeAnimationTime = () => {
state.oneTime = state.textOWidth / props.speed;
state.twoTime = (state.textOWidth + state.warpOWidth) / props.speed;
};
// 改变 animation 动画调用
const changeAnimation = () => {
if (state.order === 1) {
noticeBarTextRef.value.style.cssText = `animation: oneAnimation ${state.oneTime}s linear; opactity: 1;}`;
state.order = 2;
} else {
noticeBarTextRef.value.style.cssText = `animation: twoAnimation ${state.twoTime}s linear infinite; opacity: 1;`;
}
};
// 监听 animation 动画的结束
const listenerAnimationend = () => {
noticeBarTextRef.value.addEventListener(
'animationend',
() => {
changeAnimation();
},
false
);
};
// 右侧 icon 图标点击
const onRightIconClick = () => {
if (!props.mode) return false;
if (props.mode === 'closeable') {
state.isMode = true;
emit('close');
} else if (props.mode === 'link') {
emit('link');
}
};
// 页面加载时
onMounted(() => {
if (props.scrollable) return false;
initAnimation();
listenerAnimationend();
});
return {
noticeBarWarpRef,
noticeBarTextRef,
onRightIconClick,
...toRefs(state),
};
},
});
</script>
<style scoped lang="scss">
.notice-bar {
padding: 0 15px;
width: 100%;
border-radius: 4px;
.notice-bar-warp {
display: flex;
align-items: center;
width: 100%;
height: inherit;
.notice-bar-warp-text-box {
flex: 1;
height: inherit;
display: flex;
align-items: center;
overflow: hidden;
position: relative;
.notice-bar-warp-text {
white-space: nowrap;
position: absolute;
left: 0;
}
.notice-bar-warp-slot {
width: 100%;
white-space: nowrap;
:deep(.el-carousel__item) {
display: flex;
align-items: center;
}
}
}
.notice-bar-warp-left-icon {
width: 24px;
font-size: inherit !important;
}
.notice-bar-warp-right-icon {
width: 24px;
text-align: right;
font-size: inherit !important;
&:hover {
cursor: pointer;
}
}
}
}
</style>

View File

@ -1,73 +0,0 @@
<template>
<i v-if="isShowIconSvg" class="el-icon" :style="setIconSvgStyle">
<component :is="getIconName" />
</i>
<div v-else-if="isShowIconImg" :style="setIconImgOutStyle">
<img :src="getIconName" :style="setIconSvgInsStyle" />
</div>
<i v-else :class="getIconName" :style="setIconSvgStyle" />
</template>
<script lang="ts">
import { computed, defineComponent } from 'vue';
export default defineComponent({
name: 'svgIcon',
props: {
// svg 图标组件名字
name: {
type: String,
},
// svg 大小
size: {
type: Number,
default: () => 14,
},
// svg 颜色
color: {
type: String,
},
},
setup(props) {
// 在线链接、本地引入地址前缀
const linesString = ['https', 'http', '/src', '/assets', import.meta.env.VITE_PUBLIC_PATH];
// 获取 icon 图标名称
const getIconName = computed(() => {
return props?.name;
});
// 用于判断 element plus 自带 svg 图标的显示、隐藏
const isShowIconSvg = computed(() => {
return props?.name?.startsWith('ele-');
});
// 用于判断在线链接、本地引入等图标显示、隐藏
const isShowIconImg = computed(() => {
return linesString.find((str) => props.name?.startsWith(str));
});
// 设置图标样式
const setIconSvgStyle = computed(() => {
return `font-size: ${props.size}px;color: ${props.color};`;
});
// 设置图片样式
const setIconImgOutStyle = computed(() => {
return `width: ${props.size}px;height: ${props.size}px;display: inline-block;overflow: hidden;`;
});
// 设置图片样式
// https://gitee.com/lyt-top/vue-next-admin/issues/I59ND0
const setIconSvgInsStyle = computed(() => {
const filterStyle: string[] = [];
const compatibles: string[] = ['-webkit', '-ms', '-o', '-moz'];
compatibles.forEach((j) => filterStyle.push(`${j}-filter: drop-shadow(${props.color} 30px 0);`));
return `width: ${props.size}px;height: ${props.size}px;position: relative;left: -${props.size}px;${filterStyle.join('')}`;
});
return {
getIconName,
isShowIconSvg,
isShowIconImg,
setIconSvgStyle,
setIconImgOutStyle,
setIconSvgInsStyle,
};
},
});
</script>

View File

@ -1,68 +0,0 @@
import { createI18n } from 'vue-i18n';
import pinia from '/@/stores/index';
import { storeToRefs } from 'pinia';
import { useThemeConfig } from '/@/stores/themeConfig';
import zhcnLocale from 'element-plus/lib/locale/lang/zh-cn';
import enLocale from 'element-plus/lib/locale/lang/en';
import zhtwLocale from 'element-plus/lib/locale/lang/zh-tw';
import nextZhcn from '/@/i18n/lang/zh-cn';
import nextEn from '/@/i18n/lang/en';
import nextZhtw from '/@/i18n/lang/zh-tw';
import pagesLoginZhcn from '/@/i18n/pages/login/zh-cn';
import pagesLoginEn from '/@/i18n/pages/login/en';
import pagesLoginZhtw from '/@/i18n/pages/login/zh-tw';
import pagesFormI18nZhcn from '/@/i18n/pages/formI18n/zh-cn';
import pagesFormI18nEn from '/@/i18n/pages/formI18n/en';
import pagesFormI18nZhtw from '/@/i18n/pages/formI18n/zh-tw';
// 定义语言国际化内容
/**
* 说明:
* /src/i18n/lang 下的 ts 为框架的国际化内容
* /src/i18n/pages 下的 ts 为各界面的国际化内容
*/
const messages = {
[zhcnLocale.name]: {
...zhcnLocale,
message: {
...nextZhcn,
...pagesLoginZhcn,
...pagesFormI18nZhcn,
},
},
[enLocale.name]: {
...enLocale,
message: {
...nextEn,
...pagesLoginEn,
...pagesFormI18nEn,
},
},
[zhtwLocale.name]: {
...zhtwLocale,
message: {
...nextZhtw,
...pagesLoginZhtw,
...pagesFormI18nZhtw,
},
},
};
// 读取 pinia 默认语言
const stores = useThemeConfig(pinia);
const { themeConfig } = storeToRefs(stores);
// 导出语言国际化
// https://vue-i18n.intlify.dev/guide/essentials/fallback.html#explicit-fallback-with-one-locale
export const i18n = createI18n({
legacy: false,
silentTranslationWarn: true,
missingWarn: false,
silentFallbackWarn: true,
fallbackWarn: false,
locale: themeConfig.value.globalI18n,
fallbackLocale: zhcnLocale.name,
messages,
});

View File

@ -1,13 +0,0 @@
// 定义内容
export default {
formI18nLabel: {
name: 'name',
email: 'email',
autograph: 'autograph',
},
formI18nPlaceholder: {
name: 'Please enter your name',
email: 'Please enter the users Department',
autograph: 'Please enter the login account name',
},
};

View File

@ -1,13 +0,0 @@
// 定义内容
export default {
formI18nLabel: {
name: '姓名',
email: '用户归属部门',
autograph: '登陆账户名',
},
formI18nPlaceholder: {
name: '请输入姓名',
email: '请输入用户归属部门',
autograph: '请输入登陆账户名',
},
};

View File

@ -1,13 +0,0 @@
// 定义内容
export default {
formI18nLabel: {
name: '姓名',
email: '用戶歸屬部門',
autograph: '登入帳戶名',
},
formI18nPlaceholder: {
name: '請輸入姓名',
email: '請輸入用戶歸屬部門',
autograph: '請輸入登入帳戶名',
},
};

View File

@ -1,29 +0,0 @@
// 定义内容
export default {
label: {
one1: 'User name login',
two2: 'Mobile number',
},
link: {
one3: 'Third party login',
two4: 'Links',
},
account: {
accountPlaceholder1: 'The user name admin or not is common',
accountPlaceholder2: 'Password: 123456',
accountPlaceholder3: 'Please enter the verification code',
accountBtnText: 'Sign in',
},
mobile: {
placeholder1: 'Please input mobile phone number',
placeholder2: 'Please enter the verification code',
codeText: 'Get code',
btnText: 'Sign in',
msgText:
'Warm tip: it is recommended to use Google, Microsoft edge, version 79.0.1072.62 and above browsers, and 360 browser, please use speed mode',
},
scan: {
text: 'Open the mobile phone to scan and quickly log in / register',
},
signInText: 'welcome back!',
};

View File

@ -1,28 +0,0 @@
// 定义内容
export default {
label: {
one1: '用户名登录',
two2: '手机号登录',
},
link: {
one3: '第三方登录',
two4: '友情链接',
},
account: {
accountPlaceholder1: '用户名 admin 或不输均为 common',
accountPlaceholder2: '密码123456',
accountPlaceholder3: '请输入验证码',
accountBtnText: '登 录',
},
mobile: {
placeholder1: '请输入手机号',
placeholder2: '请输入验证码',
codeText: '获取验证码',
btnText: '登 录',
msgText: '* 温馨提示建议使用谷歌、Microsoft Edge版本 79.0.1072.62 及以上浏览器360浏览器请使用极速模式',
},
scan: {
text: '打开手机扫一扫,快速登录/注册',
},
signInText: '欢迎回来!',
};

View File

@ -1,28 +0,0 @@
// 定义内容
export default {
label: {
one1: '用戶名登入',
two2: '手機號登入',
},
link: {
one3: '協力廠商登入',
two4: '友情連結',
},
account: {
accountPlaceholder1: '用戶名admin或不輸均為common',
accountPlaceholder2: '密碼123456',
accountPlaceholder3: '請輸入驗證碼',
accountBtnText: '登入',
},
mobile: {
placeholder1: '請輸入手機號',
placeholder2: '請輸入驗證碼',
codeText: '獲取驗證碼',
btnText: '登入',
msgText: '* 溫馨提示建議使用穀歌、Microsoft Edge版本79.0.1072.62及以上瀏覽器360瀏覽器請使用極速模式',
},
scan: {
text: '打開手機掃一掃,快速登錄/注册',
},
signInText: '歡迎回來!',
};

View File

@ -1,165 +0,0 @@
<template>
<div class="h100" v-show="!isTagsViewCurrenFull">
<el-aside class="layout-aside" :class="setCollapseStyle">
<Logo v-if="setShowLogo" />
<el-scrollbar class="flex-auto" ref="layoutAsideScrollbarRef" @mouseenter="onAsideEnterLeave(true)" @mouseleave="onAsideEnterLeave(false)">
<Vertical :menuList="menuList" />
</el-scrollbar>
</el-aside>
</div>
</template>
<script lang="ts">
import { defineAsyncComponent, toRefs, reactive, computed, watch, onBeforeMount, defineComponent, ref } from 'vue';
import { storeToRefs } from 'pinia';
import pinia from '/@/stores/index';
import { useRoutesList } from '/@/stores/routesList';
import { useThemeConfig } from '/@/stores/themeConfig';
import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes';
import mittBus from '/@/utils/mitt';
export default defineComponent({
name: 'layoutAside',
components: {
Logo: defineAsyncComponent(() => import('/@/layout/logo/index.vue')),
Vertical: defineAsyncComponent(() => import('/@/layout/navMenu/vertical.vue')),
},
setup() {
const layoutAsideScrollbarRef = ref();
const stores = useRoutesList();
const storesThemeConfig = useThemeConfig();
const storesTagsViewRoutes = useTagsViewRoutes();
const { routesList } = storeToRefs(stores);
const { themeConfig } = storeToRefs(storesThemeConfig);
const { isTagsViewCurrenFull } = storeToRefs(storesTagsViewRoutes);
const state = reactive({
menuList: [],
clientWidth: 0,
});
// 设置菜单展开/收起时的宽度
const setCollapseStyle = computed(() => {
const { layout, isCollapse, menuBar } = themeConfig.value;
const asideBrTheme = ['#FFFFFF', '#FFF', '#fff', '#ffffff'];
const asideBrColor = asideBrTheme.includes(menuBar) ? 'layout-el-aside-br-color' : '';
// 判断是否是手机端
if (state.clientWidth <= 1000) {
if (isCollapse) {
document.body.setAttribute('class', 'el-popup-parent--hidden');
const asideEle = document.querySelector('.layout-container') as HTMLElement;
const modeDivs = document.createElement('div');
modeDivs.setAttribute('class', 'layout-aside-mobile-mode');
asideEle.appendChild(modeDivs);
modeDivs.addEventListener('click', closeLayoutAsideMobileMode);
return [asideBrColor, 'layout-aside-mobile', 'layout-aside-mobile-open'];
} else {
// 关闭弹窗
closeLayoutAsideMobileMode();
return [asideBrColor, 'layout-aside-mobile', 'layout-aside-mobile-close'];
}
} else {
if (layout === 'columns') {
// 分栏布局,菜单收起时宽度给 1px
if (isCollapse) return [asideBrColor, 'layout-aside-pc-1'];
else return [asideBrColor, 'layout-aside-pc-220'];
} else {
// 其它布局给 64px
if (isCollapse) return [asideBrColor, 'layout-aside-pc-64'];
else return [asideBrColor, 'layout-aside-pc-220'];
}
}
});
// 关闭移动端蒙版
const closeLayoutAsideMobileMode = () => {
const el = document.querySelector('.layout-aside-mobile-mode');
el?.setAttribute('style', 'animation: error-img-two 0.3s');
setTimeout(() => {
el?.parentNode?.removeChild(el);
}, 300);
const clientWidth = document.body.clientWidth;
if (clientWidth < 1000) themeConfig.value.isCollapse = false;
document.body.setAttribute('class', '');
};
// 设置显示/隐藏 logo
const setShowLogo = computed(() => {
let { layout, isShowLogo } = themeConfig.value;
return (isShowLogo && layout === 'defaults') || (isShowLogo && layout === 'columns');
});
// 设置/过滤路由(非静态路由/是否显示在菜单中)
const setFilterRoutes = () => {
if (themeConfig.value.layout === 'columns') return false;
(state.menuList as any) = filterRoutesFun(routesList.value);
};
// 路由过滤递归函数
const filterRoutesFun = (arr: Array<string>) => {
return arr
.filter((item: any) => !item.meta.isHide)
.map((item: any) => {
item = Object.assign({}, item);
if (item.children) item.children = filterRoutesFun(item.children);
return item;
});
};
// 设置菜单导航是否固定(移动端)
const initMenuFixed = (clientWidth: number) => {
state.clientWidth = clientWidth;
};
// 鼠标移入、移出
const onAsideEnterLeave = (bool: Boolean) => {
let { layout } = themeConfig.value;
if (layout !== 'columns') return false;
if (!bool) mittBus.emit('restoreDefault');
stores.setColumnsMenuHover(bool);
};
// 监听 themeConfig 配置文件的变化,更新菜单 el-scrollbar 的高度
watch(themeConfig.value, (val) => {
if (val.isShowLogoChange !== val.isShowLogo) {
if (layoutAsideScrollbarRef.value) layoutAsideScrollbarRef.value.update();
}
});
// 监听vuex值的变化动态赋值给菜单中
watch(
pinia.state,
(val) => {
let { layout, isClassicSplitMenu } = val.themeConfig.themeConfig;
if (layout === 'classic' && isClassicSplitMenu) return false;
setFilterRoutes();
},
{
deep: true,
}
);
// 页面加载前
onBeforeMount(() => {
initMenuFixed(document.body.clientWidth);
setFilterRoutes();
// 此界面不需要取消监听(mittBus.off('setSendColumnsChildren))
// 因为切换布局时有的监听需要使用,取消了监听,某些操作将不生效
mittBus.on('setSendColumnsChildren', (res: any) => {
state.menuList = res.children;
});
mittBus.on('setSendClassicChildren', (res: any) => {
let { layout, isClassicSplitMenu } = themeConfig.value;
if (layout === 'classic' && isClassicSplitMenu) {
state.menuList = [];
state.menuList = res.children;
}
});
mittBus.on('getBreadcrumbIndexSetFilterRoutes', () => {
setFilterRoutes();
});
mittBus.on('layoutMobileResize', (res: any) => {
initMenuFixed(res.clientWidth);
closeLayoutAsideMobileMode();
});
});
return {
layoutAsideScrollbarRef,
setCollapseStyle,
setShowLogo,
isTagsViewCurrenFull,
onAsideEnterLeave,
...toRefs(state),
};
},
});
</script>

View File

@ -1,296 +0,0 @@
<template>
<div class="layout-columns-aside">
<el-scrollbar>
<ul @mouseleave="onColumnsAsideMenuMouseleave()">
<li
v-for="(v, k) in columnsAsideList"
:key="k"
@click="onColumnsAsideMenuClick(v, k)"
@mouseenter="onColumnsAsideMenuMouseenter(v, k)"
:ref="
(el) => {
if (el) columnsAsideOffsetTopRefs[k] = el;
}
"
:class="{ 'layout-columns-active': liIndex === k, 'layout-columns-hover': liHoverIndex === k }"
:title="$t(v.meta.title)"
>
<div :class="themeConfig.columnsAsideLayout" v-if="!v.meta.isLink || (v.meta.isLink && v.meta.isIframe)">
<SvgIcon :name="v.meta.icon" />
<div class="columns-vertical-title font12">
{{
$t(v.meta.title) && $t(v.meta.title).length >= 4
? $t(v.meta.title).substr(0, themeConfig.columnsAsideLayout === 'columns-vertical' ? 4 : 3)
: $t(v.meta.title)
}}
</div>
</div>
<div :class="themeConfig.columnsAsideLayout" v-else>
<a :href="v.meta.isLink" target="_blank">
<SvgIcon :name="v.meta.icon" />
<div class="columns-vertical-title font12">
{{
$t(v.meta.title) && $t(v.meta.title).length >= 4
? $t(v.meta.title).substr(0, themeConfig.columnsAsideLayout === 'columns-vertical' ? 4 : 3)
: $t(v.meta.title)
}}
</div>
</a>
</div>
</li>
<div ref="columnsAsideActiveRef" :class="themeConfig.columnsAsideStyle"></div>
</ul>
</el-scrollbar>
</div>
</template>
<script lang="ts">
import { reactive, toRefs, ref, onMounted, nextTick, watch, onUnmounted, defineComponent } from 'vue';
import { useRoute, useRouter, onBeforeRouteUpdate, RouteRecordRaw } from 'vue-router';
import { storeToRefs } from 'pinia';
import pinia from '/@/stores/index';
import { useRoutesList } from '/@/stores/routesList';
import { useThemeConfig } from '/@/stores/themeConfig';
import mittBus from '/@/utils/mitt';
// 定义接口来定义对象的类型
interface ColumnsAsideState {
columnsAsideList: any[];
liIndex: number;
liOldIndex: null | number;
liHoverIndex: null | number;
liOldPath: null | string;
difference: number;
routeSplit: string[];
}
export default defineComponent({
name: 'layoutColumnsAside',
setup() {
const columnsAsideOffsetTopRefs: any = ref([]);
const columnsAsideActiveRef = ref();
const stores = useRoutesList();
const storesThemeConfig = useThemeConfig();
const { routesList, isColumnsMenuHover, isColumnsNavHover } = storeToRefs(stores);
const { themeConfig } = storeToRefs(storesThemeConfig);
const route = useRoute();
const router = useRouter();
const state = reactive<ColumnsAsideState>({
columnsAsideList: [],
liIndex: 0,
liOldIndex: null,
liHoverIndex: null,
liOldPath: null,
difference: 0,
routeSplit: [],
});
// 设置菜单高亮位置移动
const setColumnsAsideMove = (k: number) => {
state.liIndex = k;
columnsAsideActiveRef.value.style.top = `${columnsAsideOffsetTopRefs.value[k].offsetTop + state.difference}px`;
};
// 菜单高亮点击事件
const onColumnsAsideMenuClick = (v: Object, k: number) => {
setColumnsAsideMove(k);
let { path, redirect } = v as any;
if (redirect) router.push(redirect);
else router.push(path);
};
// 鼠标移入时,显示当前的子级菜单
const onColumnsAsideMenuMouseenter = (v: RouteRecordRaw, k: number) => {
if (!themeConfig.value.isColumnsMenuHoverPreload) return false;
let { path } = v;
state.liOldPath = path;
state.liOldIndex = k;
state.liHoverIndex = k;
mittBus.emit('setSendColumnsChildren', setSendChildren(path));
stores.setColumnsMenuHover(false);
stores.setColumnsNavHover(true);
};
// 鼠标移走时,显示原来的子级菜单
const onColumnsAsideMenuMouseleave = async () => {
await stores.setColumnsNavHover(false);
// 添加延时器,防止拿到的 store.state.routesList 值不是最新的
setTimeout(() => {
if (!isColumnsMenuHover && !isColumnsNavHover) mittBus.emit('restoreDefault');
}, 100);
};
// 设置高亮动态位置
const onColumnsAsideDown = (k: number) => {
nextTick(() => {
setColumnsAsideMove(k);
});
};
// 设置/过滤路由(非静态路由/是否显示在菜单中)
const setFilterRoutes = () => {
state.columnsAsideList = filterRoutesFun(routesList.value);
const resData: any = setSendChildren(route.path);
if (Object.keys(resData).length <= 0) return false;
onColumnsAsideDown(resData.item[0].k);
mittBus.emit('setSendColumnsChildren', resData);
};
// 传送当前子级数据到菜单中
const setSendChildren = (path: string) => {
const currentPathSplit = path.split('/');
let currentData: any = {};
state.columnsAsideList.map((v: any, k: number) => {
if (v.path === `/${currentPathSplit[1]}`) {
v['k'] = k;
currentData['item'] = [{ ...v }];
currentData['children'] = [{ ...v }];
if (v.children) currentData['children'] = v.children;
}
});
return currentData;
};
// 路由过滤递归函数
const filterRoutesFun = (arr: Array<string>) => {
return arr
.filter((item: any) => !item.meta.isHide)
.map((item: any) => {
item = Object.assign({}, item);
if (item.children) item.children = filterRoutesFun(item.children);
return item;
});
};
// tagsView 点击时,根据路由查找下标 columnsAsideList实现左侧菜单高亮
const setColumnsMenuHighlight = (path: string) => {
state.routeSplit = path.split('/');
state.routeSplit.shift();
const routeFirst = `/${state.routeSplit[0]}`;
const currentSplitRoute = state.columnsAsideList.find((v: any) => v.path === routeFirst);
if (!currentSplitRoute) return false;
// 延迟拿值,防止取不到
setTimeout(() => {
onColumnsAsideDown((<any>currentSplitRoute).k);
}, 0);
};
// 监听布局配置信息的变化,动态增加菜单高亮位置移动像素
watch(
pinia.state,
(val) => {
val.themeConfig.themeConfig.columnsAsideStyle === 'columnsRound' ? (state.difference = 3) : (state.difference = 0);
if (!val.routesList.isColumnsMenuHover && !val.routesList.isColumnsNavHover) {
state.liHoverIndex = null;
mittBus.emit('setSendColumnsChildren', setSendChildren(route.path));
} else {
state.liHoverIndex = state.liOldIndex;
if (!state.liOldPath) return false;
mittBus.emit('setSendColumnsChildren', setSendChildren(state.liOldPath));
}
},
{
deep: true,
}
);
// 页面加载时
onMounted(() => {
setFilterRoutes();
// 销毁变量,防止鼠标再次移入时,保留了上次的记录
mittBus.on('restoreDefault', () => {
state.liOldIndex = null;
state.liOldPath = null;
});
});
// 页面卸载时
onUnmounted(() => {
mittBus.off('restoreDefault', () => {});
});
// 路由更新时
onBeforeRouteUpdate((to) => {
setColumnsMenuHighlight(to.path);
mittBus.emit('setSendColumnsChildren', setSendChildren(to.path));
});
return {
themeConfig,
columnsAsideOffsetTopRefs,
columnsAsideActiveRef,
onColumnsAsideDown,
onColumnsAsideMenuClick,
onColumnsAsideMenuMouseenter,
onColumnsAsideMenuMouseleave,
...toRefs(state),
};
},
});
</script>
<style scoped lang="scss">
.layout-columns-aside {
width: 70px;
height: 100%;
background: var(--next-bg-columnsMenuBar);
ul {
position: relative;
.layout-columns-active {
color: var(--next-bg-columnsMenuBarColor) !important;
transition: 0.3s ease-in-out;
}
.layout-columns-hover {
color: var(--el-color-primary);
a {
color: var(--el-color-primary);
}
}
li {
color: var(--next-bg-columnsMenuBarColor);
width: 100%;
height: 50px;
text-align: center;
display: flex;
cursor: pointer;
position: relative;
z-index: 1;
&:hover {
@extend .layout-columns-hover;
}
.columns-vertical {
margin: auto;
.columns-vertical-title {
padding-top: 1px;
}
}
.columns-horizontal {
display: flex;
height: 50px;
width: 100%;
align-items: center;
padding: 0 5px;
i {
margin-right: 3px;
}
a {
display: flex;
.columns-horizontal-title {
padding-top: 1px;
}
}
}
a {
text-decoration: none;
color: var(--next-bg-columnsMenuBarColor);
}
}
.columns-round {
background: var(--el-color-primary);
color: var(--el-color-white);
position: absolute;
left: 50%;
top: 2px;
height: 44px;
width: 65px;
transform: translateX(-50%);
z-index: 0;
transition: 0.3s ease-in-out;
border-radius: 5px;
}
.columns-card {
@extend .columns-round;
top: 0;
height: 50px;
width: 100%;
border-radius: 0;
}
}
}
</style>

View File

@ -1,25 +0,0 @@
<template>
<el-header class="layout-header" v-show="!isTagsViewCurrenFull">
<NavBarsIndex />
</el-header>
</template>
<script lang="ts">
import { defineAsyncComponent, defineComponent } from 'vue';
import { storeToRefs } from 'pinia';
import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes';
export default defineComponent({
name: 'layoutHeader',
components: {
NavBarsIndex: defineAsyncComponent(() => import('/@/layout/navBars/index.vue')),
},
setup() {
const storesTagsViewRoutes = useTagsViewRoutes();
const { isTagsViewCurrenFull } = storeToRefs(storesTagsViewRoutes);
return {
isTagsViewCurrenFull,
};
},
});
</script>

View File

@ -1,59 +0,0 @@
<template>
<el-main class="layout-main" :style="isFixedHeader ? `height: calc(100% - ${setMainHeight})` : `minHeight: calc(100% - ${setMainHeight})`">
<el-scrollbar ref="layoutMainScrollbarRef" class="layout-main-scroll" wrap-class="layout-main-scroll" view-class="layout-main-scroll">
<LayoutParentView />
<LayoutFooter v-if="isFooter" />
</el-scrollbar>
<el-backtop target=".layout-backtop .el-scrollbar__wrap" />
</el-main>
</template>
<script lang="ts">
import { defineAsyncComponent, defineComponent, onMounted, computed, ref } from 'vue';
import { useRoute } from 'vue-router';
import { storeToRefs } from 'pinia';
import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes';
import { useThemeConfig } from '/@/stores/themeConfig';
import { NextLoading } from '/@/utils/loading';
export default defineComponent({
name: 'layoutMain',
components: {
LayoutParentView: defineAsyncComponent(() => import('/@/layout/routerView/parent.vue')),
LayoutFooter: defineAsyncComponent(() => import('/@/layout/footer/index.vue')),
},
setup() {
const layoutMainScrollbarRef = ref('');
const route = useRoute();
const storesTagsViewRoutes = useTagsViewRoutes();
const storesThemeConfig = useThemeConfig();
const { themeConfig } = storeToRefs(storesThemeConfig);
const { isTagsViewCurrenFull } = storeToRefs(storesTagsViewRoutes);
// 设置 footer 显示/隐藏
const isFooter = computed(() => {
return themeConfig.value.isFooter && !route.meta.isIframe;
});
// 设置 header 固定
const isFixedHeader = computed(() => {
return themeConfig.value.isFixedHeader;
});
// 设置主内容区的高度
const setMainHeight = computed(() => {
if (isTagsViewCurrenFull.value) return '0px';
const { isTagsview, layout } = themeConfig.value;
if (isTagsview && layout !== 'classic') return '85px';
else return '51px';
});
// 页面加载前
onMounted(() => {
NextLoading.done(600);
});
return {
layoutMainScrollbarRef,
isFooter,
isFixedHeader,
setMainHeight,
};
},
});
</script>

View File

@ -1,38 +0,0 @@
<!--
* @Author: '490912587@qq.com' '490912587@qq.com'
* @Date: 2022-11-17 09:19:20
* @LastEditors: '490912587@qq.com' '490912587@qq.com'
* @LastEditTime: 2022-11-22 13:43:03
* @FilePath: \frontend\src\layout\footer\index.vue
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
-->
<template>
<div class="layout-footer pb15">
<div class="layout-footer-warp">
<div>TsPlatformMade by 490912587@qq.com with </div>
<div class="mt5">甜蜜蜜版权所有</div>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
export default defineComponent({
name: 'layoutFooter',
});
</script>
<style scoped lang="scss">
.layout-footer {
width: 100%;
display: flex;
&-warp {
margin: auto;
color: var(--el-text-color-secondary);
text-align: center;
animation: error-num 0.3s ease;
}
}
</style>

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