mirror of
https://github.com/cool-team-official/cool-admin-midway.git
synced 2026-08-01 19:06:13 +00:00
清空
This commit is contained in:
parent
13698b70cd
commit
74432bdadd
@ -1,18 +0,0 @@
|
|||||||
logs/
|
|
||||||
npm-debug.log
|
|
||||||
yarn-error.log
|
|
||||||
node_modules/
|
|
||||||
package-lock.json
|
|
||||||
yarn.lock
|
|
||||||
coverage/
|
|
||||||
dist/
|
|
||||||
.idea/
|
|
||||||
run/
|
|
||||||
.DS_Store
|
|
||||||
*.sw*
|
|
||||||
*.un~
|
|
||||||
.tsbuildinfo
|
|
||||||
.tsbuildinfo.*
|
|
||||||
.audit
|
|
||||||
public/uploads/
|
|
||||||
cache/
|
|
||||||
@ -1,11 +0,0 @@
|
|||||||
# 🎨 editorconfig.org
|
|
||||||
|
|
||||||
root = true
|
|
||||||
|
|
||||||
[*]
|
|
||||||
charset = utf-8
|
|
||||||
end_of_line = lf
|
|
||||||
indent_style = space
|
|
||||||
indent_size = 2
|
|
||||||
trim_trailing_whitespace = true
|
|
||||||
insert_final_newline = true
|
|
||||||
@ -1,30 +0,0 @@
|
|||||||
{
|
|
||||||
"extends": "./node_modules/mwts/",
|
|
||||||
"ignorePatterns": [
|
|
||||||
"node_modules",
|
|
||||||
"dist",
|
|
||||||
"test",
|
|
||||||
"jest.config.js",
|
|
||||||
"typings",
|
|
||||||
"public/**/**",
|
|
||||||
"view/**/**",
|
|
||||||
"packages"
|
|
||||||
],
|
|
||||||
"env": {
|
|
||||||
"jest": true
|
|
||||||
},
|
|
||||||
"rules": {
|
|
||||||
"@typescript-eslint/explicit-module-boundary-types": "off",
|
|
||||||
"@typescript-eslint/no-unused-vars": "off",
|
|
||||||
"@typescript-eslint/ban-ts-comment": "off",
|
|
||||||
"node/no-extraneous-import": "off",
|
|
||||||
"no-empty": "off",
|
|
||||||
"node/no-extraneous-require": "off",
|
|
||||||
"node/no-unpublished-import": "off",
|
|
||||||
"eqeqeq": "off",
|
|
||||||
"node/no-unsupported-features/node-builtins": "off",
|
|
||||||
"@typescript-eslint/ban-types": "off",
|
|
||||||
"no-control-regex": "off",
|
|
||||||
"prefer-const": "off"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
4
.gitattributes
vendored
4
.gitattributes
vendored
@ -1,4 +0,0 @@
|
|||||||
*.js text eol=lf
|
|
||||||
*.json text eol=lf
|
|
||||||
*.ts text eol=lf
|
|
||||||
*.code-snippets text eol=lf
|
|
||||||
20
.gitignore
vendored
20
.gitignore
vendored
@ -1,20 +0,0 @@
|
|||||||
logs/
|
|
||||||
cache/
|
|
||||||
npm-debug.log
|
|
||||||
yarn-error.log
|
|
||||||
node_modules/
|
|
||||||
package-lock.json
|
|
||||||
yarn.lock
|
|
||||||
coverage/
|
|
||||||
dist/
|
|
||||||
.idea/
|
|
||||||
run/
|
|
||||||
.DS_Store
|
|
||||||
launch.json
|
|
||||||
*.sw*
|
|
||||||
*.un~
|
|
||||||
.tsbuildinfo
|
|
||||||
.tsbuildinfo.*
|
|
||||||
data/*
|
|
||||||
pnpm-lock.yaml
|
|
||||||
public/uploads/*
|
|
||||||
9
.hintrc
9
.hintrc
@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"extends": [
|
|
||||||
"development"
|
|
||||||
],
|
|
||||||
"hints": {
|
|
||||||
"typescript-config/consistent-casing": "off",
|
|
||||||
"typescript-config/strict": "off"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
...require('mwts/.prettierrc.json')
|
|
||||||
}
|
|
||||||
28
.vscode/config.code-snippets
vendored
28
.vscode/config.code-snippets
vendored
@ -1,28 +0,0 @@
|
|||||||
{
|
|
||||||
"config": {
|
|
||||||
"prefix": "config",
|
|
||||||
"body": [
|
|
||||||
"import { ModuleConfig } from '@cool-midway/core';",
|
|
||||||
"",
|
|
||||||
"/**",
|
|
||||||
" * 模块配置",
|
|
||||||
" */",
|
|
||||||
"export default () => {",
|
|
||||||
" return {",
|
|
||||||
" // 模块名称",
|
|
||||||
" name: 'xxx',",
|
|
||||||
" // 模块描述",
|
|
||||||
" description: 'xxx',",
|
|
||||||
" // 中间件,只对本模块有效",
|
|
||||||
" middlewares: [],",
|
|
||||||
" // 中间件,全局有效",
|
|
||||||
" globalMiddlewares: [],",
|
|
||||||
" // 模块加载顺序,默认为0,值越大越优先加载",
|
|
||||||
" order: 0,",
|
|
||||||
" } as ModuleConfig;",
|
|
||||||
"};",
|
|
||||||
""
|
|
||||||
],
|
|
||||||
"description": "cool-admin config代码片段"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
19
.vscode/controller.code-snippets
vendored
19
.vscode/controller.code-snippets
vendored
@ -1,19 +0,0 @@
|
|||||||
{
|
|
||||||
"controller": {
|
|
||||||
"prefix": "controller",
|
|
||||||
"body": [
|
|
||||||
"import { CoolController, BaseController } from '@cool-midway/core';",
|
|
||||||
"",
|
|
||||||
"/**",
|
|
||||||
" * 描述",
|
|
||||||
" */",
|
|
||||||
"@CoolController({",
|
|
||||||
" api: ['add', 'delete', 'update', 'info', 'list', 'page'],",
|
|
||||||
" entity: 实体,",
|
|
||||||
"})",
|
|
||||||
"export class XxxController extends BaseController {}",
|
|
||||||
""
|
|
||||||
],
|
|
||||||
"description": "cool-admin controller代码片段"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
20
.vscode/entity.code-snippets
vendored
20
.vscode/entity.code-snippets
vendored
@ -1,20 +0,0 @@
|
|||||||
{
|
|
||||||
"entity": {
|
|
||||||
"prefix": "entity",
|
|
||||||
"body": [
|
|
||||||
"import { BaseEntity } from '@cool-midway/core';",
|
|
||||||
"import { Column, Entity } from 'typeorm';",
|
|
||||||
"",
|
|
||||||
"/**",
|
|
||||||
" * 描述",
|
|
||||||
" */",
|
|
||||||
"@Entity('xxx_xxx_xxx')",
|
|
||||||
"export class XxxEntity extends BaseEntity {",
|
|
||||||
" @Column({ comment: '描述' })",
|
|
||||||
" xxx: string;",
|
|
||||||
"}",
|
|
||||||
""
|
|
||||||
],
|
|
||||||
"description": "cool-admin entity代码片段"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
21
.vscode/event.code-snippets
vendored
21
.vscode/event.code-snippets
vendored
@ -1,21 +0,0 @@
|
|||||||
{
|
|
||||||
"event": {
|
|
||||||
"prefix": "event",
|
|
||||||
"body": [
|
|
||||||
"import { CoolEvent, Event } from '@cool-midway/core';",
|
|
||||||
"",
|
|
||||||
"/**",
|
|
||||||
" * 接收事件",
|
|
||||||
" */",
|
|
||||||
"@CoolEvent()",
|
|
||||||
"export class xxxEvent {",
|
|
||||||
" @Event('updateUser')",
|
|
||||||
" async updateUser(msg, a) {",
|
|
||||||
" console.log('ImEvent', 'updateUser', msg, a);",
|
|
||||||
" }",
|
|
||||||
"}",
|
|
||||||
""
|
|
||||||
],
|
|
||||||
"description": "cool-admin event代码片段"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
29
.vscode/middleware.code-snippets
vendored
29
.vscode/middleware.code-snippets
vendored
@ -1,29 +0,0 @@
|
|||||||
{
|
|
||||||
"middleware": {
|
|
||||||
"prefix": "middleware",
|
|
||||||
"body": [
|
|
||||||
"import { Middleware } from '@midwayjs/decorator';",
|
|
||||||
"import { NextFunction, Context } from '@midwayjs/koa';",
|
|
||||||
"import { IMiddleware } from '@midwayjs/core';",
|
|
||||||
"",
|
|
||||||
"/**",
|
|
||||||
" * 描述",
|
|
||||||
" */",
|
|
||||||
"@Middleware()",
|
|
||||||
"export class XxxMiddleware implements IMiddleware<Context, NextFunction> {",
|
|
||||||
" resolve() {",
|
|
||||||
" return async (ctx: Context, next: NextFunction) => {",
|
|
||||||
" // 控制器前执行的逻辑",
|
|
||||||
" const startTime = Date.now();",
|
|
||||||
" // 执行下一个 Web 中间件,最后执行到控制器",
|
|
||||||
" await next();",
|
|
||||||
" // 控制器之后执行的逻辑",
|
|
||||||
" console.log(Date.now() - startTime);",
|
|
||||||
" };",
|
|
||||||
" }",
|
|
||||||
"}",
|
|
||||||
""
|
|
||||||
],
|
|
||||||
"description": "cool-admin middleware代码片段"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
21
.vscode/queue.code-snippets
vendored
21
.vscode/queue.code-snippets
vendored
@ -1,21 +0,0 @@
|
|||||||
{
|
|
||||||
"queue": {
|
|
||||||
"prefix": "queue",
|
|
||||||
"body": [
|
|
||||||
"import { BaseCoolQueue, CoolQueue } from '@cool-midway/task';",
|
|
||||||
"",
|
|
||||||
"/**",
|
|
||||||
" * 队列",
|
|
||||||
" */",
|
|
||||||
"@CoolQueue()",
|
|
||||||
"export abstract class xxxQueue extends BaseCoolQueue {",
|
|
||||||
" async data(job: any, done: any) {",
|
|
||||||
" console.log('收到的数据', job.data);",
|
|
||||||
" done();",
|
|
||||||
" }",
|
|
||||||
"}",
|
|
||||||
""
|
|
||||||
],
|
|
||||||
"description": "cool-admin service代码片段"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
33
.vscode/service.code-snippets
vendored
33
.vscode/service.code-snippets
vendored
@ -1,33 +0,0 @@
|
|||||||
{
|
|
||||||
"service": {
|
|
||||||
"prefix": "service",
|
|
||||||
"body": [
|
|
||||||
"import { Init, Provide } from '@midwayjs/decorator';",
|
|
||||||
"import { BaseService } from '@cool-midway/core';",
|
|
||||||
"import { InjectEntityModel } from '@midwayjs/typeorm';",
|
|
||||||
"import { Repository } from 'typeorm';",
|
|
||||||
"",
|
|
||||||
"/**",
|
|
||||||
" * 描述",
|
|
||||||
" */",
|
|
||||||
"@Provide()",
|
|
||||||
"export class XxxService extends BaseService {",
|
|
||||||
" @InjectEntityModel(实体)",
|
|
||||||
" xxxEntity: Repository<实体>;",
|
|
||||||
""
|
|
||||||
" @Init()"
|
|
||||||
" async init() {",
|
|
||||||
" await super.init();",
|
|
||||||
" this.setEntity(this.xxxEntity);",
|
|
||||||
" }",
|
|
||||||
"",
|
|
||||||
" /**",
|
|
||||||
" * 描述",
|
|
||||||
" */",
|
|
||||||
" async xxx() {}",
|
|
||||||
"}",
|
|
||||||
""
|
|
||||||
],
|
|
||||||
"description": "cool-admin service代码片段"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
33
Dockerfile
33
Dockerfile
@ -1,33 +0,0 @@
|
|||||||
|
|
||||||
FROM node:lts-alpine
|
|
||||||
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
# 配置alpine国内镜像加速
|
|
||||||
RUN sed -i "s@http://dl-cdn.alpinelinux.org/@https://repo.huaweicloud.com/@g" /etc/apk/repositories
|
|
||||||
|
|
||||||
# 安装tzdata,默认的alpine基础镜像不包含时区组件,安装后可通过TZ环境变量配置时区
|
|
||||||
RUN apk add --no-cache tzdata
|
|
||||||
|
|
||||||
# 设置时区为中国东八区,这里的配置可以被docker-compose.yml或docker run时指定的时区覆盖
|
|
||||||
ENV TZ="Asia/Shanghai"
|
|
||||||
|
|
||||||
# 如果各公司有自己的私有源,可以替换registry地址,如使用官方源注释下一行
|
|
||||||
RUN npm config set registry https://registry.npmmirror.com
|
|
||||||
|
|
||||||
# 复制package.json
|
|
||||||
COPY package.json ./package.json
|
|
||||||
# 安装依赖
|
|
||||||
RUN npm install
|
|
||||||
# 构建项目
|
|
||||||
COPY . .
|
|
||||||
RUN npm run build
|
|
||||||
# 删除开发期依赖
|
|
||||||
RUN rm -rf node_modules && rm package-lock.json
|
|
||||||
# 安装生产环境依赖
|
|
||||||
RUN npm install
|
|
||||||
|
|
||||||
# 如果端口更换,这边可以更新一下
|
|
||||||
EXPOSE 8001
|
|
||||||
|
|
||||||
CMD ["npm", "run", "start"]
|
|
||||||
21
LICENSE
21
LICENSE
@ -1,21 +0,0 @@
|
|||||||
MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2023 cool-team-official
|
|
||||||
|
|
||||||
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.
|
|
||||||
191
README.md
191
README.md
@ -1,191 +0,0 @@
|
|||||||
<p align="center">
|
|
||||||
<a href="https://midwayjs.org/" target="blank"><img src="https://cool-show.oss-cn-shanghai.aliyuncs.com/admin/logo.png" width="200" alt="Midway Logo" /></a>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p align="center">cool-admin(midway版)一个很酷的后台权限管理系统,开源免费,模块化、插件化、极速开发CRUD,方便快速构建迭代后台管理系统,支持serverless、docker、普通服务器等多种方式部署
|
|
||||||
到 <a href="https://cool-js.com" target="_blank">官网</a> 进一步了解。
|
|
||||||
<p align="center">
|
|
||||||
<a href="https://github.com/cool-team-official/cool-admin-midway/blob/master/LICENSE" target="_blank"><img src="https://img.shields.io/badge/license-MIT-green?style=flat-square" alt="GitHub license" />
|
|
||||||
<a href=""><img src="https://img.shields.io/github/package-json/v/cool-team-official/cool-admin-midway?style=flat-square" alt="GitHub tag"></a>
|
|
||||||
<img src="https://img.shields.io/github/last-commit/cool-team-official/cool-admin-midway?style=flat-square" alt="GitHub tag"></a>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
## 特性
|
|
||||||
|
|
||||||
Ai时代,很多老旧的框架已经无法满足现代化的开发需求,Cool-Admin开发了一系列的功能,让开发变得更简单、更快速、更高效。
|
|
||||||
|
|
||||||
- **Ai编码**:通过微调大模型学习框架特有写法,实现简单功能从Api接口到前端页面的一键生成
|
|
||||||
- **流程编排**:通过拖拽编排方式,即可实现类似像智能客服这样的功能
|
|
||||||
- **模块化**:代码是模块化的,清晰明了,方便维护
|
|
||||||
- **插件化**:插件化的设计,可以通过安装插件的方式扩展如:支付、短信、邮件等功能
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
## 技术栈
|
|
||||||
|
|
||||||
- 后端:**`node.js` `midway.js` `koa.js` `typescript`**
|
|
||||||
- 前端:**`vue.js` `element-plus` `jsx` `pinia` `vue-router`**
|
|
||||||
- 数据库:**`mysql` `postgresql` `sqlite`**
|
|
||||||
|
|
||||||
如果你是前端,后端的这些技术选型对你是特别友好的,前端开发者可以较快速地上手。
|
|
||||||
如果你是后端,Typescript 的语法又跟 java、php 等特别类似,一切看起来也是那么得熟悉。
|
|
||||||
|
|
||||||
如果你想使用 java 版本后端,请移步[cool-admin-java](https://cool-js.com/admin/java/introduce.html)
|
|
||||||
|
|
||||||
#### 官网
|
|
||||||
|
|
||||||
[https://cool-js.com](https://cool-js.com)
|
|
||||||
|
|
||||||
## 视频教程
|
|
||||||
|
|
||||||
[官方 B 站视频教程](https://www.bilibili.com/video/BV1j1421R7aB)
|
|
||||||
|
|
||||||
<!-- 在此次添加使用文档 -->
|
|
||||||
|
|
||||||
## 演示
|
|
||||||
|
|
||||||
[AI 极速编码](https://cool-js.com/ai/introduce.html)
|
|
||||||
|
|
||||||
[https://show.cool-admin.com](https://show.cool-admin.com)
|
|
||||||
|
|
||||||
- 账户:admin
|
|
||||||
- 密码:123456
|
|
||||||
|
|
||||||
<img src="https://cool-show.oss-cn-shanghai.aliyuncs.com/admin/home-mini.png" alt="Admin Home"></a>
|
|
||||||
|
|
||||||
#### 项目前端
|
|
||||||
|
|
||||||
[https://github.com/cool-team-official/cool-admin-vue](https://github.com/cool-team-official/cool-admin-vue)
|
|
||||||
|
|
||||||
或
|
|
||||||
|
|
||||||
[https://gitee.com/cool-team-official/cool-admin-vue](https://gitee.com/cool-team-official/cool-admin-vue)
|
|
||||||
|
|
||||||
或
|
|
||||||
|
|
||||||
[https://gitcode.com/cool_team/cool-admin-vue](https://gitcode.com/cool_team/cool-admin-vue)
|
|
||||||
|
|
||||||
## 微信群
|
|
||||||
|
|
||||||
<img width="260" src="https://cool-show.oss-cn-shanghai.aliyuncs.com/admin/wechat.jpeg?v=1" alt="Admin Wechat"></a>
|
|
||||||
|
|
||||||
## 运行
|
|
||||||
|
|
||||||
#### 修改数据库配置,配置文件位于`src/config/config.local.ts`
|
|
||||||
|
|
||||||
以 Mysql 为例,其他数据库请参考[数据库配置文档](https://cool-js.com/admin/node/quick.html#%E6%95%B0%E6%8D%AE%E5%BA%93%E9%85%8D%E7%BD%AE)
|
|
||||||
|
|
||||||
Mysql(`>=5.7版本`),建议 8.0,node 版本(`>=16.x`),建议 18.x,首次启动会自动初始化并导入数据
|
|
||||||
|
|
||||||
```ts
|
|
||||||
// mysql,驱动已经内置,无需安装
|
|
||||||
typeorm: {
|
|
||||||
dataSource: {
|
|
||||||
default: {
|
|
||||||
type: 'mysql',
|
|
||||||
host: '127.0.0.1',
|
|
||||||
port: 3306,
|
|
||||||
username: 'root',
|
|
||||||
password: '123456',
|
|
||||||
database: 'cool',
|
|
||||||
// 自动建表 注意:线上部署的时候不要使用,有可能导致数据丢失
|
|
||||||
synchronize: true,
|
|
||||||
// 打印日志
|
|
||||||
logging: false,
|
|
||||||
// 字符集
|
|
||||||
charset: 'utf8mb4',
|
|
||||||
// 是否开启缓存
|
|
||||||
cache: true,
|
|
||||||
// 实体路径
|
|
||||||
entities: ['**/modules/*/entity'],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 安装依赖并运行
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ npm i
|
|
||||||
$ npm run dev
|
|
||||||
$ open http://localhost:8001/
|
|
||||||
```
|
|
||||||
|
|
||||||
注: `npm i`如果安装失败可以尝试使用[cnpm](https://developer.aliyun.com/mirror/NPM?from=tnpm),或者切换您的镜像源,推荐使用[pnpm](https://pnpm.io/)
|
|
||||||
|
|
||||||
## CURD(快速增删改查)
|
|
||||||
|
|
||||||
大部分的后台管理系统,或者 API 服务都是对数据进行管理,所以可以看到大量的 CRUD 场景(增删改查),cool-admin 对此进行了大量地封装,让这块的编码量变得极其地少。
|
|
||||||
|
|
||||||
#### 新建一个数据表
|
|
||||||
|
|
||||||
`src/modules/demo/entity/goods.ts`,项目启动数据库会自动创建该表,无需手动创建
|
|
||||||
|
|
||||||
```ts
|
|
||||||
import { BaseEntity } from '@cool-midway/core';
|
|
||||||
import { Column, Entity, Index } from 'typeorm';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 商品
|
|
||||||
*/
|
|
||||||
@Entity('demo_app_goods')
|
|
||||||
export class DemoAppGoodsEntity extends BaseEntity {
|
|
||||||
@Column({ comment: '标题' })
|
|
||||||
title: string;
|
|
||||||
|
|
||||||
@Column({ comment: '图片' })
|
|
||||||
pic: string;
|
|
||||||
|
|
||||||
@Column({ comment: '价格', type: 'decimal', precision: 5, scale: 2 })
|
|
||||||
price: number;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 编写 api 接口
|
|
||||||
|
|
||||||
`src/modules/demo/controller/app/goods.ts`,快速编写 6 个 api 接口
|
|
||||||
|
|
||||||
```ts
|
|
||||||
import { CoolController, BaseController } from '@cool-midway/core';
|
|
||||||
import { DemoAppGoodsEntity } from '../../entity/goods';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 商品
|
|
||||||
*/
|
|
||||||
@CoolController({
|
|
||||||
api: ['add', 'delete', 'update', 'info', 'list', 'page'],
|
|
||||||
entity: DemoAppGoodsEntity,
|
|
||||||
})
|
|
||||||
export class DemoAppGoodsController extends BaseController {
|
|
||||||
/**
|
|
||||||
* 其他接口
|
|
||||||
*/
|
|
||||||
@Get('/other')
|
|
||||||
async other() {
|
|
||||||
return this.ok('hello, cool-admin!!!');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
这样我们就完成了 6 个接口的编写,对应的接口如下:
|
|
||||||
|
|
||||||
- `POST /app/demo/goods/add` 新增
|
|
||||||
- `POST /app/demo/goods/delete` 删除
|
|
||||||
- `POST /app/demo/goods/update` 更新
|
|
||||||
- `GET /app/demo/goods/info` 单个信息
|
|
||||||
- `POST /app/demo/goods/list` 列表信息
|
|
||||||
- `POST /app/demo/goods/page` 分页查询(包含模糊查询、字段全匹配等)
|
|
||||||
|
|
||||||
### 部署
|
|
||||||
|
|
||||||
[部署教程](https://cool-js.com/admin/deploy.html)
|
|
||||||
|
|
||||||
### 内置指令
|
|
||||||
|
|
||||||
- 使用 `npm run lint` 来做代码风格检查。
|
|
||||||
|
|
||||||
[midway]: https://midwayjs.org
|
|
||||||
|
|
||||||
### 低价服务器
|
|
||||||
|
|
||||||
[阿里云、腾讯云、华为云低价云服务器,不限新老](https://cool-js.com/service/cloud)
|
|
||||||
2
bootstrap.js
vendored
2
bootstrap.js
vendored
@ -1,2 +0,0 @@
|
|||||||
const { Bootstrap } = require('@midwayjs/bootstrap');
|
|
||||||
Bootstrap.run();
|
|
||||||
@ -1,70 +0,0 @@
|
|||||||
const fs = require('fs');
|
|
||||||
const path = require('path');
|
|
||||||
const JavaScriptObfuscator = require('javascript-obfuscator');
|
|
||||||
|
|
||||||
// 混淆配置
|
|
||||||
const obfuscatorOptions = {
|
|
||||||
compact: true,
|
|
||||||
controlFlowFlattening: true,
|
|
||||||
controlFlowFlatteningThreshold: 0.7,
|
|
||||||
deadCodeInjection: true,
|
|
||||||
deadCodeInjectionThreshold: 0.4,
|
|
||||||
debugProtection: false,
|
|
||||||
debugProtectionInterval: 0,
|
|
||||||
disableConsoleOutput: true,
|
|
||||||
identifierNamesGenerator: 'hexadecimal',
|
|
||||||
log: false,
|
|
||||||
numbersToExpressions: true,
|
|
||||||
renameGlobals: false,
|
|
||||||
rotateStringArray: true,
|
|
||||||
selfDefending: true,
|
|
||||||
shuffleStringArray: true,
|
|
||||||
splitStrings: true,
|
|
||||||
splitStringsChunkLength: 10,
|
|
||||||
stringArray: true,
|
|
||||||
stringArrayEncoding: ['base64'],
|
|
||||||
stringArrayThreshold: 0.75,
|
|
||||||
transformObjectKeys: true,
|
|
||||||
unicodeEscapeSequence: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
// 处理单个文件的函数
|
|
||||||
function obfuscateFile(filePath) {
|
|
||||||
try {
|
|
||||||
const code = fs.readFileSync(filePath, 'utf8');
|
|
||||||
const obfuscationResult = JavaScriptObfuscator.obfuscate(
|
|
||||||
code,
|
|
||||||
obfuscatorOptions
|
|
||||||
);
|
|
||||||
fs.writeFileSync(filePath, obfuscationResult.getObfuscatedCode());
|
|
||||||
console.log(`成功混淆文件: ${filePath}`);
|
|
||||||
} catch (error) {
|
|
||||||
console.error(`处理文件 ${filePath} 时出错:`, error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 递归处理目录的函数
|
|
||||||
function processDirectory(directory) {
|
|
||||||
const files = fs.readdirSync(directory);
|
|
||||||
|
|
||||||
files.forEach(file => {
|
|
||||||
const fullPath = path.join(directory, file);
|
|
||||||
const stat = fs.statSync(fullPath);
|
|
||||||
|
|
||||||
if (stat.isDirectory()) {
|
|
||||||
processDirectory(fullPath);
|
|
||||||
} else if (path.extname(file) === '.js') {
|
|
||||||
obfuscateFile(fullPath);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 开始处理
|
|
||||||
const distPath = path.join(process.cwd(), 'dist');
|
|
||||||
if (fs.existsSync(distPath)) {
|
|
||||||
console.log('开始混淆 dist 目录下的 JS 文件...');
|
|
||||||
processDirectory(distPath);
|
|
||||||
console.log('混淆完成!');
|
|
||||||
} else {
|
|
||||||
console.error('错误: dist 目录不存在!');
|
|
||||||
}
|
|
||||||
@ -1,40 +0,0 @@
|
|||||||
# 本地数据库环境
|
|
||||||
# 数据存放在当前目录下的 data里
|
|
||||||
# 推荐使用安装了docker扩展的vscode打开目录 在本文件上右键可以快速启动,停止
|
|
||||||
# 如不需要相关容器开机自启动,可注释掉 restart: always
|
|
||||||
# 如遇端口冲突 可调整ports下 :前面的端口号
|
|
||||||
version: "3.1"
|
|
||||||
|
|
||||||
services:
|
|
||||||
coolDB:
|
|
||||||
image: mysql
|
|
||||||
command:
|
|
||||||
--default-authentication-plugin=mysql_native_password
|
|
||||||
--sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION
|
|
||||||
--group_concat_max_len=102400
|
|
||||||
restart: always
|
|
||||||
volumes:
|
|
||||||
- ./data/mysql/:/var/lib/mysql/
|
|
||||||
environment:
|
|
||||||
TZ: Asia/Shanghai # 指定时区
|
|
||||||
MYSQL_ROOT_PASSWORD: "123456" # 配置root用户密码
|
|
||||||
MYSQL_DATABASE: "cool" # 业务库名
|
|
||||||
MYSQL_USER: "root" # 业务库用户名
|
|
||||||
MYSQL_PASSWORD: "123456" # 业务库密码
|
|
||||||
networks:
|
|
||||||
- cool
|
|
||||||
ports:
|
|
||||||
- 3306:3306
|
|
||||||
|
|
||||||
coolRedis:
|
|
||||||
image: redis
|
|
||||||
#command: --requirepass "12345678" # redis库密码,不需要密码注释本行
|
|
||||||
restart: always
|
|
||||||
environment:
|
|
||||||
TZ: Asia/Shanghai # 指定时区
|
|
||||||
volumes:
|
|
||||||
- ./data/redis/:/data/
|
|
||||||
networks:
|
|
||||||
- cool
|
|
||||||
ports:
|
|
||||||
- 6379:6379
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
preset: 'ts-jest',
|
|
||||||
testEnvironment: 'node',
|
|
||||||
testPathIgnorePatterns: ['<rootDir>/test/fixtures'],
|
|
||||||
coveragePathIgnorePatterns: ['<rootDir>/test/'],
|
|
||||||
};
|
|
||||||
80
package.json
80
package.json
@ -1,80 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "cool-admin",
|
|
||||||
"version": "7.1.2",
|
|
||||||
"description": "一个项目用COOL就够了",
|
|
||||||
"private": true,
|
|
||||||
"dependencies": {
|
|
||||||
"@cool-midway/core": "^7.1.25",
|
|
||||||
"@cool-midway/rpc": "^7.0.0",
|
|
||||||
"@cool-midway/task": "^7.0.0",
|
|
||||||
"@midwayjs/bootstrap": "^3.16.0",
|
|
||||||
"@midwayjs/cache-manager": "^3.16.0",
|
|
||||||
"@midwayjs/core": "^3.16.0",
|
|
||||||
"@midwayjs/cron": "^3.16.0",
|
|
||||||
"@midwayjs/cross-domain": "^3.16.1",
|
|
||||||
"@midwayjs/decorator": "^3.16.0",
|
|
||||||
"@midwayjs/info": "^3.16.1",
|
|
||||||
"@midwayjs/koa": "^3.16.1",
|
|
||||||
"@midwayjs/logger": "^3.4.0",
|
|
||||||
"@midwayjs/static-file": "^3.16.1",
|
|
||||||
"@midwayjs/typeorm": "^3.16.0",
|
|
||||||
"@midwayjs/upload": "^3.16.1",
|
|
||||||
"@midwayjs/validate": "^3.16.1",
|
|
||||||
"@midwayjs/view-ejs": "^3.16.1",
|
|
||||||
"axios": "^1.6.8",
|
|
||||||
"cache-manager-ioredis-yet": "^2.0.4",
|
|
||||||
"decompress": "^4.2.1",
|
|
||||||
"download": "^8.0.0",
|
|
||||||
"ipip-ipdb": "^0.6.0",
|
|
||||||
"jsonwebtoken": "^9.0.2",
|
|
||||||
"lodash": "^4.17.21",
|
|
||||||
"md5": "^2.3.0",
|
|
||||||
"mini-svg-data-uri": "^1.4.4",
|
|
||||||
"moment": "^2.30.1",
|
|
||||||
"mysql2": "^3.9.7",
|
|
||||||
"svg-captcha": "^1.4.0",
|
|
||||||
"svg2png-wasm": "^1.4.1",
|
|
||||||
"typeorm": "^0.3.20",
|
|
||||||
"uuid": "^9.0.1",
|
|
||||||
"ws": "^8.17.0"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@midwayjs/mock": "^3.16.0",
|
|
||||||
"@types/jest": "^29.5.12",
|
|
||||||
"@types/koa": "^2.15.0",
|
|
||||||
"@types/node": "20",
|
|
||||||
"cross-env": "^7.0.3",
|
|
||||||
"javascript-obfuscator": "^4.1.1",
|
|
||||||
"jest": "^29.7.0",
|
|
||||||
"mwts": "^1.3.0",
|
|
||||||
"mwtsc": "^1.10.1",
|
|
||||||
"prettier": "^3.2.5",
|
|
||||||
"ts-jest": "^29.1.2",
|
|
||||||
"typescript": "~5.4.5"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12.0.0"
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"start": "NODE_ENV=production node ./bootstrap.js",
|
|
||||||
"dev": "cross-env NODE_ENV=local mwtsc --watch --run @midwayjs/mock/app.js --keepalive",
|
|
||||||
"cov": "jest --coverage",
|
|
||||||
"lint": "mwts check",
|
|
||||||
"lint:fix": "mwts fix",
|
|
||||||
"ci": "npm run cov",
|
|
||||||
"build": "mwtsc --cleanOutDir",
|
|
||||||
"build:obfuscate": "mwtsc --cleanOutDir && node cool/obfuscate.js",
|
|
||||||
"pm2:start": "pm2 start ./bootstrap.js -i max --name cool-admin",
|
|
||||||
"pm2:stop": "pm2 stop cool-admin & pm2 delete cool-admin"
|
|
||||||
},
|
|
||||||
"midway-bin-clean": [
|
|
||||||
".vscode/.tsbuildinfo",
|
|
||||||
"dist"
|
|
||||||
],
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://cool-js.com"
|
|
||||||
},
|
|
||||||
"author": "COOL",
|
|
||||||
"license": "MIT"
|
|
||||||
}
|
|
||||||
@ -1,89 +0,0 @@
|
|||||||
body {
|
|
||||||
display: flex;
|
|
||||||
height: 100vh;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
text-align: center;
|
|
||||||
background: #222;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes fadeIn {
|
|
||||||
from {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
to {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.footer-bar {
|
|
||||||
position: fixed;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
color: #6ee1f5;
|
|
||||||
padding: 10px 0 20px 0;
|
|
||||||
text-align: center;
|
|
||||||
opacity: 0; /* 开始时隐藏 */
|
|
||||||
animation: fadeIn 5s forwards; /* 应用动画 */
|
|
||||||
}
|
|
||||||
|
|
||||||
.link {
|
|
||||||
color: #6ee1f5;
|
|
||||||
}
|
|
||||||
|
|
||||||
.reveal {
|
|
||||||
position: relative;
|
|
||||||
display: flex;
|
|
||||||
color: #6ee1f5;
|
|
||||||
font-size: 2em;
|
|
||||||
font-family: Raleway, sans-serif;
|
|
||||||
letter-spacing: 3px;
|
|
||||||
text-transform: uppercase;
|
|
||||||
white-space: pre;
|
|
||||||
}
|
|
||||||
.reveal span {
|
|
||||||
opacity: 0;
|
|
||||||
transform: scale(0);
|
|
||||||
animation: fadeIn 2.4s forwards;
|
|
||||||
}
|
|
||||||
.reveal::before, .reveal::after {
|
|
||||||
position: absolute;
|
|
||||||
content: "";
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
width: 2px;
|
|
||||||
height: 100%;
|
|
||||||
background: white;
|
|
||||||
opacity: 0;
|
|
||||||
transform: scale(0);
|
|
||||||
}
|
|
||||||
.reveal::before {
|
|
||||||
left: 50%;
|
|
||||||
animation: slideLeft 1.5s cubic-bezier(0.7, -0.6, 0.3, 1.5) forwards;
|
|
||||||
}
|
|
||||||
.reveal::after {
|
|
||||||
right: 50%;
|
|
||||||
animation: slideRight 1.5s cubic-bezier(0.7, -0.6, 0.3, 1.5) forwards;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes fadeIn {
|
|
||||||
to {
|
|
||||||
opacity: 1;
|
|
||||||
transform: scale(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@keyframes slideLeft {
|
|
||||||
to {
|
|
||||||
left: -6%;
|
|
||||||
opacity: 1;
|
|
||||||
transform: scale(0.9);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@keyframes slideRight {
|
|
||||||
to {
|
|
||||||
right: -6%;
|
|
||||||
opacity: 1;
|
|
||||||
transform: scale(0.9);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 5.7 KiB |
@ -1,14 +0,0 @@
|
|||||||
const duration = 0.8;
|
|
||||||
const delay = 0.3;
|
|
||||||
// eslint-disable-next-line no-undef
|
|
||||||
const revealText = document.querySelector('.reveal');
|
|
||||||
const letters = revealText.textContent.split('');
|
|
||||||
revealText.textContent = '';
|
|
||||||
const middle = letters.filter(e => e !== ' ').length / 2;
|
|
||||||
letters.forEach((letter, i) => {
|
|
||||||
// eslint-disable-next-line no-undef
|
|
||||||
const span = document.createElement('span');
|
|
||||||
span.textContent = letter;
|
|
||||||
span.style.animationDelay = `${delay + Math.abs(i - middle) * 0.1}s`;
|
|
||||||
revealText.append(span);
|
|
||||||
});
|
|
||||||
@ -1 +0,0 @@
|
|||||||
文件上传目录
|
|
||||||
@ -1,138 +0,0 @@
|
|||||||
import { Inject, Provide } from '@midwayjs/decorator';
|
|
||||||
import { Context } from '@midwayjs/koa';
|
|
||||||
import * as ipdb from 'ipip-ipdb';
|
|
||||||
import * as _ from 'lodash';
|
|
||||||
import * as moment from 'moment';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 帮助类
|
|
||||||
*/
|
|
||||||
@Provide()
|
|
||||||
export class Utils {
|
|
||||||
@Inject()
|
|
||||||
baseDir;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获得请求IP
|
|
||||||
*/
|
|
||||||
async getReqIP(ctx: Context) {
|
|
||||||
const req = ctx.req;
|
|
||||||
return (
|
|
||||||
req.headers['x-forwarded-for'] ||
|
|
||||||
req.socket.remoteAddress.replace('::ffff:', '')
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 去除对象的空值属性
|
|
||||||
* @param obj
|
|
||||||
*/
|
|
||||||
async removeEmptyP(obj) {
|
|
||||||
Object.keys(obj).forEach(key => {
|
|
||||||
if (obj[key] === null || obj[key] === '' || obj[key] === 'undefined') {
|
|
||||||
delete obj[key];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 线程阻塞毫秒数
|
|
||||||
* @param ms
|
|
||||||
*/
|
|
||||||
sleep(ms) {
|
|
||||||
return new Promise(resolve => setTimeout(resolve, ms));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获得最近几天的日期集合
|
|
||||||
* @param recently
|
|
||||||
*/
|
|
||||||
getRecentlyDates(recently, format = 'YYYY-MM-DD') {
|
|
||||||
moment.locale('zh-cn');
|
|
||||||
const dates = [];
|
|
||||||
for (let i = 0; i < recently; i++) {
|
|
||||||
dates.push(moment().subtract(i, 'days').format(format));
|
|
||||||
}
|
|
||||||
return dates.reverse();
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* 获得最近几个月的月数
|
|
||||||
* @param recently
|
|
||||||
*/
|
|
||||||
getRecentlyMonths(recently, format = 'YYYY-MM') {
|
|
||||||
moment.locale('zh-cn');
|
|
||||||
const dates = [];
|
|
||||||
const date = moment(Date.now()).format('YYYY-MM');
|
|
||||||
for (let i = 0; i < recently; i++) {
|
|
||||||
dates.push(moment(date).subtract(i, 'months').format(format));
|
|
||||||
}
|
|
||||||
return dates.reverse();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据开始和结束时间,获得时间段内的日期集合
|
|
||||||
* @param start
|
|
||||||
* @param end
|
|
||||||
*/
|
|
||||||
getBetweenDays(start, end, format = 'YYYY-MM-DD') {
|
|
||||||
moment.locale('zh-cn');
|
|
||||||
const dates = [];
|
|
||||||
const startTime = moment(start).format(format);
|
|
||||||
const endTime = moment(end).format(format);
|
|
||||||
const days = moment(endTime).diff(moment(startTime), 'days');
|
|
||||||
for (let i = 0; i <= days; i++) {
|
|
||||||
dates.push(moment(startTime).add(i, 'days').format(format));
|
|
||||||
}
|
|
||||||
return dates;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据开始和结束时间,获得时间段内的月份集合
|
|
||||||
* @param start
|
|
||||||
* @param end
|
|
||||||
*/
|
|
||||||
getBetweenMonths(start, end, format = 'YYYY-MM') {
|
|
||||||
moment.locale('zh-cn');
|
|
||||||
const dates = [];
|
|
||||||
const startTime = moment(start).format(format);
|
|
||||||
const endTime = moment(end).format(format);
|
|
||||||
const months = moment(endTime).diff(moment(startTime), 'months');
|
|
||||||
for (let i = 0; i <= months; i++) {
|
|
||||||
dates.push(moment(startTime).add(i, 'months').format(format));
|
|
||||||
}
|
|
||||||
return dates;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据开始和结束时间,获得时间段内的小时集合
|
|
||||||
* @param start
|
|
||||||
* @param end
|
|
||||||
*/
|
|
||||||
getBetweenHours(start, end, format = 'YYYY-MM-DD HH') {
|
|
||||||
moment.locale('zh-cn');
|
|
||||||
const dates = [];
|
|
||||||
const startTime = moment(start).format(format);
|
|
||||||
const endTime = moment(end).format(format);
|
|
||||||
const hours = moment(endTime).diff(moment(startTime), 'hours');
|
|
||||||
for (let i = 0; i <= hours; i++) {
|
|
||||||
dates.push(moment(startTime).add(i, 'hours').format(format));
|
|
||||||
}
|
|
||||||
return dates;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 字段转驼峰法
|
|
||||||
* @param obj
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
toCamelCase(obj) {
|
|
||||||
let camelCaseObject = {};
|
|
||||||
for (let i in obj) {
|
|
||||||
let camelCase = i.replace(/([-_][a-z])/gi, $1 => {
|
|
||||||
return $1.toUpperCase().replace('-', '').replace('_', '');
|
|
||||||
});
|
|
||||||
camelCaseObject[camelCase] = obj[i];
|
|
||||||
}
|
|
||||||
return camelCaseObject;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,66 +0,0 @@
|
|||||||
import { CoolConfig } from '@cool-midway/core';
|
|
||||||
import { MidwayConfig } from '@midwayjs/core';
|
|
||||||
import { CoolCacheStore } from '@cool-midway/core';
|
|
||||||
|
|
||||||
// redis缓存
|
|
||||||
// import { redisStore } from 'cache-manager-ioredis-yet';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
// use for cookie sign key, should change to your own and keep security
|
|
||||||
keys: 'cool-admin-keys-xxxxxx',
|
|
||||||
koa: {
|
|
||||||
port: 8001,
|
|
||||||
},
|
|
||||||
// 模板渲染
|
|
||||||
view: {
|
|
||||||
mapping: {
|
|
||||||
'.html': 'ejs',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// 静态文件配置
|
|
||||||
staticFile: {
|
|
||||||
buffer: true,
|
|
||||||
},
|
|
||||||
// 文件上传
|
|
||||||
upload: {
|
|
||||||
fileSize: '200mb',
|
|
||||||
whitelist: null,
|
|
||||||
},
|
|
||||||
// 缓存 可切换成其他缓存如:redis http://www.midwayjs.org/docs/extensions/caching
|
|
||||||
cacheManager: {
|
|
||||||
clients: {
|
|
||||||
default: {
|
|
||||||
store: CoolCacheStore,
|
|
||||||
options: {
|
|
||||||
path: 'cache',
|
|
||||||
ttl: 0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// cacheManager: {
|
|
||||||
// clients: {
|
|
||||||
// default: {
|
|
||||||
// store: redisStore,
|
|
||||||
// options: {
|
|
||||||
// port: 6379,
|
|
||||||
// host: '127.0.0.1',
|
|
||||||
// password: '',
|
|
||||||
// ttl: 0,
|
|
||||||
// db: 0,
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
cool: {
|
|
||||||
// 已经插件化,本地文件上传查看 plugin/config.ts,其他云存储查看对应插件的使用
|
|
||||||
file: {},
|
|
||||||
// crud配置
|
|
||||||
crud: {
|
|
||||||
// 插入模式,save不会校验字段(允许传入不存在的字段),insert会校验字段
|
|
||||||
upsert: 'save',
|
|
||||||
// 软删除
|
|
||||||
softDelete: true,
|
|
||||||
},
|
|
||||||
} as CoolConfig,
|
|
||||||
} as MidwayConfig;
|
|
||||||
@ -1,40 +0,0 @@
|
|||||||
import { CoolConfig } from '@cool-midway/core';
|
|
||||||
import { MidwayConfig } from '@midwayjs/core';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 本地开发 npm run dev 读取的配置文件
|
|
||||||
*/
|
|
||||||
export default {
|
|
||||||
typeorm: {
|
|
||||||
dataSource: {
|
|
||||||
default: {
|
|
||||||
type: 'mysql',
|
|
||||||
host: '127.0.0.1',
|
|
||||||
port: 3306,
|
|
||||||
username: 'root',
|
|
||||||
password: '123456',
|
|
||||||
database: 'cool',
|
|
||||||
// 自动建表 注意:线上部署的时候不要使用,有可能导致数据丢失
|
|
||||||
synchronize: true,
|
|
||||||
// 打印日志
|
|
||||||
logging: false,
|
|
||||||
// 字符集
|
|
||||||
charset: 'utf8mb4',
|
|
||||||
// 是否开启缓存
|
|
||||||
cache: true,
|
|
||||||
// 实体路径
|
|
||||||
entities: ['**/modules/*/entity'],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
cool: {
|
|
||||||
// 实体与路径,跟生成代码、前端请求、swagger文档相关 注意:线上不建议开启,以免暴露敏感信息
|
|
||||||
eps: true,
|
|
||||||
// 是否自动导入模块数据库
|
|
||||||
initDB: true,
|
|
||||||
// 判断是否初始化的方式
|
|
||||||
initJudge: 'db',
|
|
||||||
// 是否自动导入模块菜单
|
|
||||||
initMenu: true,
|
|
||||||
} as CoolConfig,
|
|
||||||
} as MidwayConfig;
|
|
||||||
@ -1,34 +0,0 @@
|
|||||||
import { CoolConfig } from '@cool-midway/core';
|
|
||||||
import { MidwayConfig } from '@midwayjs/core';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 本地开发 npm run prod 读取的配置文件
|
|
||||||
*/
|
|
||||||
export default {
|
|
||||||
typeorm: {
|
|
||||||
dataSource: {
|
|
||||||
default: {
|
|
||||||
type: 'mysql',
|
|
||||||
host: '127.0.0.1',
|
|
||||||
port: 3306,
|
|
||||||
username: 'root',
|
|
||||||
password: '123456',
|
|
||||||
database: 'cool',
|
|
||||||
// 自动建表 注意:线上部署的时候不要使用,有可能导致数据丢失
|
|
||||||
synchronize: false,
|
|
||||||
// 打印日志
|
|
||||||
logging: false,
|
|
||||||
// 字符集
|
|
||||||
charset: 'utf8mb4',
|
|
||||||
// 是否开启缓存
|
|
||||||
cache: true,
|
|
||||||
// 实体路径
|
|
||||||
entities: ['**/modules/*/entity'],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
cool: {
|
|
||||||
// 是否自动导入数据库,生产环境不建议开,用本地的数据库手动初始化
|
|
||||||
initDB: false,
|
|
||||||
} as CoolConfig,
|
|
||||||
} as MidwayConfig;
|
|
||||||
@ -1,60 +0,0 @@
|
|||||||
import * as orm from '@midwayjs/typeorm';
|
|
||||||
import { Configuration, App, Inject } from '@midwayjs/decorator';
|
|
||||||
import * as koa from '@midwayjs/koa';
|
|
||||||
import * as validate from '@midwayjs/validate';
|
|
||||||
import * as info from '@midwayjs/info';
|
|
||||||
import { join } from 'path';
|
|
||||||
import * as view from '@midwayjs/view-ejs';
|
|
||||||
import * as staticFile from '@midwayjs/static-file';
|
|
||||||
import * as cron from '@midwayjs/cron';
|
|
||||||
// import * as crossDomain from '@midwayjs/cross-domain';
|
|
||||||
import * as cool from '@cool-midway/core';
|
|
||||||
import { ILogger } from '@midwayjs/logger';
|
|
||||||
import * as upload from '@midwayjs/upload';
|
|
||||||
import { IMidwayApplication } from '@midwayjs/core';
|
|
||||||
// import * as swagger from '@midwayjs/swagger';
|
|
||||||
// import * as rpc from '@cool-midway/rpc';
|
|
||||||
// import * as task from '@cool-midway/task';
|
|
||||||
|
|
||||||
@Configuration({
|
|
||||||
imports: [
|
|
||||||
// https://koajs.com/
|
|
||||||
koa,
|
|
||||||
// 是否开启跨域(注:顺序不能乱放!!!) http://www.midwayjs.org/docs/extensions/cross_domain
|
|
||||||
// crossDomain,
|
|
||||||
// 模板渲染 https://midwayjs.org/docs/extensions/render
|
|
||||||
view,
|
|
||||||
// 静态文件托管 https://midwayjs.org/docs/extensions/static_file
|
|
||||||
staticFile,
|
|
||||||
// orm https://midwayjs.org/docs/extensions/orm
|
|
||||||
orm,
|
|
||||||
// 参数验证 https://midwayjs.org/docs/extensions/validate
|
|
||||||
validate,
|
|
||||||
// 本地任务 http://www.midwayjs.org/docs/extensions/cron
|
|
||||||
cron,
|
|
||||||
// 文件上传
|
|
||||||
upload,
|
|
||||||
// cool-admin 官方组件 https://cool-js.com
|
|
||||||
cool,
|
|
||||||
// rpc 微服务 远程调用
|
|
||||||
// rpc,
|
|
||||||
// 任务与队列
|
|
||||||
// task,
|
|
||||||
// swagger 文档 http://www.midwayjs.org/docs/extensions/swagger
|
|
||||||
// swagger,
|
|
||||||
{
|
|
||||||
component: info,
|
|
||||||
enabledEnvironment: ['local'],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
importConfigs: [join(__dirname, './config')],
|
|
||||||
})
|
|
||||||
export class ContainerLifeCycle {
|
|
||||||
@App()
|
|
||||||
app: IMidwayApplication;
|
|
||||||
|
|
||||||
@Inject()
|
|
||||||
logger: ILogger;
|
|
||||||
|
|
||||||
async onReady() {}
|
|
||||||
}
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
/**
|
|
||||||
* @description User-Service parameters
|
|
||||||
*/
|
|
||||||
export interface IUserOptions {
|
|
||||||
uid: number;
|
|
||||||
}
|
|
||||||
@ -1,35 +0,0 @@
|
|||||||
import { BaseLogMiddleware } from './middleware/log';
|
|
||||||
import { BaseAuthorityMiddleware } from './middleware/authority';
|
|
||||||
import { ModuleConfig } from '@cool-midway/core';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 模块的配置
|
|
||||||
*/
|
|
||||||
export default () => {
|
|
||||||
return {
|
|
||||||
// 模块名称
|
|
||||||
name: '权限管理',
|
|
||||||
// 模块描述
|
|
||||||
description: '基础的权限管理功能,包括登录,权限校验',
|
|
||||||
// 中间件
|
|
||||||
globalMiddlewares: [BaseAuthorityMiddleware, BaseLogMiddleware],
|
|
||||||
// 模块加载顺序,默认为0,值越大越优先加载
|
|
||||||
order: 10,
|
|
||||||
// app参数配置允许读取的key
|
|
||||||
allowKeys: [],
|
|
||||||
// jwt 生成解密token的
|
|
||||||
jwt: {
|
|
||||||
// 单点登录
|
|
||||||
sso: false,
|
|
||||||
// 注意: 最好重新修改,防止破解
|
|
||||||
secret: 'cool-admin-xxxxxx',
|
|
||||||
// token
|
|
||||||
token: {
|
|
||||||
// 2小时过期,需要用刷新token
|
|
||||||
expire: 2 * 3600,
|
|
||||||
// 15天内,如果没操作过就需要重新登录
|
|
||||||
refreshExpire: 24 * 3600 * 15,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} as ModuleConfig;
|
|
||||||
};
|
|
||||||
@ -1,99 +0,0 @@
|
|||||||
import {
|
|
||||||
BaseController,
|
|
||||||
CoolController,
|
|
||||||
CoolTag,
|
|
||||||
CoolUrlTag,
|
|
||||||
TagTypes,
|
|
||||||
} from '@cool-midway/core';
|
|
||||||
import { ALL, Body, Get, Inject, Post, Provide } from '@midwayjs/decorator';
|
|
||||||
import { Context } from '@midwayjs/koa';
|
|
||||||
import { PluginService } from '../../../plugin/service/info';
|
|
||||||
import { BaseSysUserEntity } from '../../entity/sys/user';
|
|
||||||
import { BaseSysLoginService } from '../../service/sys/login';
|
|
||||||
import { BaseSysPermsService } from '../../service/sys/perms';
|
|
||||||
import { BaseSysUserService } from '../../service/sys/user';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Base 通用接口 一般写不需要权限过滤的接口
|
|
||||||
*/
|
|
||||||
@CoolUrlTag()
|
|
||||||
@Provide()
|
|
||||||
@CoolController()
|
|
||||||
export class BaseCommController extends BaseController {
|
|
||||||
@Inject()
|
|
||||||
baseSysUserService: BaseSysUserService;
|
|
||||||
|
|
||||||
@Inject()
|
|
||||||
baseSysPermsService: BaseSysPermsService;
|
|
||||||
|
|
||||||
@Inject()
|
|
||||||
baseSysLoginService: BaseSysLoginService;
|
|
||||||
|
|
||||||
@Inject()
|
|
||||||
ctx: Context;
|
|
||||||
|
|
||||||
@Inject()
|
|
||||||
pluginService: PluginService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获得个人信息
|
|
||||||
*/
|
|
||||||
@Get('/person', { summary: '个人信息' })
|
|
||||||
async person() {
|
|
||||||
return this.ok(
|
|
||||||
await this.baseSysUserService.person(this.ctx.admin?.userId)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 修改个人信息
|
|
||||||
*/
|
|
||||||
@Post('/personUpdate', { summary: '修改个人信息' })
|
|
||||||
async personUpdate(@Body(ALL) user: BaseSysUserEntity) {
|
|
||||||
await this.baseSysUserService.personUpdate(user);
|
|
||||||
return this.ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 权限菜单
|
|
||||||
*/
|
|
||||||
@Get('/permmenu', { summary: '权限与菜单' })
|
|
||||||
async permmenu() {
|
|
||||||
return this.ok(
|
|
||||||
await this.baseSysPermsService.permmenu(this.ctx.admin.roleIds)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 文件上传
|
|
||||||
*/
|
|
||||||
@Post('/upload', { summary: '文件上传' })
|
|
||||||
async upload() {
|
|
||||||
const file = await this.pluginService.getInstance('upload');
|
|
||||||
return this.ok(await file.upload(this.ctx));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 文件上传模式,本地或者云存储
|
|
||||||
*/
|
|
||||||
@Get('/uploadMode', { summary: '文件上传模式' })
|
|
||||||
async uploadMode() {
|
|
||||||
const file = await this.pluginService.getInstance('upload');
|
|
||||||
return this.ok(await file.getMode());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 退出
|
|
||||||
*/
|
|
||||||
@Post('/logout', { summary: '退出' })
|
|
||||||
async logout() {
|
|
||||||
await this.baseSysLoginService.logout();
|
|
||||||
return this.ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
@CoolTag(TagTypes.IGNORE_TOKEN)
|
|
||||||
@Get('/program', { summary: '编程' })
|
|
||||||
async program() {
|
|
||||||
return this.ok('Node');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,99 +0,0 @@
|
|||||||
import { Provide, Body, Inject, Post, Get, Query } from '@midwayjs/decorator';
|
|
||||||
import {
|
|
||||||
CoolController,
|
|
||||||
BaseController,
|
|
||||||
CoolEps,
|
|
||||||
CoolUrlTag,
|
|
||||||
CoolTag,
|
|
||||||
TagTypes,
|
|
||||||
RESCODE,
|
|
||||||
} from '@cool-midway/core';
|
|
||||||
import { LoginDTO } from '../../dto/login';
|
|
||||||
import { BaseSysLoginService } from '../../service/sys/login';
|
|
||||||
import { BaseSysParamService } from '../../service/sys/param';
|
|
||||||
import { Context } from '@midwayjs/koa';
|
|
||||||
import { Validate } from '@midwayjs/validate';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 不需要登录的后台接口
|
|
||||||
*/
|
|
||||||
@Provide()
|
|
||||||
@CoolController({ description: '开放接口' })
|
|
||||||
@CoolUrlTag()
|
|
||||||
export class BaseOpenController extends BaseController {
|
|
||||||
@Inject()
|
|
||||||
baseSysLoginService: BaseSysLoginService;
|
|
||||||
|
|
||||||
@Inject()
|
|
||||||
baseSysParamService: BaseSysParamService;
|
|
||||||
|
|
||||||
@Inject()
|
|
||||||
ctx: Context;
|
|
||||||
|
|
||||||
@Inject()
|
|
||||||
eps: CoolEps;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 实体信息与路径
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
@CoolTag(TagTypes.IGNORE_TOKEN)
|
|
||||||
@Get('/eps', { summary: '实体信息与路径' })
|
|
||||||
public async getEps() {
|
|
||||||
return this.ok(this.eps.admin);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据配置参数key获得网页内容(富文本)
|
|
||||||
*/
|
|
||||||
@CoolTag(TagTypes.IGNORE_TOKEN)
|
|
||||||
@Get('/html', { summary: '获得网页内容的参数值' })
|
|
||||||
async htmlByKey(@Query('key') key: string) {
|
|
||||||
this.ctx.body = await this.baseSysParamService.htmlByKey(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 登录
|
|
||||||
* @param login
|
|
||||||
*/
|
|
||||||
@CoolTag(TagTypes.IGNORE_TOKEN)
|
|
||||||
@Post('/login', { summary: '登录' })
|
|
||||||
@Validate()
|
|
||||||
async login(@Body() login: LoginDTO) {
|
|
||||||
return this.ok(await this.baseSysLoginService.login(login));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获得验证码
|
|
||||||
*/
|
|
||||||
@CoolTag(TagTypes.IGNORE_TOKEN)
|
|
||||||
@Get('/captcha', { summary: '验证码' })
|
|
||||||
async captcha(
|
|
||||||
@Query('type') type: string,
|
|
||||||
@Query('width') width: number,
|
|
||||||
@Query('height') height: number,
|
|
||||||
@Query('color') color: string
|
|
||||||
) {
|
|
||||||
return this.ok(
|
|
||||||
await this.baseSysLoginService.captcha(type, width, height, color)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 刷新token
|
|
||||||
*/
|
|
||||||
@CoolTag(TagTypes.IGNORE_TOKEN)
|
|
||||||
@Get('/refreshToken', { summary: '刷新token' })
|
|
||||||
async refreshToken(@Query('refreshToken') refreshToken: string) {
|
|
||||||
try {
|
|
||||||
const token = await this.baseSysLoginService.refreshToken(refreshToken);
|
|
||||||
return this.ok(token);
|
|
||||||
} catch (e) {
|
|
||||||
this.ctx.status = 401;
|
|
||||||
this.ctx.body = {
|
|
||||||
code: RESCODE.COMMFAIL,
|
|
||||||
message: '登录失效~',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,27 +0,0 @@
|
|||||||
import { ALL, Body, Inject, Post, Provide } from '@midwayjs/decorator';
|
|
||||||
import { CoolController, BaseController } from '@cool-midway/core';
|
|
||||||
import { BaseSysDepartmentEntity } from '../../../entity/sys/department';
|
|
||||||
import { BaseSysDepartmentService } from '../../../service/sys/department';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 部门
|
|
||||||
*/
|
|
||||||
@Provide()
|
|
||||||
@CoolController({
|
|
||||||
api: ['add', 'delete', 'update', 'list'],
|
|
||||||
entity: BaseSysDepartmentEntity,
|
|
||||||
service: BaseSysDepartmentService,
|
|
||||||
})
|
|
||||||
export class BaseDepartmentController extends BaseController {
|
|
||||||
@Inject()
|
|
||||||
baseDepartmentService: BaseSysDepartmentService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 部门排序
|
|
||||||
*/
|
|
||||||
@Post('/order', { summary: '排序' })
|
|
||||||
async order(@Body(ALL) params: any) {
|
|
||||||
await this.baseDepartmentService.order(params);
|
|
||||||
return this.ok();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,64 +0,0 @@
|
|||||||
import { Provide, Post, Inject, Body, Get } from '@midwayjs/decorator';
|
|
||||||
import { CoolController, BaseController } from '@cool-midway/core';
|
|
||||||
import { BaseSysLogEntity } from '../../../entity/sys/log';
|
|
||||||
import { BaseSysUserEntity } from '../../../entity/sys/user';
|
|
||||||
import { BaseSysConfService } from '../../../service/sys/conf';
|
|
||||||
import { BaseSysLogService } from '../../../service/sys/log';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 系统日志
|
|
||||||
*/
|
|
||||||
@Provide()
|
|
||||||
@CoolController({
|
|
||||||
api: ['page'],
|
|
||||||
entity: BaseSysLogEntity,
|
|
||||||
urlTag: {
|
|
||||||
name: 'a',
|
|
||||||
url: ['add'],
|
|
||||||
},
|
|
||||||
pageQueryOp: {
|
|
||||||
keyWordLikeFields: ['b.name', 'a.action', 'a.ip'],
|
|
||||||
select: ['a.*', 'b.name'],
|
|
||||||
join: [
|
|
||||||
{
|
|
||||||
entity: BaseSysUserEntity,
|
|
||||||
alias: 'b',
|
|
||||||
condition: 'a.userId = b.id',
|
|
||||||
type: 'leftJoin',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
})
|
|
||||||
export class BaseSysLogController extends BaseController {
|
|
||||||
@Inject()
|
|
||||||
baseSysLogService: BaseSysLogService;
|
|
||||||
|
|
||||||
@Inject()
|
|
||||||
baseSysConfService: BaseSysConfService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 清空日志
|
|
||||||
*/
|
|
||||||
@Post('/clear', { summary: '清理' })
|
|
||||||
public async clear() {
|
|
||||||
await this.baseSysLogService.clear(true);
|
|
||||||
return this.ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置日志保存时间
|
|
||||||
*/
|
|
||||||
@Post('/setKeep', { summary: '日志保存时间' })
|
|
||||||
public async setKeep(@Body('value') value: number) {
|
|
||||||
await this.baseSysConfService.updateVaule('logKeep', value);
|
|
||||||
return this.ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获得日志保存时间
|
|
||||||
*/
|
|
||||||
@Get('/getKeep', { summary: '获得日志保存时间' })
|
|
||||||
public async getKeep() {
|
|
||||||
return this.ok(await this.baseSysConfService.getValue('logKeep'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,46 +0,0 @@
|
|||||||
import { Body, Inject, Post, Provide } from '@midwayjs/decorator';
|
|
||||||
import { CoolController, BaseController } from '@cool-midway/core';
|
|
||||||
import { BaseSysMenuEntity } from '../../../entity/sys/menu';
|
|
||||||
import { BaseSysMenuService } from '../../../service/sys/menu';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 菜单
|
|
||||||
*/
|
|
||||||
@Provide()
|
|
||||||
@CoolController({
|
|
||||||
api: ['add', 'delete', 'update', 'info', 'list', 'page'],
|
|
||||||
entity: BaseSysMenuEntity,
|
|
||||||
service: BaseSysMenuService,
|
|
||||||
})
|
|
||||||
export class BaseSysMenuController extends BaseController {
|
|
||||||
@Inject()
|
|
||||||
baseSysMenuService: BaseSysMenuService;
|
|
||||||
|
|
||||||
@Post('/parse', { summary: '解析' })
|
|
||||||
async parse(
|
|
||||||
@Body('entity') entity: string,
|
|
||||||
@Body('controller') controller: string,
|
|
||||||
@Body('module') module: string
|
|
||||||
) {
|
|
||||||
return this.ok(
|
|
||||||
await this.baseSysMenuService.parse(entity, controller, module)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Post('/create', { summary: '创建代码' })
|
|
||||||
async create(@Body() body) {
|
|
||||||
await this.baseSysMenuService.create(body);
|
|
||||||
return this.ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Post('/export', { summary: '导出' })
|
|
||||||
async export(@Body('ids') ids: number[]) {
|
|
||||||
return this.ok(await this.baseSysMenuService.export(ids));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Post('/import', { summary: '导入' })
|
|
||||||
async import(@Body('menus') menus: any[]) {
|
|
||||||
await this.baseSysMenuService.import(menus);
|
|
||||||
return this.ok();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,34 +0,0 @@
|
|||||||
import { Get, Inject, Provide, Query } from '@midwayjs/decorator';
|
|
||||||
import { CoolController, BaseController } from '@cool-midway/core';
|
|
||||||
import { BaseSysParamEntity } from '../../../entity/sys/param';
|
|
||||||
import { BaseSysParamService } from '../../../service/sys/param';
|
|
||||||
import { Context } from '@midwayjs/koa';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 参数配置
|
|
||||||
*/
|
|
||||||
@Provide()
|
|
||||||
@CoolController({
|
|
||||||
api: ['add', 'delete', 'update', 'info', 'page'],
|
|
||||||
entity: BaseSysParamEntity,
|
|
||||||
service: BaseSysParamService,
|
|
||||||
pageQueryOp: {
|
|
||||||
keyWordLikeFields: ['name', 'keyName'],
|
|
||||||
fieldEq: ['dataType'],
|
|
||||||
},
|
|
||||||
})
|
|
||||||
export class BaseSysParamController extends BaseController {
|
|
||||||
@Inject()
|
|
||||||
baseSysParamService: BaseSysParamService;
|
|
||||||
|
|
||||||
@Inject()
|
|
||||||
ctx: Context;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据配置参数key获得网页内容(富文本)
|
|
||||||
*/
|
|
||||||
@Get('/html', { summary: '获得网页内容的参数值' })
|
|
||||||
async htmlByKey(@Query('key') key: string) {
|
|
||||||
this.ctx.body = await this.baseSysParamService.htmlByKey(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,38 +0,0 @@
|
|||||||
import { Provide } from '@midwayjs/decorator';
|
|
||||||
import { CoolController, BaseController } from '@cool-midway/core';
|
|
||||||
import { Context } from 'vm';
|
|
||||||
import { BaseSysRoleEntity } from '../../../entity/sys/role';
|
|
||||||
import { BaseSysRoleService } from '../../../service/sys/role';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 系统角色
|
|
||||||
*/
|
|
||||||
@Provide()
|
|
||||||
@CoolController({
|
|
||||||
api: ['add', 'delete', 'update', 'info', 'list', 'page'],
|
|
||||||
entity: BaseSysRoleEntity,
|
|
||||||
service: BaseSysRoleService,
|
|
||||||
// 新增的时候插入当前用户ID
|
|
||||||
insertParam: async (ctx: Context) => {
|
|
||||||
return {
|
|
||||||
userId: ctx.admin.userId,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
pageQueryOp: {
|
|
||||||
keyWordLikeFields: ['a.name', 'a.label'],
|
|
||||||
where: async (ctx: Context) => {
|
|
||||||
const { userId, roleIds, username } = ctx.admin;
|
|
||||||
return [
|
|
||||||
// 超级管理员的角色不展示
|
|
||||||
['label != :label', { label: 'admin' }],
|
|
||||||
// 如果不是超管,只能看到自己新建的或者自己有的角色
|
|
||||||
[
|
|
||||||
`(userId=:userId or id in (${roleIds.join(',')}))`,
|
|
||||||
{ userId },
|
|
||||||
username !== 'admin',
|
|
||||||
],
|
|
||||||
];
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
export class BaseSysRoleController extends BaseController {}
|
|
||||||
@ -1,30 +0,0 @@
|
|||||||
import { Body, Inject, Post, Provide } from '@midwayjs/decorator';
|
|
||||||
import { CoolController, BaseController } from '@cool-midway/core';
|
|
||||||
import { BaseSysUserEntity } from '../../../entity/sys/user';
|
|
||||||
import { BaseSysUserService } from '../../../service/sys/user';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 系统用户
|
|
||||||
*/
|
|
||||||
@Provide()
|
|
||||||
@CoolController({
|
|
||||||
api: ['add', 'delete', 'update', 'info', 'list', 'page'],
|
|
||||||
entity: BaseSysUserEntity,
|
|
||||||
service: BaseSysUserService,
|
|
||||||
})
|
|
||||||
export class BaseSysUserController extends BaseController {
|
|
||||||
@Inject()
|
|
||||||
baseSysUserService: BaseSysUserService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 移动部门
|
|
||||||
*/
|
|
||||||
@Post('/move', { summary: '移动部门' })
|
|
||||||
async move(
|
|
||||||
@Body('departmentId') departmentId: number,
|
|
||||||
@Body('userIds') userIds: []
|
|
||||||
) {
|
|
||||||
await this.baseSysUserService.move(departmentId, userIds);
|
|
||||||
return this.ok();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1 +0,0 @@
|
|||||||
这里写对外的api接口
|
|
||||||
@ -1,72 +0,0 @@
|
|||||||
import { Provide, Inject, Get, Post, Query, Config } from '@midwayjs/decorator';
|
|
||||||
import {
|
|
||||||
CoolController,
|
|
||||||
BaseController,
|
|
||||||
CoolEps,
|
|
||||||
TagTypes,
|
|
||||||
CoolUrlTag,
|
|
||||||
CoolTag,
|
|
||||||
} from '@cool-midway/core';
|
|
||||||
import { Context } from '@midwayjs/koa';
|
|
||||||
import { BaseSysParamService } from '../../service/sys/param';
|
|
||||||
import { PluginService } from '../../../plugin/service/info';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 不需要登录的后台接口
|
|
||||||
*/
|
|
||||||
@CoolUrlTag()
|
|
||||||
@Provide()
|
|
||||||
@CoolController()
|
|
||||||
export class BaseAppCommController extends BaseController {
|
|
||||||
@Inject()
|
|
||||||
pluginService: PluginService;
|
|
||||||
|
|
||||||
@Inject()
|
|
||||||
ctx: Context;
|
|
||||||
|
|
||||||
@Config('module.base.allowKeys')
|
|
||||||
allowKeys: string[];
|
|
||||||
|
|
||||||
@Inject()
|
|
||||||
eps: CoolEps;
|
|
||||||
|
|
||||||
@Inject()
|
|
||||||
baseSysParamService: BaseSysParamService;
|
|
||||||
|
|
||||||
@CoolTag(TagTypes.IGNORE_TOKEN)
|
|
||||||
@Get('/param', { summary: '参数配置' })
|
|
||||||
async param(@Query('key') key: string) {
|
|
||||||
if (!this.allowKeys.includes(key)) {
|
|
||||||
return this.fail('非法操作');
|
|
||||||
}
|
|
||||||
return this.ok(await this.baseSysParamService.dataByKey(key));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 实体信息与路径
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
@CoolTag(TagTypes.IGNORE_TOKEN)
|
|
||||||
@Get('/eps', { summary: '实体信息与路径' })
|
|
||||||
public async getEps() {
|
|
||||||
return this.ok(this.eps.app);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 文件上传
|
|
||||||
*/
|
|
||||||
@Post('/upload', { summary: '文件上传' })
|
|
||||||
async upload() {
|
|
||||||
const file = await this.pluginService.getInstance('upload');
|
|
||||||
return this.ok(await file.upload(this.ctx));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 文件上传模式,本地或者云存储
|
|
||||||
*/
|
|
||||||
@Get('/uploadMode', { summary: '文件上传模式' })
|
|
||||||
async uploadMode() {
|
|
||||||
const file = await this.pluginService.getInstance('upload');
|
|
||||||
return this.ok(await file.getMode());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,103 +0,0 @@
|
|||||||
{
|
|
||||||
"base_sys_param": [
|
|
||||||
{
|
|
||||||
"keyName": "rich",
|
|
||||||
"name": "富文本参数",
|
|
||||||
"data": "<h3><strong>这是一个富文本</strong></h3><p>xxx</p><p>xxxxxxxxxx</p><p><br></p>",
|
|
||||||
"dataType": 1,
|
|
||||||
"remark": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"keyName": "json",
|
|
||||||
"name": "JSON参数",
|
|
||||||
"data": "{\n \"code\": 111233\n}",
|
|
||||||
"dataType": 0,
|
|
||||||
"remark": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"keyName": "file",
|
|
||||||
"name": "文件",
|
|
||||||
"data": "",
|
|
||||||
"dataType": 2,
|
|
||||||
"remark": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"keyName": "text",
|
|
||||||
"name": "测试",
|
|
||||||
"data": "这是一段字符串",
|
|
||||||
"dataType": 0,
|
|
||||||
"remark": null
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"base_sys_conf": [
|
|
||||||
{
|
|
||||||
"cKey": "logKeep",
|
|
||||||
"cValue": "31"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cKey": "recycleKeep",
|
|
||||||
"cValue": "31"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"base_sys_department": [
|
|
||||||
{
|
|
||||||
"id": 1,
|
|
||||||
"name": "COOL",
|
|
||||||
"parentId": null,
|
|
||||||
"orderNum": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 11,
|
|
||||||
"name": "开发",
|
|
||||||
"parentId": 12,
|
|
||||||
"orderNum": 2
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 12,
|
|
||||||
"name": "测试",
|
|
||||||
"parentId": 1,
|
|
||||||
"orderNum": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 13,
|
|
||||||
"name": "游客",
|
|
||||||
"parentId": 1,
|
|
||||||
"orderNum": 3
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"base_sys_role": [
|
|
||||||
{
|
|
||||||
"id": 1,
|
|
||||||
"userId": "1",
|
|
||||||
"name": "超管",
|
|
||||||
"label": "admin",
|
|
||||||
"remark": "最高权限的角色",
|
|
||||||
"relevance": 1,
|
|
||||||
"menuIdList": "null",
|
|
||||||
"departmentIdList": "null"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"base_sys_user": [
|
|
||||||
{
|
|
||||||
"id": 1,
|
|
||||||
"departmentId": 1,
|
|
||||||
"name": "超级管理员",
|
|
||||||
"username": "admin",
|
|
||||||
"password": "e10adc3949ba59abbe56e057f20f883e",
|
|
||||||
"passwordV": 7,
|
|
||||||
"nickName": "管理员",
|
|
||||||
"headImg": "https://cool-js.com/admin/headimg.jpg",
|
|
||||||
"phone": "18000000000",
|
|
||||||
"email": "team@cool-js.com",
|
|
||||||
"status": 1,
|
|
||||||
"remark": "拥有最高权限的用户",
|
|
||||||
"socketId": null
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"base_sys_user_role": [
|
|
||||||
{
|
|
||||||
"userId": 1,
|
|
||||||
"roleId": 1
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@ -1,21 +0,0 @@
|
|||||||
import { Rule, RuleType } from '@midwayjs/validate';
|
|
||||||
/**
|
|
||||||
* 登录参数校验
|
|
||||||
*/
|
|
||||||
export class LoginDTO {
|
|
||||||
// 用户名
|
|
||||||
@Rule(RuleType.string().required())
|
|
||||||
username: string;
|
|
||||||
|
|
||||||
// 密码
|
|
||||||
@Rule(RuleType.string().required())
|
|
||||||
password: string;
|
|
||||||
|
|
||||||
// 验证码ID
|
|
||||||
@Rule(RuleType.string().required())
|
|
||||||
captchaId: string;
|
|
||||||
|
|
||||||
// 验证码
|
|
||||||
@Rule(RuleType.required())
|
|
||||||
verifyCode: number;
|
|
||||||
}
|
|
||||||
@ -1,15 +0,0 @@
|
|||||||
import { Column, Index, Entity } from 'typeorm';
|
|
||||||
import { BaseEntity } from '@cool-midway/core';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 系统配置
|
|
||||||
*/
|
|
||||||
@Entity('base_sys_conf')
|
|
||||||
export class BaseSysConfEntity extends BaseEntity {
|
|
||||||
@Index({ unique: true })
|
|
||||||
@Column({ comment: '配置键' })
|
|
||||||
cKey: string;
|
|
||||||
|
|
||||||
@Column({ comment: '配置值' })
|
|
||||||
cValue: string;
|
|
||||||
}
|
|
||||||
@ -1,19 +0,0 @@
|
|||||||
import { BaseEntity } from '@cool-midway/core';
|
|
||||||
import { Column, Entity } from 'typeorm';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 部门
|
|
||||||
*/
|
|
||||||
@Entity('base_sys_department')
|
|
||||||
export class BaseSysDepartmentEntity extends BaseEntity {
|
|
||||||
@Column({ comment: '部门名称' })
|
|
||||||
name: string;
|
|
||||||
|
|
||||||
@Column({ comment: '上级部门ID', nullable: true })
|
|
||||||
parentId: number;
|
|
||||||
|
|
||||||
@Column({ comment: '排序', default: 0 })
|
|
||||||
orderNum: number;
|
|
||||||
// 父菜单名称
|
|
||||||
parentName: string;
|
|
||||||
}
|
|
||||||
@ -1,23 +0,0 @@
|
|||||||
import { BaseEntity } from '@cool-midway/core';
|
|
||||||
import { Column, Index, Entity } from 'typeorm';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 系统日志
|
|
||||||
*/
|
|
||||||
@Entity('base_sys_log')
|
|
||||||
export class BaseSysLogEntity extends BaseEntity {
|
|
||||||
@Index()
|
|
||||||
@Column({ comment: '用户ID', nullable: true })
|
|
||||||
userId: number;
|
|
||||||
|
|
||||||
@Index()
|
|
||||||
@Column({ comment: '行为' })
|
|
||||||
action: string;
|
|
||||||
|
|
||||||
@Index()
|
|
||||||
@Column({ comment: 'ip', nullable: true })
|
|
||||||
ip: string;
|
|
||||||
|
|
||||||
@Column({ comment: '参数', nullable: true, type: 'json' })
|
|
||||||
params: string;
|
|
||||||
}
|
|
||||||
@ -1,47 +0,0 @@
|
|||||||
import { BaseEntity } from '@cool-midway/core';
|
|
||||||
import { Column, Entity } from 'typeorm';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 菜单
|
|
||||||
*/
|
|
||||||
@Entity('base_sys_menu')
|
|
||||||
export class BaseSysMenuEntity extends BaseEntity {
|
|
||||||
@Column({ comment: '父菜单ID', nullable: true })
|
|
||||||
parentId: number;
|
|
||||||
|
|
||||||
@Column({ comment: '菜单名称' })
|
|
||||||
name: string;
|
|
||||||
|
|
||||||
@Column({ comment: '菜单地址', nullable: true })
|
|
||||||
router: string;
|
|
||||||
|
|
||||||
@Column({ comment: '权限标识', type: 'text', nullable: true })
|
|
||||||
perms: string;
|
|
||||||
|
|
||||||
@Column({
|
|
||||||
comment: '类型 0-目录 1-菜单 2-按钮',
|
|
||||||
default: 0,
|
|
||||||
})
|
|
||||||
type: number;
|
|
||||||
|
|
||||||
@Column({ comment: '图标', nullable: true })
|
|
||||||
icon: string;
|
|
||||||
|
|
||||||
@Column({ comment: '排序', default: 0 })
|
|
||||||
orderNum: number;
|
|
||||||
|
|
||||||
@Column({ comment: '视图地址', nullable: true })
|
|
||||||
viewPath: string;
|
|
||||||
|
|
||||||
@Column({ comment: '路由缓存', default: true })
|
|
||||||
keepAlive: boolean;
|
|
||||||
|
|
||||||
@Column({ comment: '是否显示', default: true })
|
|
||||||
isShow: boolean;
|
|
||||||
|
|
||||||
// 父菜单名称
|
|
||||||
parentName: string;
|
|
||||||
|
|
||||||
// 子菜单
|
|
||||||
childMenus: any;
|
|
||||||
}
|
|
||||||
@ -1,27 +0,0 @@
|
|||||||
import { BaseEntity } from '@cool-midway/core';
|
|
||||||
import { Column, Index, Entity } from 'typeorm';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 参数配置
|
|
||||||
*/
|
|
||||||
@Entity('base_sys_param')
|
|
||||||
export class BaseSysParamEntity extends BaseEntity {
|
|
||||||
@Index({ unique: true })
|
|
||||||
@Column({ comment: '键' })
|
|
||||||
keyName: string;
|
|
||||||
|
|
||||||
@Column({ comment: '名称' })
|
|
||||||
name: string;
|
|
||||||
|
|
||||||
@Column({ comment: '数据', type: 'text' })
|
|
||||||
data: string;
|
|
||||||
|
|
||||||
@Column({
|
|
||||||
comment: '数据类型 0-字符串 1-富文本 2-文件 ',
|
|
||||||
default: 0,
|
|
||||||
})
|
|
||||||
dataType: number;
|
|
||||||
|
|
||||||
@Column({ comment: '备注', nullable: true })
|
|
||||||
remark: string;
|
|
||||||
}
|
|
||||||
@ -1,31 +0,0 @@
|
|||||||
import { BaseEntity } from '@cool-midway/core';
|
|
||||||
import { Column, Index, Entity } from 'typeorm';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 角色
|
|
||||||
*/
|
|
||||||
@Entity('base_sys_role')
|
|
||||||
export class BaseSysRoleEntity extends BaseEntity {
|
|
||||||
@Column({ comment: '用户ID' })
|
|
||||||
userId: string;
|
|
||||||
|
|
||||||
@Index({ unique: true })
|
|
||||||
@Column({ comment: '名称' })
|
|
||||||
name: string;
|
|
||||||
|
|
||||||
@Index({ unique: true })
|
|
||||||
@Column({ comment: '角色标签', nullable: true, length: 50 })
|
|
||||||
label: string;
|
|
||||||
|
|
||||||
@Column({ comment: '备注', nullable: true })
|
|
||||||
remark: string;
|
|
||||||
|
|
||||||
@Column({ comment: '数据权限是否关联上下级', default: false })
|
|
||||||
relevance: boolean;
|
|
||||||
|
|
||||||
@Column({ comment: '菜单权限', type: 'json' })
|
|
||||||
menuIdList: number[];
|
|
||||||
|
|
||||||
@Column({ comment: '部门权限', type: 'json' })
|
|
||||||
departmentIdList: number[];
|
|
||||||
}
|
|
||||||
@ -1,14 +0,0 @@
|
|||||||
import { BaseEntity } from '@cool-midway/core';
|
|
||||||
import { Column, Entity } from 'typeorm';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 角色部门
|
|
||||||
*/
|
|
||||||
@Entity('base_sys_role_department')
|
|
||||||
export class BaseSysRoleDepartmentEntity extends BaseEntity {
|
|
||||||
@Column({ comment: '角色ID' })
|
|
||||||
roleId: number;
|
|
||||||
|
|
||||||
@Column({ comment: '部门ID' })
|
|
||||||
departmentId: number;
|
|
||||||
}
|
|
||||||
@ -1,14 +0,0 @@
|
|||||||
import { BaseEntity } from '@cool-midway/core';
|
|
||||||
import { Column, Entity } from 'typeorm';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 角色菜单
|
|
||||||
*/
|
|
||||||
@Entity('base_sys_role_menu')
|
|
||||||
export class BaseSysRoleMenuEntity extends BaseEntity {
|
|
||||||
@Column({ comment: '角色ID' })
|
|
||||||
roleId: number;
|
|
||||||
|
|
||||||
@Column({ comment: '菜单ID' })
|
|
||||||
menuId: number;
|
|
||||||
}
|
|
||||||
@ -1,54 +0,0 @@
|
|||||||
import { BaseEntity } from '@cool-midway/core';
|
|
||||||
import { Column, Index, Entity } from 'typeorm';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 系统用户
|
|
||||||
*/
|
|
||||||
@Entity('base_sys_user')
|
|
||||||
export class BaseSysUserEntity extends BaseEntity {
|
|
||||||
@Index()
|
|
||||||
@Column({ comment: '部门ID', nullable: true })
|
|
||||||
departmentId: number;
|
|
||||||
|
|
||||||
@Column({ comment: '姓名', nullable: true })
|
|
||||||
name: string;
|
|
||||||
|
|
||||||
@Index({ unique: true })
|
|
||||||
@Column({ comment: '用户名', length: 100 })
|
|
||||||
username: string;
|
|
||||||
|
|
||||||
@Column({ comment: '密码' })
|
|
||||||
password: string;
|
|
||||||
|
|
||||||
@Column({
|
|
||||||
comment: '密码版本, 作用是改完密码,让原来的token失效',
|
|
||||||
default: 1,
|
|
||||||
})
|
|
||||||
passwordV: number;
|
|
||||||
|
|
||||||
@Column({ comment: '昵称', nullable: true })
|
|
||||||
nickName: string;
|
|
||||||
|
|
||||||
@Column({ comment: '头像', nullable: true })
|
|
||||||
headImg: string;
|
|
||||||
|
|
||||||
@Index()
|
|
||||||
@Column({ comment: '手机', nullable: true, length: 20 })
|
|
||||||
phone: string;
|
|
||||||
|
|
||||||
@Column({ comment: '邮箱', nullable: true })
|
|
||||||
email: string;
|
|
||||||
|
|
||||||
@Column({ comment: '备注', nullable: true })
|
|
||||||
remark: string;
|
|
||||||
|
|
||||||
@Column({ comment: '状态 0-禁用 1-启用', default: 1 })
|
|
||||||
status: number;
|
|
||||||
// 部门名称
|
|
||||||
departmentName: string;
|
|
||||||
// 角色ID列表
|
|
||||||
roleIdList: number[];
|
|
||||||
|
|
||||||
@Column({ comment: 'socketId', nullable: true })
|
|
||||||
socketId: string;
|
|
||||||
}
|
|
||||||
@ -1,14 +0,0 @@
|
|||||||
import { BaseEntity } from '@cool-midway/core';
|
|
||||||
import { Column, Entity } from 'typeorm';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 用户角色
|
|
||||||
*/
|
|
||||||
@Entity('base_sys_user_role')
|
|
||||||
export class BaseSysUserRoleEntity extends BaseEntity {
|
|
||||||
@Column({ comment: '用户ID' })
|
|
||||||
userId: number;
|
|
||||||
|
|
||||||
@Column({ comment: '角色ID' })
|
|
||||||
roleId: number;
|
|
||||||
}
|
|
||||||
@ -1,102 +0,0 @@
|
|||||||
import { CoolEvent, Event } from '@cool-midway/core';
|
|
||||||
import { App, Config, ILogger, Logger } from '@midwayjs/core';
|
|
||||||
import { IMidwayKoaApplication } from '@midwayjs/koa';
|
|
||||||
import * as fs from 'fs';
|
|
||||||
import * as path from 'path';
|
|
||||||
import { v1 as uuid } from 'uuid';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 修改jwt.secret
|
|
||||||
*/
|
|
||||||
@CoolEvent()
|
|
||||||
export class BaseAppEvent {
|
|
||||||
@Logger()
|
|
||||||
coreLogger: ILogger;
|
|
||||||
|
|
||||||
@Config('module')
|
|
||||||
config;
|
|
||||||
|
|
||||||
@Config('keys')
|
|
||||||
configKeys;
|
|
||||||
|
|
||||||
@Config('koa.port')
|
|
||||||
port;
|
|
||||||
|
|
||||||
@App()
|
|
||||||
app: IMidwayKoaApplication;
|
|
||||||
|
|
||||||
@Event('onMenuInit')
|
|
||||||
async onMenuInit() {
|
|
||||||
if (this.app.getEnv() != 'local') return;
|
|
||||||
this.checkConfig();
|
|
||||||
this.checkKeys();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Event('onServerReady')
|
|
||||||
async onServerReady() {
|
|
||||||
this.coreLogger.info(`服务启动成功,端口:${this.port}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 检查配置
|
|
||||||
*/
|
|
||||||
async checkConfig() {
|
|
||||||
if (this.config.base.jwt.secret == 'cool-admin-xxxxxx') {
|
|
||||||
this.coreLogger.warn(
|
|
||||||
'\x1B[36m 检测到模块[base] jwt.secret 配置是默认值,请不要关闭!即将自动修改... \x1B[0m'
|
|
||||||
);
|
|
||||||
setTimeout(() => {
|
|
||||||
const filePath = path.join(
|
|
||||||
this.app.getBaseDir(),
|
|
||||||
'..',
|
|
||||||
'src',
|
|
||||||
'modules',
|
|
||||||
'base',
|
|
||||||
'config.ts'
|
|
||||||
);
|
|
||||||
// 替换文件内容
|
|
||||||
let fileData = fs.readFileSync(filePath, 'utf8');
|
|
||||||
const secret = uuid().replace(/-/g, '');
|
|
||||||
this.config.base.jwt.secret = secret;
|
|
||||||
fs.writeFileSync(
|
|
||||||
filePath,
|
|
||||||
fileData.replace('cool-admin-xxxxxx', secret)
|
|
||||||
);
|
|
||||||
this.coreLogger.info(
|
|
||||||
'\x1B[36m [cool:module:base] midwayjs cool module base auto modify jwt.secret\x1B[0m'
|
|
||||||
);
|
|
||||||
}, 6000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 检查keys
|
|
||||||
*/
|
|
||||||
async checkKeys() {
|
|
||||||
if (this.configKeys == 'cool-admin-keys-xxxxxx') {
|
|
||||||
this.coreLogger.warn(
|
|
||||||
'\x1B[36m 检测到基础配置[Keys] 是默认值,请不要关闭!即将自动修改... \x1B[0m'
|
|
||||||
);
|
|
||||||
setTimeout(() => {
|
|
||||||
const filePath = path.join(
|
|
||||||
this.app.getBaseDir(),
|
|
||||||
'..',
|
|
||||||
'src',
|
|
||||||
'config',
|
|
||||||
'config.default.ts'
|
|
||||||
);
|
|
||||||
// 替换文件内容
|
|
||||||
let fileData = fs.readFileSync(filePath, 'utf8');
|
|
||||||
const secret = uuid().replace(/-/g, '');
|
|
||||||
this.config.base.jwt.secret = secret;
|
|
||||||
fs.writeFileSync(
|
|
||||||
filePath,
|
|
||||||
fileData.replace('cool-admin-keys-xxxxxx', secret)
|
|
||||||
);
|
|
||||||
this.coreLogger.info(
|
|
||||||
'\x1B[36m [cool:module:base] midwayjs cool keys auto modify \x1B[0m'
|
|
||||||
);
|
|
||||||
}, 6000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,40 +0,0 @@
|
|||||||
import { CoolEvent, CoolEventManager, Event } from '@cool-midway/core';
|
|
||||||
import { BaseSysMenuService } from '../service/sys/menu';
|
|
||||||
import {
|
|
||||||
App,
|
|
||||||
ILogger,
|
|
||||||
IMidwayApplication,
|
|
||||||
Inject,
|
|
||||||
Logger,
|
|
||||||
} from '@midwayjs/core';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 导入菜单
|
|
||||||
*/
|
|
||||||
@CoolEvent()
|
|
||||||
export class BaseMenuEvent {
|
|
||||||
@Logger()
|
|
||||||
coreLogger: ILogger;
|
|
||||||
|
|
||||||
@Inject()
|
|
||||||
baseSysMenuService: BaseSysMenuService;
|
|
||||||
|
|
||||||
@App()
|
|
||||||
app: IMidwayApplication;
|
|
||||||
|
|
||||||
@Inject()
|
|
||||||
coolEventManager: CoolEventManager;
|
|
||||||
|
|
||||||
@Event('onMenuImport')
|
|
||||||
async onMenuImport(datas) {
|
|
||||||
for (const module in datas) {
|
|
||||||
await this.baseSysMenuService.import(datas[module]);
|
|
||||||
this.coreLogger.info(
|
|
||||||
'\x1B[36m [cool:module:base] midwayjs cool module base import [' +
|
|
||||||
module +
|
|
||||||
'] module menu success \x1B[0m'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
this.coolEventManager.emit('onMenuInit', {});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,25 +0,0 @@
|
|||||||
import { Job, IJob } from '@midwayjs/cron';
|
|
||||||
import { FORMAT, ILogger, Inject } from '@midwayjs/core';
|
|
||||||
import { BaseSysLogService } from '../service/sys/log';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 日志定时任务
|
|
||||||
*/
|
|
||||||
@Job({
|
|
||||||
cronTime: FORMAT.CRONTAB.EVERY_DAY,
|
|
||||||
start: true,
|
|
||||||
})
|
|
||||||
export class BaseLogJob implements IJob {
|
|
||||||
@Inject()
|
|
||||||
baseSysLogService: BaseSysLogService;
|
|
||||||
|
|
||||||
@Inject()
|
|
||||||
logger: ILogger;
|
|
||||||
|
|
||||||
async onTick() {
|
|
||||||
this.logger.info('清除日志定时任务开始执行');
|
|
||||||
const startTime = Date.now();
|
|
||||||
await this.baseSysLogService.clear();
|
|
||||||
this.logger.info(`清除日志定时任务结束,耗时:${Date.now() - startTime}ms`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,875 +0,0 @@
|
|||||||
[
|
|
||||||
{
|
|
||||||
"name": "系统管理",
|
|
||||||
"router": "/sys",
|
|
||||||
"perms": null,
|
|
||||||
"type": 0,
|
|
||||||
"icon": "icon-system",
|
|
||||||
"orderNum": 2,
|
|
||||||
"viewPath": null,
|
|
||||||
"keepAlive": true,
|
|
||||||
"isShow": true,
|
|
||||||
"childMenus": [
|
|
||||||
{
|
|
||||||
"name": "权限管理",
|
|
||||||
"router": null,
|
|
||||||
"perms": null,
|
|
||||||
"type": 0,
|
|
||||||
"icon": "icon-auth",
|
|
||||||
"orderNum": 1,
|
|
||||||
"viewPath": null,
|
|
||||||
"keepAlive": false,
|
|
||||||
"isShow": true,
|
|
||||||
"childMenus": [
|
|
||||||
{
|
|
||||||
"name": "菜单列表",
|
|
||||||
"router": "/sys/menu",
|
|
||||||
"perms": null,
|
|
||||||
"type": 1,
|
|
||||||
"icon": "icon-menu",
|
|
||||||
"orderNum": 2,
|
|
||||||
"viewPath": "modules/base/views/menu/index.vue",
|
|
||||||
"keepAlive": true,
|
|
||||||
"isShow": true,
|
|
||||||
"childMenus": [
|
|
||||||
{
|
|
||||||
"name": "新增",
|
|
||||||
"router": null,
|
|
||||||
"perms": "base:sys:menu:add",
|
|
||||||
"type": 2,
|
|
||||||
"icon": null,
|
|
||||||
"orderNum": 1,
|
|
||||||
"viewPath": null,
|
|
||||||
"keepAlive": false,
|
|
||||||
"isShow": true,
|
|
||||||
"childMenus": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "删除",
|
|
||||||
"router": null,
|
|
||||||
"perms": "base:sys:menu:delete",
|
|
||||||
"type": 2,
|
|
||||||
"icon": null,
|
|
||||||
"orderNum": 2,
|
|
||||||
"viewPath": null,
|
|
||||||
"keepAlive": false,
|
|
||||||
"isShow": true,
|
|
||||||
"childMenus": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "查询",
|
|
||||||
"router": null,
|
|
||||||
"perms": "base:sys:menu:page,base:sys:menu:list,base:sys:menu:info",
|
|
||||||
"type": 2,
|
|
||||||
"icon": null,
|
|
||||||
"orderNum": 4,
|
|
||||||
"viewPath": null,
|
|
||||||
"keepAlive": false,
|
|
||||||
"isShow": true,
|
|
||||||
"childMenus": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "参数",
|
|
||||||
"router": "/test/aa",
|
|
||||||
"perms": null,
|
|
||||||
"type": 1,
|
|
||||||
"icon": "icon-goods",
|
|
||||||
"orderNum": 0,
|
|
||||||
"viewPath": "modules/base/views/info.vue",
|
|
||||||
"keepAlive": true,
|
|
||||||
"isShow": true,
|
|
||||||
"childMenus": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "编辑",
|
|
||||||
"router": null,
|
|
||||||
"perms": "base:sys:menu:info,base:sys:menu:update",
|
|
||||||
"type": 2,
|
|
||||||
"icon": null,
|
|
||||||
"orderNum": 0,
|
|
||||||
"viewPath": null,
|
|
||||||
"keepAlive": true,
|
|
||||||
"isShow": true,
|
|
||||||
"childMenus": []
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "角色列表",
|
|
||||||
"router": "/sys/role",
|
|
||||||
"perms": null,
|
|
||||||
"type": 1,
|
|
||||||
"icon": "icon-dept",
|
|
||||||
"orderNum": 3,
|
|
||||||
"viewPath": "cool/modules/base/views/role.vue",
|
|
||||||
"keepAlive": true,
|
|
||||||
"isShow": true,
|
|
||||||
"childMenus": [
|
|
||||||
{
|
|
||||||
"name": "新增",
|
|
||||||
"router": null,
|
|
||||||
"perms": "base:sys:role:add",
|
|
||||||
"type": 2,
|
|
||||||
"icon": null,
|
|
||||||
"orderNum": 1,
|
|
||||||
"viewPath": null,
|
|
||||||
"keepAlive": false,
|
|
||||||
"isShow": true,
|
|
||||||
"childMenus": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "删除",
|
|
||||||
"router": null,
|
|
||||||
"perms": "base:sys:role:delete",
|
|
||||||
"type": 2,
|
|
||||||
"icon": null,
|
|
||||||
"orderNum": 2,
|
|
||||||
"viewPath": null,
|
|
||||||
"keepAlive": false,
|
|
||||||
"isShow": true,
|
|
||||||
"childMenus": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "修改",
|
|
||||||
"router": null,
|
|
||||||
"perms": "base:sys:role:update",
|
|
||||||
"type": 2,
|
|
||||||
"icon": null,
|
|
||||||
"orderNum": 3,
|
|
||||||
"viewPath": null,
|
|
||||||
"keepAlive": false,
|
|
||||||
"isShow": true,
|
|
||||||
"childMenus": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "查询",
|
|
||||||
"router": null,
|
|
||||||
"perms": "base:sys:role:page,base:sys:role:list,base:sys:role:info",
|
|
||||||
"type": 2,
|
|
||||||
"icon": null,
|
|
||||||
"orderNum": 4,
|
|
||||||
"viewPath": null,
|
|
||||||
"keepAlive": false,
|
|
||||||
"isShow": true,
|
|
||||||
"childMenus": []
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "用户列表",
|
|
||||||
"router": "/sys/user",
|
|
||||||
"perms": null,
|
|
||||||
"type": 1,
|
|
||||||
"icon": "icon-user",
|
|
||||||
"orderNum": 0,
|
|
||||||
"viewPath": "modules/base/views/user/index.vue",
|
|
||||||
"keepAlive": true,
|
|
||||||
"isShow": true,
|
|
||||||
"childMenus": [
|
|
||||||
{
|
|
||||||
"name": "部门列表",
|
|
||||||
"router": null,
|
|
||||||
"perms": "base:sys:department:list",
|
|
||||||
"type": 2,
|
|
||||||
"icon": null,
|
|
||||||
"orderNum": 0,
|
|
||||||
"viewPath": null,
|
|
||||||
"keepAlive": true,
|
|
||||||
"isShow": true,
|
|
||||||
"childMenus": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "新增部门",
|
|
||||||
"router": null,
|
|
||||||
"perms": "base:sys:department:add",
|
|
||||||
"type": 2,
|
|
||||||
"icon": null,
|
|
||||||
"orderNum": 0,
|
|
||||||
"viewPath": null,
|
|
||||||
"keepAlive": true,
|
|
||||||
"isShow": true,
|
|
||||||
"childMenus": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "更新部门",
|
|
||||||
"router": null,
|
|
||||||
"perms": "base:sys:department:update",
|
|
||||||
"type": 2,
|
|
||||||
"icon": null,
|
|
||||||
"orderNum": 0,
|
|
||||||
"viewPath": null,
|
|
||||||
"keepAlive": true,
|
|
||||||
"isShow": true,
|
|
||||||
"childMenus": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "删除部门",
|
|
||||||
"router": null,
|
|
||||||
"perms": "base:sys:department:delete",
|
|
||||||
"type": 2,
|
|
||||||
"icon": null,
|
|
||||||
"orderNum": 0,
|
|
||||||
"viewPath": null,
|
|
||||||
"keepAlive": true,
|
|
||||||
"isShow": true,
|
|
||||||
"childMenus": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "部门排序",
|
|
||||||
"router": null,
|
|
||||||
"perms": "base:sys:department:order",
|
|
||||||
"type": 2,
|
|
||||||
"icon": null,
|
|
||||||
"orderNum": 0,
|
|
||||||
"viewPath": null,
|
|
||||||
"keepAlive": true,
|
|
||||||
"isShow": true,
|
|
||||||
"childMenus": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "用户转移",
|
|
||||||
"router": null,
|
|
||||||
"perms": "base:sys:user:move",
|
|
||||||
"type": 2,
|
|
||||||
"icon": null,
|
|
||||||
"orderNum": 0,
|
|
||||||
"viewPath": null,
|
|
||||||
"keepAlive": true,
|
|
||||||
"isShow": true,
|
|
||||||
"childMenus": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "新增",
|
|
||||||
"router": null,
|
|
||||||
"perms": "base:sys:user:add",
|
|
||||||
"type": 2,
|
|
||||||
"icon": null,
|
|
||||||
"orderNum": 0,
|
|
||||||
"viewPath": null,
|
|
||||||
"keepAlive": true,
|
|
||||||
"isShow": true,
|
|
||||||
"childMenus": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "删除",
|
|
||||||
"router": null,
|
|
||||||
"perms": "base:sys:user:delete",
|
|
||||||
"type": 2,
|
|
||||||
"icon": null,
|
|
||||||
"orderNum": 0,
|
|
||||||
"viewPath": null,
|
|
||||||
"keepAlive": true,
|
|
||||||
"isShow": true,
|
|
||||||
"childMenus": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "修改",
|
|
||||||
"router": null,
|
|
||||||
"perms": "base:sys:user:delete,base:sys:user:update",
|
|
||||||
"type": 2,
|
|
||||||
"icon": null,
|
|
||||||
"orderNum": 0,
|
|
||||||
"viewPath": null,
|
|
||||||
"keepAlive": true,
|
|
||||||
"isShow": true,
|
|
||||||
"childMenus": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "查询",
|
|
||||||
"router": null,
|
|
||||||
"perms": "base:sys:user:page,base:sys:user:list,base:sys:user:info",
|
|
||||||
"type": 2,
|
|
||||||
"icon": null,
|
|
||||||
"orderNum": 0,
|
|
||||||
"viewPath": null,
|
|
||||||
"keepAlive": true,
|
|
||||||
"isShow": true,
|
|
||||||
"childMenus": []
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "参数配置",
|
|
||||||
"router": null,
|
|
||||||
"perms": null,
|
|
||||||
"type": 0,
|
|
||||||
"icon": "icon-params",
|
|
||||||
"orderNum": 3,
|
|
||||||
"viewPath": null,
|
|
||||||
"keepAlive": true,
|
|
||||||
"isShow": true,
|
|
||||||
"childMenus": [
|
|
||||||
{
|
|
||||||
"name": "参数列表",
|
|
||||||
"router": "/sys/param",
|
|
||||||
"perms": null,
|
|
||||||
"type": 1,
|
|
||||||
"icon": "icon-menu",
|
|
||||||
"orderNum": 0,
|
|
||||||
"viewPath": "cool/modules/base/views/param.vue",
|
|
||||||
"keepAlive": true,
|
|
||||||
"isShow": true,
|
|
||||||
"childMenus": [
|
|
||||||
{
|
|
||||||
"name": "新增",
|
|
||||||
"router": null,
|
|
||||||
"perms": "base:sys:param:add",
|
|
||||||
"type": 2,
|
|
||||||
"icon": null,
|
|
||||||
"orderNum": 0,
|
|
||||||
"viewPath": null,
|
|
||||||
"keepAlive": true,
|
|
||||||
"isShow": true,
|
|
||||||
"childMenus": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "修改",
|
|
||||||
"router": null,
|
|
||||||
"perms": "base:sys:param:info,base:sys:param:update",
|
|
||||||
"type": 2,
|
|
||||||
"icon": null,
|
|
||||||
"orderNum": 0,
|
|
||||||
"viewPath": null,
|
|
||||||
"keepAlive": true,
|
|
||||||
"isShow": true,
|
|
||||||
"childMenus": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "删除",
|
|
||||||
"router": null,
|
|
||||||
"perms": "base:sys:param:delete",
|
|
||||||
"type": 2,
|
|
||||||
"icon": null,
|
|
||||||
"orderNum": 0,
|
|
||||||
"viewPath": null,
|
|
||||||
"keepAlive": true,
|
|
||||||
"isShow": true,
|
|
||||||
"childMenus": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "查看",
|
|
||||||
"router": null,
|
|
||||||
"perms": "base:sys:param:page,base:sys:param:list,base:sys:param:info",
|
|
||||||
"type": 2,
|
|
||||||
"icon": null,
|
|
||||||
"orderNum": 0,
|
|
||||||
"viewPath": null,
|
|
||||||
"keepAlive": true,
|
|
||||||
"isShow": true,
|
|
||||||
"childMenus": []
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "监控管理",
|
|
||||||
"router": null,
|
|
||||||
"perms": null,
|
|
||||||
"type": 0,
|
|
||||||
"icon": "icon-monitor",
|
|
||||||
"orderNum": 9,
|
|
||||||
"viewPath": null,
|
|
||||||
"keepAlive": true,
|
|
||||||
"isShow": true,
|
|
||||||
"childMenus": [
|
|
||||||
{
|
|
||||||
"name": "请求日志",
|
|
||||||
"router": "/sys/log",
|
|
||||||
"perms": null,
|
|
||||||
"type": 1,
|
|
||||||
"icon": "icon-log",
|
|
||||||
"orderNum": 1,
|
|
||||||
"viewPath": "cool/modules/base/views/log.vue",
|
|
||||||
"keepAlive": true,
|
|
||||||
"isShow": true,
|
|
||||||
"childMenus": [
|
|
||||||
{
|
|
||||||
"name": "权限",
|
|
||||||
"router": null,
|
|
||||||
"perms": "base:sys:log:page,base:sys:log:clear,base:sys:log:getKeep,base:sys:log:setKeep",
|
|
||||||
"type": 2,
|
|
||||||
"icon": null,
|
|
||||||
"orderNum": 1,
|
|
||||||
"viewPath": null,
|
|
||||||
"keepAlive": false,
|
|
||||||
"isShow": true,
|
|
||||||
"childMenus": []
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "任务管理",
|
|
||||||
"router": null,
|
|
||||||
"perms": null,
|
|
||||||
"type": 0,
|
|
||||||
"icon": "icon-activity",
|
|
||||||
"orderNum": 9,
|
|
||||||
"viewPath": null,
|
|
||||||
"keepAlive": true,
|
|
||||||
"isShow": true,
|
|
||||||
"childMenus": [
|
|
||||||
{
|
|
||||||
"name": "任务列表",
|
|
||||||
"router": "/task/list",
|
|
||||||
"perms": null,
|
|
||||||
"type": 1,
|
|
||||||
"icon": "icon-menu",
|
|
||||||
"orderNum": 0,
|
|
||||||
"viewPath": "modules/task/views/list.vue",
|
|
||||||
"keepAlive": true,
|
|
||||||
"isShow": true,
|
|
||||||
"childMenus": [
|
|
||||||
{
|
|
||||||
"name": "权限",
|
|
||||||
"router": null,
|
|
||||||
"perms": "task:info:page,task:info:list,task:info:info,task:info:add,task:info:delete,task:info:update,task:info:stop,task:info:start,task:info:once,task:info:log",
|
|
||||||
"type": 2,
|
|
||||||
"icon": null,
|
|
||||||
"orderNum": 0,
|
|
||||||
"viewPath": null,
|
|
||||||
"keepAlive": true,
|
|
||||||
"isShow": true,
|
|
||||||
"childMenus": []
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "框架教程",
|
|
||||||
"router": "/tutorial",
|
|
||||||
"perms": null,
|
|
||||||
"type": 0,
|
|
||||||
"icon": "icon-task",
|
|
||||||
"orderNum": 98,
|
|
||||||
"viewPath": null,
|
|
||||||
"keepAlive": true,
|
|
||||||
"isShow": true,
|
|
||||||
"childMenus": [
|
|
||||||
{
|
|
||||||
"name": "文档官网",
|
|
||||||
"router": "/tutorial/doc",
|
|
||||||
"perms": null,
|
|
||||||
"type": 1,
|
|
||||||
"icon": "icon-log",
|
|
||||||
"orderNum": 0,
|
|
||||||
"viewPath": "https://admin.cool-js.com",
|
|
||||||
"keepAlive": true,
|
|
||||||
"isShow": true,
|
|
||||||
"childMenus": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "crud 示例",
|
|
||||||
"router": "/demo/crud",
|
|
||||||
"perms": null,
|
|
||||||
"type": 1,
|
|
||||||
"icon": "icon-favor",
|
|
||||||
"orderNum": 1,
|
|
||||||
"viewPath": "modules/demo/views/crud/index.vue",
|
|
||||||
"keepAlive": true,
|
|
||||||
"isShow": true,
|
|
||||||
"childMenus": []
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "通用",
|
|
||||||
"router": null,
|
|
||||||
"perms": null,
|
|
||||||
"type": 0,
|
|
||||||
"icon": "icon-radioboxfill",
|
|
||||||
"orderNum": 99,
|
|
||||||
"viewPath": null,
|
|
||||||
"keepAlive": true,
|
|
||||||
"isShow": false,
|
|
||||||
"childMenus": [
|
|
||||||
{
|
|
||||||
"name": "图片上传",
|
|
||||||
"router": null,
|
|
||||||
"perms": "space:info:page,space:info:list,space:info:info,space:info:add,space:info:delete,space:info:update,space:type:page,space:type:list,space:type:info,space:type:add,space:type:delete,space:type:update",
|
|
||||||
"type": 2,
|
|
||||||
"icon": null,
|
|
||||||
"orderNum": 1,
|
|
||||||
"viewPath": null,
|
|
||||||
"keepAlive": true,
|
|
||||||
"isShow": true,
|
|
||||||
"childMenus": []
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "首页",
|
|
||||||
"router": "/",
|
|
||||||
"perms": null,
|
|
||||||
"type": 1,
|
|
||||||
"icon": null,
|
|
||||||
"orderNum": 0,
|
|
||||||
"viewPath": "modules/demo/views/home/index.vue",
|
|
||||||
"keepAlive": true,
|
|
||||||
"isShow": false,
|
|
||||||
"childMenus": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "数据管理",
|
|
||||||
"router": null,
|
|
||||||
"perms": null,
|
|
||||||
"type": 0,
|
|
||||||
"icon": "icon-data",
|
|
||||||
"orderNum": 7,
|
|
||||||
"viewPath": null,
|
|
||||||
"keepAlive": true,
|
|
||||||
"isShow": true,
|
|
||||||
"childMenus": [
|
|
||||||
{
|
|
||||||
"name": "字典管理",
|
|
||||||
"router": "/dict/list",
|
|
||||||
"perms": null,
|
|
||||||
"type": 1,
|
|
||||||
"icon": "icon-dict",
|
|
||||||
"orderNum": 3,
|
|
||||||
"viewPath": "modules/dict/views/list.vue",
|
|
||||||
"keepAlive": true,
|
|
||||||
"isShow": true,
|
|
||||||
"childMenus": [
|
|
||||||
{
|
|
||||||
"name": "删除",
|
|
||||||
"router": null,
|
|
||||||
"perms": "dict:info:delete",
|
|
||||||
"type": 2,
|
|
||||||
"icon": null,
|
|
||||||
"orderNum": 0,
|
|
||||||
"viewPath": null,
|
|
||||||
"keepAlive": true,
|
|
||||||
"isShow": true,
|
|
||||||
"childMenus": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "修改",
|
|
||||||
"router": null,
|
|
||||||
"perms": "dict:info:update,dict:info:info",
|
|
||||||
"type": 2,
|
|
||||||
"icon": null,
|
|
||||||
"orderNum": 0,
|
|
||||||
"viewPath": null,
|
|
||||||
"keepAlive": true,
|
|
||||||
"isShow": true,
|
|
||||||
"childMenus": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "获得字典数据",
|
|
||||||
"router": null,
|
|
||||||
"perms": "dict:info:data",
|
|
||||||
"type": 2,
|
|
||||||
"icon": null,
|
|
||||||
"orderNum": 0,
|
|
||||||
"viewPath": null,
|
|
||||||
"keepAlive": true,
|
|
||||||
"isShow": true,
|
|
||||||
"childMenus": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "单个信息",
|
|
||||||
"router": null,
|
|
||||||
"perms": "dict:info:info",
|
|
||||||
"type": 2,
|
|
||||||
"icon": null,
|
|
||||||
"orderNum": 0,
|
|
||||||
"viewPath": null,
|
|
||||||
"keepAlive": true,
|
|
||||||
"isShow": true,
|
|
||||||
"childMenus": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "列表查询",
|
|
||||||
"router": null,
|
|
||||||
"perms": "dict:info:list",
|
|
||||||
"type": 2,
|
|
||||||
"icon": null,
|
|
||||||
"orderNum": 0,
|
|
||||||
"viewPath": null,
|
|
||||||
"keepAlive": true,
|
|
||||||
"isShow": true,
|
|
||||||
"childMenus": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "分页查询",
|
|
||||||
"router": null,
|
|
||||||
"perms": "dict:info:page",
|
|
||||||
"type": 2,
|
|
||||||
"icon": null,
|
|
||||||
"orderNum": 0,
|
|
||||||
"viewPath": null,
|
|
||||||
"keepAlive": true,
|
|
||||||
"isShow": true,
|
|
||||||
"childMenus": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "新增",
|
|
||||||
"router": null,
|
|
||||||
"perms": "dict:info:add",
|
|
||||||
"type": 2,
|
|
||||||
"icon": null,
|
|
||||||
"orderNum": 0,
|
|
||||||
"viewPath": null,
|
|
||||||
"keepAlive": true,
|
|
||||||
"isShow": true,
|
|
||||||
"childMenus": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "组权限",
|
|
||||||
"router": null,
|
|
||||||
"perms": "dict:type:list,dict:type:update,dict:type:delete,dict:type:add",
|
|
||||||
"type": 2,
|
|
||||||
"icon": null,
|
|
||||||
"orderNum": 0,
|
|
||||||
"viewPath": null,
|
|
||||||
"keepAlive": true,
|
|
||||||
"isShow": true,
|
|
||||||
"childMenus": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "字典类型",
|
|
||||||
"router": null,
|
|
||||||
"perms": "dict:type:delete,dict:type:update,dict:type:info,dict:type:list,dict:type:page,dict:type:add",
|
|
||||||
"type": 2,
|
|
||||||
"icon": null,
|
|
||||||
"orderNum": 0,
|
|
||||||
"viewPath": null,
|
|
||||||
"keepAlive": true,
|
|
||||||
"isShow": true,
|
|
||||||
"childMenus": []
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "数据回收站",
|
|
||||||
"router": "/recycle/data",
|
|
||||||
"perms": null,
|
|
||||||
"type": 1,
|
|
||||||
"icon": "icon-delete",
|
|
||||||
"orderNum": 6,
|
|
||||||
"viewPath": "modules/recycle/views/data.vue",
|
|
||||||
"keepAlive": true,
|
|
||||||
"isShow": true,
|
|
||||||
"childMenus": [
|
|
||||||
{
|
|
||||||
"name": "恢复数据",
|
|
||||||
"router": null,
|
|
||||||
"perms": "recycle:data:restore",
|
|
||||||
"type": 2,
|
|
||||||
"icon": null,
|
|
||||||
"orderNum": 0,
|
|
||||||
"viewPath": null,
|
|
||||||
"keepAlive": true,
|
|
||||||
"isShow": true,
|
|
||||||
"childMenus": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "单个信息",
|
|
||||||
"router": null,
|
|
||||||
"perms": "recycle:data:info",
|
|
||||||
"type": 2,
|
|
||||||
"icon": null,
|
|
||||||
"orderNum": 0,
|
|
||||||
"viewPath": null,
|
|
||||||
"keepAlive": true,
|
|
||||||
"isShow": true,
|
|
||||||
"childMenus": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "分页查询",
|
|
||||||
"router": null,
|
|
||||||
"perms": "recycle:data:page",
|
|
||||||
"type": 2,
|
|
||||||
"icon": null,
|
|
||||||
"orderNum": 0,
|
|
||||||
"viewPath": null,
|
|
||||||
"keepAlive": true,
|
|
||||||
"isShow": true,
|
|
||||||
"childMenus": []
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "文件管理",
|
|
||||||
"router": "/upload/list",
|
|
||||||
"perms": null,
|
|
||||||
"type": 1,
|
|
||||||
"icon": "icon-log",
|
|
||||||
"orderNum": 5,
|
|
||||||
"viewPath": "modules/space/views/list.vue",
|
|
||||||
"keepAlive": true,
|
|
||||||
"isShow": true,
|
|
||||||
"childMenus": [
|
|
||||||
{
|
|
||||||
"name": "权限",
|
|
||||||
"router": null,
|
|
||||||
"perms": "space:type:delete,space:type:update,space:type:info,space:type:list,space:type:page,space:type:add,space:info:getConfig,space:info:delete,space:info:update,space:info:info,space:info:list,space:info:page,space:info:add",
|
|
||||||
"type": 2,
|
|
||||||
"icon": null,
|
|
||||||
"orderNum": 0,
|
|
||||||
"viewPath": null,
|
|
||||||
"keepAlive": true,
|
|
||||||
"isShow": true,
|
|
||||||
"childMenus": []
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "用户管理",
|
|
||||||
"router": null,
|
|
||||||
"perms": null,
|
|
||||||
"type": 0,
|
|
||||||
"icon": "icon-user",
|
|
||||||
"orderNum": 11,
|
|
||||||
"viewPath": null,
|
|
||||||
"keepAlive": true,
|
|
||||||
"isShow": true,
|
|
||||||
"childMenus": [
|
|
||||||
{
|
|
||||||
"name": "用户列表",
|
|
||||||
"router": "/user/list",
|
|
||||||
"perms": null,
|
|
||||||
"type": 1,
|
|
||||||
"icon": "icon-menu",
|
|
||||||
"orderNum": 1,
|
|
||||||
"viewPath": "modules/user/views/list.vue",
|
|
||||||
"keepAlive": true,
|
|
||||||
"isShow": true,
|
|
||||||
"childMenus": [
|
|
||||||
{
|
|
||||||
"name": "删除",
|
|
||||||
"router": null,
|
|
||||||
"perms": "user:info:delete",
|
|
||||||
"type": 2,
|
|
||||||
"icon": null,
|
|
||||||
"orderNum": 0,
|
|
||||||
"viewPath": null,
|
|
||||||
"keepAlive": true,
|
|
||||||
"isShow": true,
|
|
||||||
"childMenus": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "修改",
|
|
||||||
"router": null,
|
|
||||||
"perms": "user:info:update,user:info:info",
|
|
||||||
"type": 2,
|
|
||||||
"icon": null,
|
|
||||||
"orderNum": 0,
|
|
||||||
"viewPath": null,
|
|
||||||
"keepAlive": true,
|
|
||||||
"isShow": true,
|
|
||||||
"childMenus": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "单个信息",
|
|
||||||
"router": null,
|
|
||||||
"perms": "user:info:info",
|
|
||||||
"type": 2,
|
|
||||||
"icon": null,
|
|
||||||
"orderNum": 0,
|
|
||||||
"viewPath": null,
|
|
||||||
"keepAlive": true,
|
|
||||||
"isShow": true,
|
|
||||||
"childMenus": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "列表查询",
|
|
||||||
"router": null,
|
|
||||||
"perms": "user:info:list",
|
|
||||||
"type": 2,
|
|
||||||
"icon": null,
|
|
||||||
"orderNum": 0,
|
|
||||||
"viewPath": null,
|
|
||||||
"keepAlive": true,
|
|
||||||
"isShow": true,
|
|
||||||
"childMenus": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "分页查询",
|
|
||||||
"router": null,
|
|
||||||
"perms": "user:info:page",
|
|
||||||
"type": 2,
|
|
||||||
"icon": null,
|
|
||||||
"orderNum": 0,
|
|
||||||
"viewPath": null,
|
|
||||||
"keepAlive": true,
|
|
||||||
"isShow": true,
|
|
||||||
"childMenus": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "新增",
|
|
||||||
"router": null,
|
|
||||||
"perms": "user:info:add",
|
|
||||||
"type": 2,
|
|
||||||
"icon": null,
|
|
||||||
"orderNum": 0,
|
|
||||||
"viewPath": null,
|
|
||||||
"keepAlive": true,
|
|
||||||
"isShow": true,
|
|
||||||
"childMenus": []
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "扩展管理",
|
|
||||||
"router": null,
|
|
||||||
"perms": null,
|
|
||||||
"type": 0,
|
|
||||||
"icon": "icon-favor",
|
|
||||||
"orderNum": 8,
|
|
||||||
"viewPath": null,
|
|
||||||
"keepAlive": true,
|
|
||||||
"isShow": true,
|
|
||||||
"childMenus": [
|
|
||||||
{
|
|
||||||
"name": "后端插件",
|
|
||||||
"router": "/helper/plugins/serve",
|
|
||||||
"perms": null,
|
|
||||||
"type": 1,
|
|
||||||
"icon": "icon-component",
|
|
||||||
"orderNum": 2,
|
|
||||||
"viewPath": "modules/helper/views/plugins/serve.vue",
|
|
||||||
"keepAlive": true,
|
|
||||||
"isShow": true,
|
|
||||||
"childMenus": [
|
|
||||||
{
|
|
||||||
"name": "权限",
|
|
||||||
"router": null,
|
|
||||||
"perms": "plugin:info:install,plugin:info:delete,plugin:info:update,plugin:info:page,plugin:info:info",
|
|
||||||
"type": 2,
|
|
||||||
"icon": null,
|
|
||||||
"orderNum": 0,
|
|
||||||
"viewPath": null,
|
|
||||||
"keepAlive": true,
|
|
||||||
"isShow": true,
|
|
||||||
"childMenus": []
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "前端插件",
|
|
||||||
"router": "/helper/plugins/vue",
|
|
||||||
"perms": null,
|
|
||||||
"type": 1,
|
|
||||||
"icon": "icon-vue",
|
|
||||||
"orderNum": 1,
|
|
||||||
"viewPath": "modules/helper/views/plugins/vue.vue",
|
|
||||||
"keepAlive": true,
|
|
||||||
"isShow": true,
|
|
||||||
"childMenus": []
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
@ -1,185 +0,0 @@
|
|||||||
import { App, Config, Inject, Middleware } from '@midwayjs/decorator';
|
|
||||||
import * as _ from 'lodash';
|
|
||||||
import { CoolUrlTagData, RESCODE, TagTypes } from '@cool-midway/core';
|
|
||||||
import * as jwt from 'jsonwebtoken';
|
|
||||||
import { NextFunction, Context } from '@midwayjs/koa';
|
|
||||||
import {
|
|
||||||
IMiddleware,
|
|
||||||
IMidwayApplication,
|
|
||||||
Init,
|
|
||||||
InjectClient,
|
|
||||||
} from '@midwayjs/core';
|
|
||||||
import { CachingFactory, MidwayCache } from '@midwayjs/cache-manager';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 权限校验
|
|
||||||
*/
|
|
||||||
@Middleware()
|
|
||||||
export class BaseAuthorityMiddleware
|
|
||||||
implements IMiddleware<Context, NextFunction>
|
|
||||||
{
|
|
||||||
@Config('koa.globalPrefix')
|
|
||||||
prefix;
|
|
||||||
|
|
||||||
@Config('module.base')
|
|
||||||
jwtConfig;
|
|
||||||
|
|
||||||
@InjectClient(CachingFactory, 'default')
|
|
||||||
midwayCache: MidwayCache;
|
|
||||||
|
|
||||||
@Inject()
|
|
||||||
coolUrlTagData: CoolUrlTagData;
|
|
||||||
|
|
||||||
@App()
|
|
||||||
app: IMidwayApplication;
|
|
||||||
|
|
||||||
ignoreUrls: string[] = [];
|
|
||||||
|
|
||||||
@Init()
|
|
||||||
async init() {
|
|
||||||
this.ignoreUrls = this.coolUrlTagData.byKey(TagTypes.IGNORE_TOKEN, 'admin');
|
|
||||||
}
|
|
||||||
|
|
||||||
resolve() {
|
|
||||||
return async (ctx: Context, next: NextFunction) => {
|
|
||||||
let statusCode = 200;
|
|
||||||
let { url } = ctx;
|
|
||||||
url = url.replace(this.prefix, '').split('?')[0];
|
|
||||||
const token = ctx.get('Authorization');
|
|
||||||
const adminUrl = '/admin/';
|
|
||||||
// 路由地址为 admin前缀的 需要权限校验
|
|
||||||
if (_.startsWith(url, adminUrl)) {
|
|
||||||
try {
|
|
||||||
ctx.admin = jwt.verify(token, this.jwtConfig.jwt.secret);
|
|
||||||
if (ctx.admin.isRefresh) {
|
|
||||||
ctx.status = 401;
|
|
||||||
ctx.body = {
|
|
||||||
code: RESCODE.COMMFAIL,
|
|
||||||
message: '登录失效~',
|
|
||||||
};
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} catch (error) {}
|
|
||||||
// 使用matchUrl方法来检查URL是否应该被忽略
|
|
||||||
const isIgnored = this.ignoreUrls.some(pattern =>
|
|
||||||
this.matchUrl(pattern, url)
|
|
||||||
);
|
|
||||||
if (isIgnored) {
|
|
||||||
await next();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (ctx.admin) {
|
|
||||||
const rToken = await this.midwayCache.get(
|
|
||||||
`admin:token:${ctx.admin.userId}`
|
|
||||||
);
|
|
||||||
// 判断密码版本是否正确
|
|
||||||
const passwordV = await this.midwayCache.get(
|
|
||||||
`admin:passwordVersion:${ctx.admin.userId}`
|
|
||||||
);
|
|
||||||
if (passwordV != ctx.admin.passwordVersion) {
|
|
||||||
ctx.status = 401;
|
|
||||||
ctx.body = {
|
|
||||||
code: RESCODE.COMMFAIL,
|
|
||||||
message: '登录失效~',
|
|
||||||
};
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// 超管拥有所有权限
|
|
||||||
if (ctx.admin.username == 'admin' && !ctx.admin.isRefresh) {
|
|
||||||
if (rToken !== token && this.jwtConfig.jwt.sso) {
|
|
||||||
ctx.status = 401;
|
|
||||||
ctx.body = {
|
|
||||||
code: RESCODE.COMMFAIL,
|
|
||||||
message: '登录失效~',
|
|
||||||
};
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
await next();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 要登录每个人都有权限的接口
|
|
||||||
if (
|
|
||||||
new RegExp(`^${adminUrl}?.*/comm/`).test(url) ||
|
|
||||||
// 字典接口
|
|
||||||
url == '/admin/dict/info/data'
|
|
||||||
) {
|
|
||||||
await next();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// 如果传的token是refreshToken则校验失败
|
|
||||||
if (ctx.admin.isRefresh) {
|
|
||||||
ctx.status = 401;
|
|
||||||
ctx.body = {
|
|
||||||
code: RESCODE.COMMFAIL,
|
|
||||||
message: '登录失效~',
|
|
||||||
};
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!rToken) {
|
|
||||||
ctx.status = 401;
|
|
||||||
ctx.body = {
|
|
||||||
code: RESCODE.COMMFAIL,
|
|
||||||
message: '登录失效或无权限访问~',
|
|
||||||
};
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (rToken !== token && this.jwtConfig.jwt.sso) {
|
|
||||||
statusCode = 401;
|
|
||||||
} else {
|
|
||||||
let perms: string[] = await this.midwayCache.get(
|
|
||||||
`admin:perms:${ctx.admin.userId}`
|
|
||||||
);
|
|
||||||
if (!_.isEmpty(perms)) {
|
|
||||||
perms = perms.map(e => {
|
|
||||||
return e.replace(/:/g, '/');
|
|
||||||
});
|
|
||||||
if (!perms.includes(url.split('?')[0].replace('/admin/', ''))) {
|
|
||||||
statusCode = 403;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
statusCode = 403;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
statusCode = 401;
|
|
||||||
}
|
|
||||||
if (statusCode > 200) {
|
|
||||||
ctx.status = statusCode;
|
|
||||||
ctx.body = {
|
|
||||||
code: RESCODE.COMMFAIL,
|
|
||||||
message: '登录失效或无权限访问~',
|
|
||||||
};
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
await next();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// 匹配URL的方法
|
|
||||||
matchUrl(pattern, url) {
|
|
||||||
const patternSegments = pattern.split('/').filter(Boolean);
|
|
||||||
const urlSegments = url.split('/').filter(Boolean);
|
|
||||||
|
|
||||||
// 如果段的数量不同,则无法匹配
|
|
||||||
if (patternSegments.length !== urlSegments.length) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 逐段进行匹配
|
|
||||||
for (let i = 0; i < patternSegments.length; i++) {
|
|
||||||
if (patternSegments[i].startsWith(':')) {
|
|
||||||
// 如果模式段以':'开始,我们认为它是一个参数,可以匹配任何内容
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// 如果两个段不相同,则不匹配
|
|
||||||
if (patternSegments[i] !== urlSegments[i]) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 所有段都匹配
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,26 +0,0 @@
|
|||||||
import { Middleware } from '@midwayjs/decorator';
|
|
||||||
import * as _ from 'lodash';
|
|
||||||
import { NextFunction, Context } from '@midwayjs/koa';
|
|
||||||
import { IMiddleware } from '@midwayjs/core';
|
|
||||||
import { BaseSysLogService } from '../service/sys/log';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 日志中间件
|
|
||||||
*/
|
|
||||||
@Middleware()
|
|
||||||
export class BaseLogMiddleware implements IMiddleware<Context, NextFunction> {
|
|
||||||
resolve() {
|
|
||||||
return async (ctx: Context, next: NextFunction) => {
|
|
||||||
const baseSysLogService = await ctx.requestContext.getAsync(
|
|
||||||
BaseSysLogService
|
|
||||||
);
|
|
||||||
baseSysLogService.record(
|
|
||||||
ctx,
|
|
||||||
ctx.url,
|
|
||||||
ctx.req.method === 'GET' ? ctx.request.query : ctx.request.body,
|
|
||||||
ctx.admin ? ctx.admin.userId : null
|
|
||||||
);
|
|
||||||
await next();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,39 +0,0 @@
|
|||||||
import { Provide } from '@midwayjs/decorator';
|
|
||||||
import { BaseService } from '@cool-midway/core';
|
|
||||||
import { InjectEntityModel } from '@midwayjs/typeorm';
|
|
||||||
import { Repository } from 'typeorm';
|
|
||||||
import { BaseSysConfEntity } from '../../entity/sys/conf';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 系统配置
|
|
||||||
*/
|
|
||||||
@Provide()
|
|
||||||
export class BaseSysConfService extends BaseService {
|
|
||||||
@InjectEntityModel(BaseSysConfEntity)
|
|
||||||
baseSysConfEntity: Repository<BaseSysConfEntity>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获得配置参数值
|
|
||||||
* @param key
|
|
||||||
*/
|
|
||||||
async getValue(key) {
|
|
||||||
const conf = await this.baseSysConfEntity.findOneBy({ cKey: key });
|
|
||||||
if (conf) {
|
|
||||||
return conf.cValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新配置参数
|
|
||||||
* @param cKey
|
|
||||||
* @param cValue
|
|
||||||
*/
|
|
||||||
async updateVaule(cKey, cValue) {
|
|
||||||
await this.baseSysConfEntity
|
|
||||||
.createQueryBuilder()
|
|
||||||
.update()
|
|
||||||
.where({ cKey })
|
|
||||||
.set({ cKey, cValue })
|
|
||||||
.execute();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,10 +0,0 @@
|
|||||||
import { DataSource } from 'typeorm';
|
|
||||||
|
|
||||||
export class TempDataSource extends DataSource {
|
|
||||||
/**
|
|
||||||
* 重新构造元数据
|
|
||||||
*/
|
|
||||||
async buildMetadatas() {
|
|
||||||
await super.buildMetadatas();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,124 +0,0 @@
|
|||||||
import { Inject, Provide } from '@midwayjs/decorator';
|
|
||||||
import { BaseService } from '@cool-midway/core';
|
|
||||||
import { InjectEntityModel } from '@midwayjs/typeorm';
|
|
||||||
import { In, Repository } from 'typeorm';
|
|
||||||
import { BaseSysDepartmentEntity } from '../../entity/sys/department';
|
|
||||||
import * as _ from 'lodash';
|
|
||||||
import { BaseSysRoleDepartmentEntity } from '../../entity/sys/role_department';
|
|
||||||
import { BaseSysPermsService } from './perms';
|
|
||||||
import { BaseSysUserEntity } from '../../entity/sys/user';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 描述
|
|
||||||
*/
|
|
||||||
@Provide()
|
|
||||||
export class BaseSysDepartmentService extends BaseService {
|
|
||||||
@InjectEntityModel(BaseSysDepartmentEntity)
|
|
||||||
baseSysDepartmentEntity: Repository<BaseSysDepartmentEntity>;
|
|
||||||
|
|
||||||
@InjectEntityModel(BaseSysUserEntity)
|
|
||||||
baseSysUserEntity: Repository<BaseSysUserEntity>;
|
|
||||||
|
|
||||||
@InjectEntityModel(BaseSysRoleDepartmentEntity)
|
|
||||||
baseSysRoleDepartmentEntity: Repository<BaseSysRoleDepartmentEntity>;
|
|
||||||
|
|
||||||
@Inject()
|
|
||||||
baseSysPermsService: BaseSysPermsService;
|
|
||||||
|
|
||||||
@Inject()
|
|
||||||
ctx;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获得部门菜单
|
|
||||||
*/
|
|
||||||
async list() {
|
|
||||||
// 部门权限
|
|
||||||
const permsDepartmentArr = await this.baseSysPermsService.departmentIds(
|
|
||||||
this.ctx.admin.userId
|
|
||||||
);
|
|
||||||
|
|
||||||
// 过滤部门权限
|
|
||||||
const find = this.baseSysDepartmentEntity.createQueryBuilder('a');
|
|
||||||
if (this.ctx.admin.username !== 'admin')
|
|
||||||
find.andWhere('a.id in (:...ids)', {
|
|
||||||
ids: !_.isEmpty(permsDepartmentArr) ? permsDepartmentArr : [null],
|
|
||||||
});
|
|
||||||
find.addOrderBy('a.orderNum', 'ASC');
|
|
||||||
const departments: BaseSysDepartmentEntity[] = await find.getMany();
|
|
||||||
|
|
||||||
if (!_.isEmpty(departments)) {
|
|
||||||
departments.forEach(e => {
|
|
||||||
const parentMenu = departments.filter(m => {
|
|
||||||
e.parentId = parseInt(e.parentId + '');
|
|
||||||
if (e.parentId == m.id) {
|
|
||||||
return m.name;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (!_.isEmpty(parentMenu)) {
|
|
||||||
e.parentName = parentMenu[0].name;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return departments;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据多个ID获得部门权限信息
|
|
||||||
* @param {[]} roleIds 数组
|
|
||||||
* @param isAdmin 是否超管
|
|
||||||
*/
|
|
||||||
async getByRoleIds(roleIds: number[], isAdmin) {
|
|
||||||
if (!_.isEmpty(roleIds)) {
|
|
||||||
if (isAdmin) {
|
|
||||||
const result = await this.baseSysDepartmentEntity.find();
|
|
||||||
return result.map(e => {
|
|
||||||
return e.id;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
const result = await this.baseSysRoleDepartmentEntity
|
|
||||||
.createQueryBuilder('a')
|
|
||||||
.where('a.roleId in (:...roleIds)', { roleIds })
|
|
||||||
.getMany();
|
|
||||||
if (!_.isEmpty(result)) {
|
|
||||||
return _.uniq(
|
|
||||||
result.map(e => {
|
|
||||||
return e.departmentId;
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 部门排序
|
|
||||||
* @param params
|
|
||||||
*/
|
|
||||||
async order(params) {
|
|
||||||
for (const e of params) {
|
|
||||||
await this.baseSysDepartmentEntity.update(e.id, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 删除
|
|
||||||
*/
|
|
||||||
async delete(ids: number[]) {
|
|
||||||
const { deleteUser } = this.ctx.request.body;
|
|
||||||
await super.delete(ids);
|
|
||||||
if (deleteUser) {
|
|
||||||
await this.baseSysUserEntity.delete({ departmentId: In(ids) });
|
|
||||||
} else {
|
|
||||||
const topDepartment = await this.baseSysDepartmentEntity
|
|
||||||
.createQueryBuilder('a')
|
|
||||||
.where('a.parentId is null')
|
|
||||||
.getOne();
|
|
||||||
if (topDepartment) {
|
|
||||||
await this.baseSysUserEntity.update(
|
|
||||||
{ departmentId: In(ids) },
|
|
||||||
{ departmentId: topDepartment.id }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,62 +0,0 @@
|
|||||||
import { Inject, Provide } from '@midwayjs/decorator';
|
|
||||||
import { BaseService } from '@cool-midway/core';
|
|
||||||
import { InjectEntityModel } from '@midwayjs/typeorm';
|
|
||||||
import { LessThan, Repository } from 'typeorm';
|
|
||||||
import * as _ from 'lodash';
|
|
||||||
import { BaseSysLogEntity } from '../../entity/sys/log';
|
|
||||||
import * as moment from 'moment';
|
|
||||||
import { Utils } from '../../../../comm/utils';
|
|
||||||
import { BaseSysConfService } from './conf';
|
|
||||||
import { Context } from '@midwayjs/koa';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 描述
|
|
||||||
*/
|
|
||||||
@Provide()
|
|
||||||
export class BaseSysLogService extends BaseService {
|
|
||||||
@Inject()
|
|
||||||
ctx;
|
|
||||||
|
|
||||||
@Inject()
|
|
||||||
utils: Utils;
|
|
||||||
|
|
||||||
@InjectEntityModel(BaseSysLogEntity)
|
|
||||||
baseSysLogEntity: Repository<BaseSysLogEntity>;
|
|
||||||
|
|
||||||
@Inject()
|
|
||||||
baseSysConfService: BaseSysConfService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 记录
|
|
||||||
* @param url URL地址
|
|
||||||
* @param params 参数
|
|
||||||
* @param userId 用户ID
|
|
||||||
*/
|
|
||||||
async record(context: Context, url, params, userId) {
|
|
||||||
const ip = await this.utils.getReqIP(context);
|
|
||||||
const sysLog = new BaseSysLogEntity();
|
|
||||||
sysLog.userId = userId;
|
|
||||||
sysLog.ip = typeof ip === 'string' ? ip : ip.join(',');
|
|
||||||
sysLog.action = url.split('?')[0];
|
|
||||||
sysLog.params = params;
|
|
||||||
await this.baseSysLogEntity.insert(sysLog);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 日志
|
|
||||||
* @param isAll 是否清除全部
|
|
||||||
*/
|
|
||||||
async clear(isAll?) {
|
|
||||||
if (isAll) {
|
|
||||||
await this.baseSysLogEntity.clear();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const keepDay = await this.baseSysConfService.getValue('logKeep');
|
|
||||||
if (keepDay) {
|
|
||||||
const beforeDate = moment().add(-keepDay, 'days').startOf('day').toDate();
|
|
||||||
await this.baseSysLogEntity.delete({ createTime: LessThan(beforeDate) });
|
|
||||||
} else {
|
|
||||||
await this.baseSysLogEntity.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,251 +0,0 @@
|
|||||||
import { Inject, Provide, Config, InjectClient } from '@midwayjs/decorator';
|
|
||||||
import { BaseService, CoolCommException } from '@cool-midway/core';
|
|
||||||
import { LoginDTO } from '../../dto/login';
|
|
||||||
import * as svgCaptcha from 'svg-captcha';
|
|
||||||
import { v1 as uuid } from 'uuid';
|
|
||||||
import { BaseSysUserEntity } from '../../entity/sys/user';
|
|
||||||
import { Repository } from 'typeorm';
|
|
||||||
import { InjectEntityModel } from '@midwayjs/typeorm';
|
|
||||||
import * as md5 from 'md5';
|
|
||||||
import { BaseSysRoleService } from './role';
|
|
||||||
import * as _ from 'lodash';
|
|
||||||
import { BaseSysMenuService } from './menu';
|
|
||||||
import { BaseSysDepartmentService } from './department';
|
|
||||||
import * as jwt from 'jsonwebtoken';
|
|
||||||
import * as svgToDataURL from 'mini-svg-data-uri';
|
|
||||||
import { Context } from '@midwayjs/koa';
|
|
||||||
import { CachingFactory, MidwayCache } from '@midwayjs/cache-manager';
|
|
||||||
import { readFileSync } from 'fs';
|
|
||||||
const { svg2png, initialize } = require('svg2png-wasm');
|
|
||||||
initialize(readFileSync('./node_modules/svg2png-wasm/svg2png_wasm_bg.wasm'));
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 登录
|
|
||||||
*/
|
|
||||||
@Provide()
|
|
||||||
export class BaseSysLoginService extends BaseService {
|
|
||||||
@InjectClient(CachingFactory, 'default')
|
|
||||||
midwayCache: MidwayCache;
|
|
||||||
|
|
||||||
@InjectEntityModel(BaseSysUserEntity)
|
|
||||||
baseSysUserEntity: Repository<BaseSysUserEntity>;
|
|
||||||
|
|
||||||
@Inject()
|
|
||||||
baseSysRoleService: BaseSysRoleService;
|
|
||||||
|
|
||||||
@Inject()
|
|
||||||
baseSysMenuService: BaseSysMenuService;
|
|
||||||
|
|
||||||
@Inject()
|
|
||||||
baseSysDepartmentService: BaseSysDepartmentService;
|
|
||||||
|
|
||||||
@Inject()
|
|
||||||
ctx: Context;
|
|
||||||
|
|
||||||
@Config('module.base')
|
|
||||||
coolConfig;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 登录
|
|
||||||
* @param login
|
|
||||||
*/
|
|
||||||
async login(login: LoginDTO) {
|
|
||||||
const { username, captchaId, verifyCode, password } = login;
|
|
||||||
// 校验验证码
|
|
||||||
const checkV = await this.captchaCheck(captchaId, verifyCode);
|
|
||||||
if (checkV) {
|
|
||||||
const user = await this.baseSysUserEntity.findOneBy({ username });
|
|
||||||
// 校验用户
|
|
||||||
if (user) {
|
|
||||||
// 校验用户状态及密码
|
|
||||||
if (user.status === 0 || user.password !== md5(password)) {
|
|
||||||
throw new CoolCommException('账户或密码不正确~');
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw new CoolCommException('账户或密码不正确~');
|
|
||||||
}
|
|
||||||
// 校验角色
|
|
||||||
const roleIds = await this.baseSysRoleService.getByUser(user.id);
|
|
||||||
if (_.isEmpty(roleIds)) {
|
|
||||||
throw new CoolCommException('该用户未设置任何角色,无法登录~');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 生成token
|
|
||||||
const { expire, refreshExpire } = this.coolConfig.jwt.token;
|
|
||||||
const result = {
|
|
||||||
expire,
|
|
||||||
token: await this.generateToken(user, roleIds, expire),
|
|
||||||
refreshExpire,
|
|
||||||
refreshToken: await this.generateToken(
|
|
||||||
user,
|
|
||||||
roleIds,
|
|
||||||
refreshExpire,
|
|
||||||
true
|
|
||||||
),
|
|
||||||
};
|
|
||||||
|
|
||||||
// 将用户相关信息保存到缓存
|
|
||||||
const perms = await this.baseSysMenuService.getPerms(roleIds);
|
|
||||||
const departments = await this.baseSysDepartmentService.getByRoleIds(
|
|
||||||
roleIds,
|
|
||||||
user.username === 'admin'
|
|
||||||
);
|
|
||||||
await this.midwayCache.set(`admin:department:${user.id}`, departments);
|
|
||||||
await this.midwayCache.set(`admin:perms:${user.id}`, perms);
|
|
||||||
await this.midwayCache.set(`admin:token:${user.id}`, result.token);
|
|
||||||
await this.midwayCache.set(
|
|
||||||
`admin:token:refresh:${user.id}`,
|
|
||||||
result.token
|
|
||||||
);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
} else {
|
|
||||||
throw new CoolCommException('验证码不正确');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 验证码
|
|
||||||
* @param type 图片验证码类型 svg
|
|
||||||
* @param width 宽
|
|
||||||
* @param height 高
|
|
||||||
*/
|
|
||||||
async captcha(type: string, width = 150, height = 50, color = '#fff') {
|
|
||||||
const svg = svgCaptcha.create({
|
|
||||||
ignoreChars: 'qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM',
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
});
|
|
||||||
const result = {
|
|
||||||
captchaId: uuid(),
|
|
||||||
data: svg.data.replace(/"/g, "'"),
|
|
||||||
};
|
|
||||||
// 文字变白
|
|
||||||
const rpList = [
|
|
||||||
'#111',
|
|
||||||
'#222',
|
|
||||||
'#333',
|
|
||||||
'#444',
|
|
||||||
'#555',
|
|
||||||
'#666',
|
|
||||||
'#777',
|
|
||||||
'#888',
|
|
||||||
'#999',
|
|
||||||
];
|
|
||||||
rpList.forEach(rp => {
|
|
||||||
result.data = result.data['replaceAll'](rp, color);
|
|
||||||
});
|
|
||||||
if (type === 'base64') {
|
|
||||||
result.data = svgToDataURL(result.data);
|
|
||||||
}
|
|
||||||
if (type === 'png') {
|
|
||||||
result.data = await svg2png(result.data, {
|
|
||||||
scale: 2, // optional
|
|
||||||
width, // optional
|
|
||||||
height, // optional
|
|
||||||
backgroundColor: 'white', // optional
|
|
||||||
});
|
|
||||||
result.data =
|
|
||||||
'data:image/png;base64,' +
|
|
||||||
Buffer.from(result.data, 'binary').toString('base64');
|
|
||||||
}
|
|
||||||
// 半小时过期
|
|
||||||
await this.midwayCache.set(
|
|
||||||
`verify:img:${result.captchaId}`,
|
|
||||||
svg.text.toLowerCase(),
|
|
||||||
1800 * 1000
|
|
||||||
);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 退出登录
|
|
||||||
*/
|
|
||||||
async logout() {
|
|
||||||
if (!this.coolConfig.jwt.sso) return;
|
|
||||||
const { userId } = this.ctx.admin;
|
|
||||||
await this.midwayCache.del(`admin:department:${userId}`);
|
|
||||||
await this.midwayCache.del(`admin:perms:${userId}`);
|
|
||||||
await this.midwayCache.del(`admin:token:${userId}`);
|
|
||||||
await this.midwayCache.del(`admin:token:refresh:${userId}`);
|
|
||||||
await this.midwayCache.del(`admin:passwordVersion:${userId}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 检验图片验证码
|
|
||||||
* @param captchaId 验证码ID
|
|
||||||
* @param value 验证码
|
|
||||||
*/
|
|
||||||
async captchaCheck(captchaId, value) {
|
|
||||||
const rv = await this.midwayCache.get(`verify:img:${captchaId}`);
|
|
||||||
if (!rv || !value || value.toLowerCase() !== rv) {
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
this.midwayCache.del(`verify:img:${captchaId}`);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 生成token
|
|
||||||
* @param user 用户对象
|
|
||||||
* @param roleIds 角色集合
|
|
||||||
* @param expire 过期
|
|
||||||
* @param isRefresh 是否是刷新
|
|
||||||
*/
|
|
||||||
async generateToken(user, roleIds, expire, isRefresh?) {
|
|
||||||
await this.midwayCache.set(
|
|
||||||
`admin:passwordVersion:${user.id}`,
|
|
||||||
user.passwordV
|
|
||||||
);
|
|
||||||
const tokenInfo = {
|
|
||||||
isRefresh: false,
|
|
||||||
roleIds,
|
|
||||||
username: user.username,
|
|
||||||
userId: user.id,
|
|
||||||
passwordVersion: user.passwordV,
|
|
||||||
};
|
|
||||||
if (isRefresh) {
|
|
||||||
tokenInfo.isRefresh = true;
|
|
||||||
}
|
|
||||||
return jwt.sign(tokenInfo, this.coolConfig.jwt.secret, {
|
|
||||||
expiresIn: expire,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 刷新token
|
|
||||||
* @param token
|
|
||||||
*/
|
|
||||||
async refreshToken(token: string) {
|
|
||||||
const decoded = jwt.verify(token, this.coolConfig.jwt.secret);
|
|
||||||
if (decoded && decoded['isRefresh']) {
|
|
||||||
delete decoded['exp'];
|
|
||||||
delete decoded['iat'];
|
|
||||||
|
|
||||||
const { expire, refreshExpire } = this.coolConfig.jwt.token;
|
|
||||||
decoded['isRefresh'] = false;
|
|
||||||
const result = {
|
|
||||||
expire,
|
|
||||||
token: jwt.sign(decoded, this.coolConfig.jwt.secret, {
|
|
||||||
expiresIn: expire,
|
|
||||||
}),
|
|
||||||
refreshExpire,
|
|
||||||
refreshToken: '',
|
|
||||||
};
|
|
||||||
decoded['isRefresh'] = true;
|
|
||||||
result.refreshToken = jwt.sign(decoded, this.coolConfig.jwt.secret, {
|
|
||||||
expiresIn: refreshExpire,
|
|
||||||
});
|
|
||||||
await this.midwayCache.set(
|
|
||||||
`admin:passwordVersion:${decoded['userId']}`,
|
|
||||||
decoded['passwordVersion']
|
|
||||||
);
|
|
||||||
await this.midwayCache.set(
|
|
||||||
`admin:token:${decoded['userId']}`,
|
|
||||||
result.token
|
|
||||||
);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,463 +0,0 @@
|
|||||||
import { App, IMidwayApplication, Scope, ScopeEnum } from '@midwayjs/core';
|
|
||||||
import { ALL, Config, Inject, Provide } from '@midwayjs/decorator';
|
|
||||||
import { BaseService, CoolCommException } from '@cool-midway/core';
|
|
||||||
import { InjectEntityModel } from '@midwayjs/typeorm';
|
|
||||||
import { In, Repository } from 'typeorm';
|
|
||||||
import { BaseSysMenuEntity } from '../../entity/sys/menu';
|
|
||||||
import * as _ from 'lodash';
|
|
||||||
import { BaseSysPermsService } from './perms';
|
|
||||||
import { Context } from '@midwayjs/koa';
|
|
||||||
import { TempDataSource } from './data';
|
|
||||||
// eslint-disable-next-line node/no-unpublished-import
|
|
||||||
import * as ts from 'typescript';
|
|
||||||
import * as fs from 'fs';
|
|
||||||
import * as pathUtil from 'path';
|
|
||||||
import { BaseSysRoleMenuEntity } from '../../entity/sys/role_menu';
|
|
||||||
import { BaseSysUserRoleEntity } from '../../entity/sys/user_role';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 菜单
|
|
||||||
*/
|
|
||||||
@Scope(ScopeEnum.Request, { allowDowngrade: true })
|
|
||||||
@Provide()
|
|
||||||
export class BaseSysMenuService extends BaseService {
|
|
||||||
@Inject()
|
|
||||||
ctx: Context;
|
|
||||||
|
|
||||||
@InjectEntityModel(BaseSysMenuEntity)
|
|
||||||
baseSysMenuEntity: Repository<BaseSysMenuEntity>;
|
|
||||||
|
|
||||||
@InjectEntityModel(BaseSysRoleMenuEntity)
|
|
||||||
baseSysRoleMenuEntity: Repository<BaseSysRoleMenuEntity>;
|
|
||||||
|
|
||||||
@Inject()
|
|
||||||
baseSysPermsService: BaseSysPermsService;
|
|
||||||
|
|
||||||
@Config(ALL)
|
|
||||||
config;
|
|
||||||
|
|
||||||
@App()
|
|
||||||
app: IMidwayApplication;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获得所有菜单
|
|
||||||
*/
|
|
||||||
async list() {
|
|
||||||
const menus = await this.getMenus(
|
|
||||||
this.ctx.admin.roleIds,
|
|
||||||
this.ctx.admin.username === 'admin'
|
|
||||||
);
|
|
||||||
if (!_.isEmpty(menus)) {
|
|
||||||
menus.forEach((e: any) => {
|
|
||||||
const parentMenu = menus.filter(m => {
|
|
||||||
e.parentId = parseInt(e.parentId);
|
|
||||||
if (e.parentId == m.id) {
|
|
||||||
return m.name;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (!_.isEmpty(parentMenu)) {
|
|
||||||
e.parentName = parentMenu[0].name;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return menus;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 修改之后
|
|
||||||
* @param param
|
|
||||||
*/
|
|
||||||
async modifyAfter(param) {
|
|
||||||
if (param.id) {
|
|
||||||
await this.refreshPerms(param.id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据角色获得权限信息
|
|
||||||
* @param {[]} roleIds 数组
|
|
||||||
*/
|
|
||||||
async getPerms(roleIds) {
|
|
||||||
let perms = [];
|
|
||||||
if (!_.isEmpty(roleIds)) {
|
|
||||||
const find = await this.baseSysMenuEntity.createQueryBuilder('a');
|
|
||||||
if (!roleIds.includes(1)) {
|
|
||||||
find.innerJoinAndSelect(
|
|
||||||
BaseSysRoleMenuEntity,
|
|
||||||
'b',
|
|
||||||
'a.id = b.menuId AND b.roleId in (:...roleIds)',
|
|
||||||
{ roleIds }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
find.where('a.perms is not NULL');
|
|
||||||
const result = await find.getMany();
|
|
||||||
if (result) {
|
|
||||||
result.forEach(d => {
|
|
||||||
if (d.perms) {
|
|
||||||
perms = perms.concat(d.perms.split(','));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
perms = _.uniq(perms);
|
|
||||||
perms = _.remove(perms, n => {
|
|
||||||
return !_.isEmpty(n);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return _.uniq(perms);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获得用户菜单信息
|
|
||||||
* @param roleIds
|
|
||||||
* @param isAdmin 是否是超管
|
|
||||||
*/
|
|
||||||
async getMenus(roleIds, isAdmin) {
|
|
||||||
const find = this.baseSysMenuEntity.createQueryBuilder('a');
|
|
||||||
if (!isAdmin) {
|
|
||||||
find.innerJoinAndSelect(
|
|
||||||
BaseSysRoleMenuEntity,
|
|
||||||
'b',
|
|
||||||
'a.id = b.menuId AND b.roleId in (:...roleIds)',
|
|
||||||
{ roleIds }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
find.orderBy('a.orderNum', 'ASC');
|
|
||||||
const list = await find.getMany();
|
|
||||||
return _.uniqBy(list, 'id');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 删除
|
|
||||||
* @param ids
|
|
||||||
*/
|
|
||||||
async delete(ids) {
|
|
||||||
let idArr;
|
|
||||||
if (ids instanceof Array) {
|
|
||||||
idArr = ids;
|
|
||||||
} else {
|
|
||||||
idArr = ids.split(',');
|
|
||||||
}
|
|
||||||
for (const id of idArr) {
|
|
||||||
await this.baseSysMenuEntity.delete({ id });
|
|
||||||
await this.delChildMenu(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 删除子菜单
|
|
||||||
* @param id
|
|
||||||
*/
|
|
||||||
private async delChildMenu(id) {
|
|
||||||
await this.refreshPerms(id);
|
|
||||||
const delMenu = await this.baseSysMenuEntity.findBy({ parentId: id });
|
|
||||||
if (_.isEmpty(delMenu)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const delMenuIds = delMenu.map(e => {
|
|
||||||
return e.id;
|
|
||||||
});
|
|
||||||
await this.baseSysMenuEntity.delete(delMenuIds);
|
|
||||||
for (const menuId of delMenuIds) {
|
|
||||||
await this.delChildMenu(menuId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新权限
|
|
||||||
* @param menuId
|
|
||||||
*/
|
|
||||||
async refreshPerms(menuId) {
|
|
||||||
const find = this.baseSysRoleMenuEntity.createQueryBuilder('a');
|
|
||||||
find.leftJoinAndSelect(BaseSysUserRoleEntity, 'b', 'a.roleId = b.roleId');
|
|
||||||
find.where('a.menuId = :menuId', { menuId: menuId });
|
|
||||||
find.select('b.userId', 'userId');
|
|
||||||
const users = await find.getRawMany();
|
|
||||||
// 刷新admin权限
|
|
||||||
await this.baseSysPermsService.refreshPerms(1);
|
|
||||||
if (!_.isEmpty(users)) {
|
|
||||||
// 刷新其他权限
|
|
||||||
for (const user of _.uniqBy(users, 'userId')) {
|
|
||||||
await this.baseSysPermsService.refreshPerms(user.userId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 解析实体和Controller
|
|
||||||
* @param entityString
|
|
||||||
* @param controller
|
|
||||||
* @param module
|
|
||||||
*/
|
|
||||||
async parse(entityString: string, controller: string, module: string) {
|
|
||||||
const tempDataSource = new TempDataSource({
|
|
||||||
...this.config.typeorm.dataSource.default,
|
|
||||||
entities: [],
|
|
||||||
});
|
|
||||||
// 连接数据库
|
|
||||||
await tempDataSource.initialize();
|
|
||||||
const { newCode, className, oldTableName } = this.parseCode(entityString);
|
|
||||||
const code = ts.transpile(
|
|
||||||
`${newCode}
|
|
||||||
tempDataSource.options.entities.push(${className})
|
|
||||||
`,
|
|
||||||
{
|
|
||||||
emitDecoratorMetadata: true,
|
|
||||||
module: ts.ModuleKind.CommonJS,
|
|
||||||
target: ts.ScriptTarget.ES2018,
|
|
||||||
removeComments: true,
|
|
||||||
experimentalDecorators: true,
|
|
||||||
noImplicitThis: true,
|
|
||||||
noUnusedLocals: true,
|
|
||||||
stripInternal: true,
|
|
||||||
skipLibCheck: true,
|
|
||||||
pretty: true,
|
|
||||||
declaration: true,
|
|
||||||
noImplicitAny: false,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
eval(code);
|
|
||||||
await tempDataSource.buildMetadatas();
|
|
||||||
const meta = tempDataSource.getMetadata(className);
|
|
||||||
const columnArr = meta.columns;
|
|
||||||
await tempDataSource.destroy();
|
|
||||||
|
|
||||||
const commColums = [];
|
|
||||||
const columns = _.filter(
|
|
||||||
columnArr.map(e => {
|
|
||||||
return {
|
|
||||||
propertyName: e.propertyName,
|
|
||||||
type: typeof e.type == 'string' ? e.type : e.type.name.toLowerCase(),
|
|
||||||
length: e.length,
|
|
||||||
comment: e.comment,
|
|
||||||
nullable: e.isNullable,
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
o => {
|
|
||||||
if (['createTime', 'updateTime'].includes(o.propertyName)) {
|
|
||||||
commColums.push(o);
|
|
||||||
}
|
|
||||||
return o && !['createTime', 'updateTime'].includes(o.propertyName);
|
|
||||||
}
|
|
||||||
).concat(commColums);
|
|
||||||
if (!controller) {
|
|
||||||
const tableNames = oldTableName.split('_');
|
|
||||||
const fileName = tableNames[tableNames.length - 1];
|
|
||||||
return {
|
|
||||||
columns,
|
|
||||||
className: className.replace('TEMP', ''),
|
|
||||||
tableName: oldTableName,
|
|
||||||
fileName,
|
|
||||||
path: `/admin/${module}/${fileName}`,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
const fileName = await this.fileName(controller);
|
|
||||||
return {
|
|
||||||
columns,
|
|
||||||
path: `/admin/${module}/${fileName}`,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 解析Entity类名
|
|
||||||
* @param code
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
parseCode(code: string) {
|
|
||||||
try {
|
|
||||||
const oldClassName = code
|
|
||||||
.match('class(.*)extends')[1]
|
|
||||||
.replace(/\s*/g, '');
|
|
||||||
const oldTableStart = code.indexOf('@Entity(');
|
|
||||||
const oldTableEnd = code.indexOf(')');
|
|
||||||
|
|
||||||
const oldTableName = code
|
|
||||||
.substring(oldTableStart + 9, oldTableEnd - 1)
|
|
||||||
.replace(/\s*/g, '')
|
|
||||||
// eslint-disable-next-line no-useless-escape
|
|
||||||
.replace(/\"/g, '')
|
|
||||||
// eslint-disable-next-line no-useless-escape
|
|
||||||
.replace(/\'/g, '');
|
|
||||||
const className = `${oldClassName}TEMP`;
|
|
||||||
return {
|
|
||||||
newCode: code
|
|
||||||
.replace(oldClassName, className)
|
|
||||||
.replace(oldTableName, `func_${oldTableName}`),
|
|
||||||
className,
|
|
||||||
tableName: `func_${oldTableName}`,
|
|
||||||
oldTableName,
|
|
||||||
};
|
|
||||||
} catch (err) {
|
|
||||||
throw new CoolCommException('代码结构不正确,请检查');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建代码
|
|
||||||
* @param body body
|
|
||||||
*/
|
|
||||||
async create(body) {
|
|
||||||
const { module, entity, controller, service, fileName } = body;
|
|
||||||
const basePath = this.app.getBaseDir();
|
|
||||||
const modulePath = pathUtil.join(basePath, '..', 'src', 'modules', module);
|
|
||||||
// 生成Entity
|
|
||||||
const entityPath = pathUtil.join(modulePath, 'entity', `${fileName}.ts`);
|
|
||||||
// 生成Controller
|
|
||||||
const controllerPath = pathUtil.join(
|
|
||||||
modulePath,
|
|
||||||
'controller',
|
|
||||||
'admin',
|
|
||||||
`${fileName}.ts`
|
|
||||||
);
|
|
||||||
// 生成Service
|
|
||||||
const servicePath = pathUtil.join(modulePath, 'service', `${fileName}.ts`);
|
|
||||||
this.createConfigFile(module);
|
|
||||||
this.createFile(entityPath, entity);
|
|
||||||
this.createFile(controllerPath, controller);
|
|
||||||
this.createFile(servicePath, service);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建配置文件
|
|
||||||
* @param module
|
|
||||||
*/
|
|
||||||
async createConfigFile(module: string) {
|
|
||||||
const basePath = this.app.getBaseDir();
|
|
||||||
const configFilePath = pathUtil.join(
|
|
||||||
basePath,
|
|
||||||
'..',
|
|
||||||
'src',
|
|
||||||
'modules',
|
|
||||||
module,
|
|
||||||
'config.ts'
|
|
||||||
);
|
|
||||||
if (!fs.existsSync(configFilePath)) {
|
|
||||||
const data = `import { ModuleConfig } from '@cool-midway/core';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 模块配置
|
|
||||||
*/
|
|
||||||
export default () => {
|
|
||||||
return {
|
|
||||||
// 模块名称
|
|
||||||
name: 'xxx',
|
|
||||||
// 模块描述
|
|
||||||
description: 'xxx',
|
|
||||||
// 中间件,只对本模块有效
|
|
||||||
middlewares: [],
|
|
||||||
// 中间件,全局有效
|
|
||||||
globalMiddlewares: [],
|
|
||||||
// 模块加载顺序,默认为0,值越大越优先加载
|
|
||||||
order: 0,
|
|
||||||
} as ModuleConfig;
|
|
||||||
};
|
|
||||||
`;
|
|
||||||
await this.createFile(configFilePath, data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 找到文件名
|
|
||||||
* @param controller
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
async fileName(controller: string) {
|
|
||||||
const regex = /import\s*{\s*\w+\s*}\s*from\s*'[^']*\/([\w-]+)';/;
|
|
||||||
const match = regex.exec(controller);
|
|
||||||
|
|
||||||
if (match && match.length > 1) {
|
|
||||||
return match[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建文件
|
|
||||||
* @param filePath
|
|
||||||
* @param content
|
|
||||||
*/
|
|
||||||
async createFile(filePath: string, content: string) {
|
|
||||||
const folderPath = pathUtil.dirname(filePath);
|
|
||||||
if (!fs.existsSync(folderPath)) {
|
|
||||||
fs.mkdirSync(folderPath, { recursive: true });
|
|
||||||
}
|
|
||||||
fs.writeFileSync(filePath, content);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 导出菜单
|
|
||||||
* @param ids
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
async export(ids: number[]) {
|
|
||||||
const result: any[] = [];
|
|
||||||
const menus = await this.baseSysMenuEntity.findBy({ id: In(ids) });
|
|
||||||
|
|
||||||
// 递归取出子菜单
|
|
||||||
const getChildMenus = (parentId: number): any[] => {
|
|
||||||
const children = _.remove(menus, e => e.parentId == parentId);
|
|
||||||
children.forEach(child => {
|
|
||||||
child.childMenus = getChildMenus(child.id);
|
|
||||||
// 删除不需要的字段
|
|
||||||
delete child.id;
|
|
||||||
delete child.createTime;
|
|
||||||
delete child.updateTime;
|
|
||||||
delete child.parentId;
|
|
||||||
});
|
|
||||||
return children;
|
|
||||||
};
|
|
||||||
|
|
||||||
// lodash取出父级菜单(parentId为 null), 并从menus 删除
|
|
||||||
const parentMenus = _.remove(menus, e => {
|
|
||||||
return e.parentId == null;
|
|
||||||
});
|
|
||||||
|
|
||||||
// 对于每个父级菜单,获取它的子菜单
|
|
||||||
parentMenus.forEach(parent => {
|
|
||||||
parent.childMenus = getChildMenus(parent.id);
|
|
||||||
// 删除不需要的字段
|
|
||||||
delete parent.id;
|
|
||||||
delete parent.createTime;
|
|
||||||
delete parent.updateTime;
|
|
||||||
delete parent.parentId;
|
|
||||||
|
|
||||||
result.push(parent);
|
|
||||||
});
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 导入
|
|
||||||
* @param menus
|
|
||||||
*/
|
|
||||||
async import(menus: any[]) {
|
|
||||||
// 递归保存子菜单
|
|
||||||
const saveChildMenus = async (parentMenu: any, parentId: number | null) => {
|
|
||||||
const children = parentMenu.childMenus || [];
|
|
||||||
for (let child of children) {
|
|
||||||
const childData = { ...child, parentId: parentId }; // 保持与数据库的parentId字段的一致性
|
|
||||||
delete childData.childMenus; // 删除childMenus属性,因为我们不想将它保存到数据库中
|
|
||||||
|
|
||||||
// 保存子菜单并获取其ID,以便为其子菜单设置parentId
|
|
||||||
const savedChild = await this.baseSysMenuEntity.save(childData);
|
|
||||||
|
|
||||||
if (!_.isEmpty(child.childMenus)) {
|
|
||||||
await saveChildMenus(child, savedChild.id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
for (let menu of menus) {
|
|
||||||
const menuData = { ...menu };
|
|
||||||
delete menuData.childMenus; // 删除childMenus属性,因为我们不想将它保存到数据库中
|
|
||||||
|
|
||||||
// 保存主菜单并获取其ID
|
|
||||||
const savedMenu = await this.baseSysMenuEntity.save(menuData);
|
|
||||||
|
|
||||||
if (menu.childMenus && menu.childMenus.length > 0) {
|
|
||||||
await saveChildMenus(menu, savedMenu.id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,91 +0,0 @@
|
|||||||
import { Inject, InjectClient, Provide } from '@midwayjs/decorator';
|
|
||||||
import { BaseService, CoolCommException } from '@cool-midway/core';
|
|
||||||
import { InjectEntityModel } from '@midwayjs/typeorm';
|
|
||||||
import { Not, Repository } from 'typeorm';
|
|
||||||
import { BaseSysParamEntity } from '../../entity/sys/param';
|
|
||||||
import { CachingFactory, MidwayCache } from '@midwayjs/cache-manager';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 参数配置
|
|
||||||
*/
|
|
||||||
@Provide()
|
|
||||||
export class BaseSysParamService extends BaseService {
|
|
||||||
@InjectEntityModel(BaseSysParamEntity)
|
|
||||||
baseSysParamEntity: Repository<BaseSysParamEntity>;
|
|
||||||
|
|
||||||
@InjectClient(CachingFactory, 'default')
|
|
||||||
midwayCache: MidwayCache;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据key获得对应的参数
|
|
||||||
* @param key
|
|
||||||
*/
|
|
||||||
async dataByKey(key) {
|
|
||||||
let result: any = await this.midwayCache.get(`param:${key}`);
|
|
||||||
if (!result) {
|
|
||||||
result = await this.baseSysParamEntity.findOneBy({ keyName: key });
|
|
||||||
this.midwayCache.set(`param:${key}`, result);
|
|
||||||
}
|
|
||||||
if (result) {
|
|
||||||
if (result.dataType == 0) {
|
|
||||||
try {
|
|
||||||
return JSON.parse(result.data);
|
|
||||||
} catch (error) {
|
|
||||||
return result.data;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (result.dataType == 1) {
|
|
||||||
return result.data;
|
|
||||||
}
|
|
||||||
if (result.dataType == 2) {
|
|
||||||
return result.data.split(',');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据key获得对应的网页数据
|
|
||||||
* @param key
|
|
||||||
*/
|
|
||||||
async htmlByKey(key) {
|
|
||||||
let html = '<html><title>@title</title><body>@content</body></html>';
|
|
||||||
let result: any = await this.midwayCache.get(`param:${key}`);
|
|
||||||
if (result) {
|
|
||||||
html = html
|
|
||||||
.replace('@content', result.data)
|
|
||||||
.replace('@title', result.name);
|
|
||||||
} else {
|
|
||||||
html = html.replace('@content', 'key notfound');
|
|
||||||
}
|
|
||||||
return html;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 添加或者修改
|
|
||||||
* @param param
|
|
||||||
*/
|
|
||||||
async addOrUpdate(param: any, type): Promise<void> {
|
|
||||||
const find = {
|
|
||||||
keyName: param.keyName,
|
|
||||||
};
|
|
||||||
if (param.id) {
|
|
||||||
find['id'] = Not(param.id);
|
|
||||||
}
|
|
||||||
const check = await this.baseSysParamEntity.findOneBy(find);
|
|
||||||
if (check) {
|
|
||||||
throw new CoolCommException('存在相同的keyName');
|
|
||||||
}
|
|
||||||
await super.addOrUpdate(param, type);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 重新初始化缓存
|
|
||||||
*/
|
|
||||||
async modifyAfter() {
|
|
||||||
const params = await this.baseSysParamEntity.find();
|
|
||||||
for (const param of params) {
|
|
||||||
await this.midwayCache.set(`param:${param.keyName}`, param);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,90 +0,0 @@
|
|||||||
import { Inject, InjectClient, Provide } from '@midwayjs/decorator';
|
|
||||||
import { BaseService } from '@cool-midway/core';
|
|
||||||
import { BaseSysMenuService } from './menu';
|
|
||||||
import { BaseSysRoleService } from './role';
|
|
||||||
import { BaseSysDepartmentService } from './department';
|
|
||||||
import { Context } from '@midwayjs/koa';
|
|
||||||
import { CachingFactory, MidwayCache } from '@midwayjs/cache-manager';
|
|
||||||
import { BaseSysRoleEntity } from '../../entity/sys/role';
|
|
||||||
import { In, Repository } from 'typeorm';
|
|
||||||
import { InjectEntityModel } from '@midwayjs/typeorm';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 权限
|
|
||||||
*/
|
|
||||||
@Provide()
|
|
||||||
export class BaseSysPermsService extends BaseService {
|
|
||||||
@InjectClient(CachingFactory, 'default')
|
|
||||||
midwayCache: MidwayCache;
|
|
||||||
|
|
||||||
@Inject()
|
|
||||||
baseSysMenuService: BaseSysMenuService;
|
|
||||||
|
|
||||||
@Inject()
|
|
||||||
baseSysRoleService: BaseSysRoleService;
|
|
||||||
|
|
||||||
@Inject()
|
|
||||||
baseSysDepartmentService: BaseSysDepartmentService;
|
|
||||||
|
|
||||||
@InjectEntityModel(BaseSysRoleEntity)
|
|
||||||
baseSysRoleEntity: Repository<BaseSysRoleEntity>;
|
|
||||||
|
|
||||||
@Inject()
|
|
||||||
ctx: Context;
|
|
||||||
base: any;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 刷新权限
|
|
||||||
* @param userId 用户ID
|
|
||||||
*/
|
|
||||||
async refreshPerms(userId) {
|
|
||||||
const roleIds = await this.baseSysRoleService.getByUser(userId);
|
|
||||||
const perms = await this.baseSysMenuService.getPerms(roleIds);
|
|
||||||
await this.midwayCache.set(`admin:perms:${userId}`, perms);
|
|
||||||
// 更新部门权限
|
|
||||||
const departments = await this.baseSysDepartmentService.getByRoleIds(
|
|
||||||
roleIds,
|
|
||||||
await this.isAdmin(roleIds)
|
|
||||||
);
|
|
||||||
await this.midwayCache.set(`admin:department:${userId}`, departments);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据角色判断是不是超管
|
|
||||||
* @param roleIds
|
|
||||||
*/
|
|
||||||
async isAdmin(roleIds: number[]) {
|
|
||||||
const roles = await this.baseSysRoleEntity.findBy({ id: In(roleIds) });
|
|
||||||
const roleLabels = roles.map(item => item.label);
|
|
||||||
return roleLabels.includes('admin');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获得权限菜单
|
|
||||||
* @param roleIds
|
|
||||||
*/
|
|
||||||
async permmenu(roleIds: number[]) {
|
|
||||||
const perms = await this.baseSysMenuService.getPerms(roleIds);
|
|
||||||
const menus = await this.baseSysMenuService.getMenus(
|
|
||||||
roleIds,
|
|
||||||
this.ctx.admin.username === 'admin'
|
|
||||||
);
|
|
||||||
return { perms, menus };
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据用户ID获得部门权限
|
|
||||||
* @param userId
|
|
||||||
* @return 部门ID数组
|
|
||||||
*/
|
|
||||||
async departmentIds(userId: number) {
|
|
||||||
const department: any = await this.midwayCache.get(
|
|
||||||
`admin:department:${userId}`
|
|
||||||
);
|
|
||||||
if (department) {
|
|
||||||
return department;
|
|
||||||
} else {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,136 +0,0 @@
|
|||||||
import { Inject, Provide } from '@midwayjs/decorator';
|
|
||||||
import { BaseService } from '@cool-midway/core';
|
|
||||||
import { InjectEntityModel } from '@midwayjs/typeorm';
|
|
||||||
import { Repository } from 'typeorm';
|
|
||||||
import { BaseSysRoleEntity } from '../../entity/sys/role';
|
|
||||||
import { BaseSysUserRoleEntity } from '../../entity/sys/user_role';
|
|
||||||
import * as _ from 'lodash';
|
|
||||||
import { BaseSysRoleMenuEntity } from '../../entity/sys/role_menu';
|
|
||||||
import { BaseSysRoleDepartmentEntity } from '../../entity/sys/role_department';
|
|
||||||
import { BaseSysPermsService } from './perms';
|
|
||||||
import { Brackets } from 'typeorm';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 角色
|
|
||||||
*/
|
|
||||||
@Provide()
|
|
||||||
export class BaseSysRoleService extends BaseService {
|
|
||||||
@InjectEntityModel(BaseSysRoleEntity)
|
|
||||||
baseSysRoleEntity: Repository<BaseSysRoleEntity>;
|
|
||||||
|
|
||||||
@InjectEntityModel(BaseSysUserRoleEntity)
|
|
||||||
baseSysUserRoleEntity: Repository<BaseSysUserRoleEntity>;
|
|
||||||
|
|
||||||
@InjectEntityModel(BaseSysRoleMenuEntity)
|
|
||||||
baseSysRoleMenuEntity: Repository<BaseSysRoleMenuEntity>;
|
|
||||||
|
|
||||||
@InjectEntityModel(BaseSysRoleDepartmentEntity)
|
|
||||||
baseSysRoleDepartmentEntity: Repository<BaseSysRoleDepartmentEntity>;
|
|
||||||
|
|
||||||
@Inject()
|
|
||||||
baseSysPermsService: BaseSysPermsService;
|
|
||||||
|
|
||||||
@Inject()
|
|
||||||
ctx;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据用户ID获得所有用户角色
|
|
||||||
* @param userId
|
|
||||||
*/
|
|
||||||
async getByUser(userId: number): Promise<number[]> {
|
|
||||||
const userRole = await this.baseSysUserRoleEntity.findBy({ userId });
|
|
||||||
if (!_.isEmpty(userRole)) {
|
|
||||||
return userRole.map(e => {
|
|
||||||
return e.roleId;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param param
|
|
||||||
*/
|
|
||||||
async modifyAfter(param) {
|
|
||||||
if (param.id) {
|
|
||||||
this.updatePerms(param.id, param.menuIdList, param.departmentIdList);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新权限
|
|
||||||
* @param roleId
|
|
||||||
* @param menuIdList
|
|
||||||
* @param departmentIds
|
|
||||||
*/
|
|
||||||
async updatePerms(roleId, menuIdList?, departmentIds = []) {
|
|
||||||
// 更新菜单权限
|
|
||||||
await this.baseSysRoleMenuEntity.delete({ roleId });
|
|
||||||
await Promise.all(
|
|
||||||
menuIdList.map(async e => {
|
|
||||||
return await this.baseSysRoleMenuEntity.save({ roleId, menuId: e });
|
|
||||||
})
|
|
||||||
);
|
|
||||||
// 更新部门权限
|
|
||||||
await this.baseSysRoleDepartmentEntity.delete({ roleId });
|
|
||||||
await Promise.all(
|
|
||||||
departmentIds.map(async e => {
|
|
||||||
return await this.baseSysRoleDepartmentEntity.save({
|
|
||||||
roleId,
|
|
||||||
departmentId: e,
|
|
||||||
});
|
|
||||||
})
|
|
||||||
);
|
|
||||||
// 刷新权限
|
|
||||||
const userRoles = await this.baseSysUserRoleEntity.findBy({ roleId });
|
|
||||||
for (const userRole of userRoles) {
|
|
||||||
await this.baseSysPermsService.refreshPerms(userRole.userId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 角色信息
|
|
||||||
* @param id
|
|
||||||
*/
|
|
||||||
async info(id) {
|
|
||||||
const info = await this.baseSysRoleEntity.findOneBy({ id });
|
|
||||||
if (info) {
|
|
||||||
const menus = await this.baseSysRoleMenuEntity.findBy(
|
|
||||||
id !== 1 ? { roleId: id } : {}
|
|
||||||
);
|
|
||||||
const menuIdList = menus.map(e => {
|
|
||||||
return parseInt(e.menuId + '');
|
|
||||||
});
|
|
||||||
const departments = await this.baseSysRoleDepartmentEntity.findBy(
|
|
||||||
id !== 1 ? { roleId: id } : {}
|
|
||||||
);
|
|
||||||
const departmentIdList = departments.map(e => {
|
|
||||||
return parseInt(e.departmentId + '');
|
|
||||||
});
|
|
||||||
return {
|
|
||||||
...info,
|
|
||||||
menuIdList,
|
|
||||||
departmentIdList,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
async list() {
|
|
||||||
return this.baseSysRoleEntity
|
|
||||||
.createQueryBuilder('a')
|
|
||||||
.where(
|
|
||||||
new Brackets(qb => {
|
|
||||||
qb.where('a.id !=:id', { id: 1 }); // 超级管理员的角色不展示
|
|
||||||
// 如果不是超管,只能看到自己新建的或者自己有的角色
|
|
||||||
if (this.ctx.admin.username !== 'admin') {
|
|
||||||
qb.andWhere('(a.userId=:userId or a.id in (:...roleId))', {
|
|
||||||
userId: this.ctx.admin.userId,
|
|
||||||
roleId: this.ctx.admin.roleIds,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})
|
|
||||||
)
|
|
||||||
.getMany();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,235 +0,0 @@
|
|||||||
import { Inject, InjectClient, Provide } from '@midwayjs/decorator';
|
|
||||||
import { BaseService, CoolCommException } from '@cool-midway/core';
|
|
||||||
import { InjectEntityModel } from '@midwayjs/typeorm';
|
|
||||||
import { Equal, In, Repository } from 'typeorm';
|
|
||||||
import { BaseSysUserEntity } from '../../entity/sys/user';
|
|
||||||
import { BaseSysPermsService } from './perms';
|
|
||||||
import * as _ from 'lodash';
|
|
||||||
import { BaseSysUserRoleEntity } from '../../entity/sys/user_role';
|
|
||||||
import * as md5 from 'md5';
|
|
||||||
import { BaseSysDepartmentEntity } from '../../entity/sys/department';
|
|
||||||
import { CachingFactory, MidwayCache } from '@midwayjs/cache-manager';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 系统用户
|
|
||||||
*/
|
|
||||||
@Provide()
|
|
||||||
export class BaseSysUserService extends BaseService {
|
|
||||||
@InjectEntityModel(BaseSysUserEntity)
|
|
||||||
baseSysUserEntity: Repository<BaseSysUserEntity>;
|
|
||||||
|
|
||||||
@InjectEntityModel(BaseSysUserRoleEntity)
|
|
||||||
baseSysUserRoleEntity: Repository<BaseSysUserRoleEntity>;
|
|
||||||
|
|
||||||
@InjectEntityModel(BaseSysDepartmentEntity)
|
|
||||||
baseSysDepartmentEntity: Repository<BaseSysDepartmentEntity>;
|
|
||||||
|
|
||||||
@InjectClient(CachingFactory, 'default')
|
|
||||||
midwayCache: MidwayCache;
|
|
||||||
|
|
||||||
@Inject()
|
|
||||||
baseSysPermsService: BaseSysPermsService;
|
|
||||||
|
|
||||||
@Inject()
|
|
||||||
ctx;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 分页查询
|
|
||||||
* @param query
|
|
||||||
*/
|
|
||||||
async page(query) {
|
|
||||||
const { keyWord, status, departmentIds = [] } = query;
|
|
||||||
const permsDepartmentArr = await this.baseSysPermsService.departmentIds(
|
|
||||||
this.ctx.admin.userId
|
|
||||||
); // 部门权限
|
|
||||||
const sql = `
|
|
||||||
SELECT
|
|
||||||
a.id,a.name,a.nickName,a.headImg,a.email,a.remark,a.status,a.createTime,a.updateTime,a.username,a.phone,a.departmentId,
|
|
||||||
b.name as "departmentName"
|
|
||||||
FROM
|
|
||||||
base_sys_user a
|
|
||||||
LEFT JOIN base_sys_department b on a.departmentId = b.id
|
|
||||||
WHERE 1 = 1
|
|
||||||
${this.setSql(
|
|
||||||
!_.isEmpty(departmentIds),
|
|
||||||
'and a.departmentId in (?)',
|
|
||||||
[departmentIds]
|
|
||||||
)}
|
|
||||||
${this.setSql(status, 'and a.status = ?', [status])}
|
|
||||||
${this.setSql(keyWord, 'and (a.name LIKE ? or a.username LIKE ?)', [
|
|
||||||
`%${keyWord}%`,
|
|
||||||
`%${keyWord}%`,
|
|
||||||
])}
|
|
||||||
${this.setSql(true, 'and a.username != ?', ['admin'])}
|
|
||||||
${this.setSql(
|
|
||||||
this.ctx.admin.username !== 'admin',
|
|
||||||
'and a.departmentId in (?)',
|
|
||||||
[!_.isEmpty(permsDepartmentArr) ? permsDepartmentArr : [null]]
|
|
||||||
)} `;
|
|
||||||
const result = await this.sqlRenderPage(sql, query);
|
|
||||||
// 匹配角色
|
|
||||||
if (!_.isEmpty(result.list)) {
|
|
||||||
const userIds = result.list.map(e => e.id);
|
|
||||||
const roles = await this.nativeQuery(
|
|
||||||
'SELECT b.name, a.userId FROM base_sys_user_role a LEFT JOIN base_sys_role b ON a.roleId = b.id WHERE a.userId in (?) ',
|
|
||||||
[userIds]
|
|
||||||
);
|
|
||||||
result.list.forEach(e => {
|
|
||||||
e['roleName'] = roles
|
|
||||||
.filter(role => role.userId == e.id)
|
|
||||||
.map(role => role.name)
|
|
||||||
.join(',');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 移动部门
|
|
||||||
* @param departmentId
|
|
||||||
* @param userIds
|
|
||||||
*/
|
|
||||||
async move(departmentId, userIds) {
|
|
||||||
await this.baseSysUserEntity.update({ id: In(userIds) }, { departmentId });
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获得个人信息
|
|
||||||
*/
|
|
||||||
async person(userId) {
|
|
||||||
const info = await this.baseSysUserEntity.findOneBy({
|
|
||||||
id: Equal(userId),
|
|
||||||
});
|
|
||||||
delete info?.password;
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新用户角色关系
|
|
||||||
* @param user
|
|
||||||
*/
|
|
||||||
async updateUserRole(user) {
|
|
||||||
if (_.isEmpty(user.roleIdList)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (user.username === 'admin') {
|
|
||||||
throw new CoolCommException('非法操作~');
|
|
||||||
}
|
|
||||||
await this.baseSysUserRoleEntity.delete({ userId: user.id });
|
|
||||||
if (user.roleIdList) {
|
|
||||||
for (const roleId of user.roleIdList) {
|
|
||||||
await this.baseSysUserRoleEntity.save({ userId: user.id, roleId });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
await this.baseSysPermsService.refreshPerms(user.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 新增
|
|
||||||
* @param param
|
|
||||||
*/
|
|
||||||
async add(param) {
|
|
||||||
const exists = await this.baseSysUserEntity.findOneBy({
|
|
||||||
username: param.username,
|
|
||||||
});
|
|
||||||
if (!_.isEmpty(exists)) {
|
|
||||||
throw new CoolCommException('用户名已经存在~');
|
|
||||||
}
|
|
||||||
param.password = md5(param.password);
|
|
||||||
await this.baseSysUserEntity.save(param);
|
|
||||||
await this.updateUserRole(param);
|
|
||||||
return param.id;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据ID获得信息
|
|
||||||
* @param id
|
|
||||||
*/
|
|
||||||
public async info(id) {
|
|
||||||
const info = await this.baseSysUserEntity.findOneBy({ id });
|
|
||||||
const userRoles = await this.nativeQuery(
|
|
||||||
'select a.roleId from base_sys_user_role a where a.userId = ?',
|
|
||||||
[id]
|
|
||||||
);
|
|
||||||
const department = await this.baseSysDepartmentEntity.findOneBy({
|
|
||||||
id: info.departmentId,
|
|
||||||
});
|
|
||||||
if (info) {
|
|
||||||
delete info.password;
|
|
||||||
if (userRoles) {
|
|
||||||
info.roleIdList = userRoles.map(e => {
|
|
||||||
return parseInt(e.roleId);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
delete info.password;
|
|
||||||
if (department) {
|
|
||||||
info.departmentName = department.name;
|
|
||||||
}
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 修改个人信息
|
|
||||||
* @param param
|
|
||||||
*/
|
|
||||||
public async personUpdate(param) {
|
|
||||||
param.id = this.ctx.admin.userId;
|
|
||||||
if (!_.isEmpty(param.password)) {
|
|
||||||
param.password = md5(param.password);
|
|
||||||
const oldPassword = md5(param.oldPassword);
|
|
||||||
const userInfo = await this.baseSysUserEntity.findOneBy({ id: param.id });
|
|
||||||
if (!userInfo) {
|
|
||||||
throw new CoolCommException('用户不存在');
|
|
||||||
}
|
|
||||||
if (oldPassword !== userInfo.password) {
|
|
||||||
throw new CoolCommException('原密码错误');
|
|
||||||
}
|
|
||||||
param.passwordV = userInfo.passwordV + 1;
|
|
||||||
await this.midwayCache.set(
|
|
||||||
`admin:passwordVersion:${param.id}`,
|
|
||||||
param.passwordV
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
delete param.password;
|
|
||||||
}
|
|
||||||
await this.baseSysUserEntity.save(param);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 修改
|
|
||||||
* @param param 数据
|
|
||||||
*/
|
|
||||||
async update(param) {
|
|
||||||
if (param.id && param.username === 'admin') {
|
|
||||||
throw new CoolCommException('非法操作~');
|
|
||||||
}
|
|
||||||
if (!_.isEmpty(param.password)) {
|
|
||||||
param.password = md5(param.password);
|
|
||||||
const userInfo = await this.baseSysUserEntity.findOneBy({ id: param.id });
|
|
||||||
if (!userInfo) {
|
|
||||||
throw new CoolCommException('用户不存在');
|
|
||||||
}
|
|
||||||
param.passwordV = userInfo.passwordV + 1;
|
|
||||||
await this.midwayCache.set(
|
|
||||||
`admin:passwordVersion:${param.id}`,
|
|
||||||
param.passwordV
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
delete param.password;
|
|
||||||
}
|
|
||||||
if (param.status === 0) {
|
|
||||||
await this.forbidden(param.id);
|
|
||||||
}
|
|
||||||
await this.baseSysUserEntity.save(param);
|
|
||||||
await this.updateUserRole(param);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 禁用用户
|
|
||||||
* @param userId
|
|
||||||
*/
|
|
||||||
async forbidden(userId) {
|
|
||||||
await this.midwayCache.del(`admin:token:${userId}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,19 +0,0 @@
|
|||||||
import { ModuleConfig } from '@cool-midway/core';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 模块配置
|
|
||||||
*/
|
|
||||||
export default () => {
|
|
||||||
return {
|
|
||||||
// 模块名称
|
|
||||||
name: 'demo模块',
|
|
||||||
// 模块描述
|
|
||||||
description: '演示用',
|
|
||||||
// 中间件,只对本模块有效
|
|
||||||
middlewares: [],
|
|
||||||
// 中间件,全局有效
|
|
||||||
globalMiddlewares: [],
|
|
||||||
// 模块加载顺序,默认为0,值越大越优先加载
|
|
||||||
order: 0,
|
|
||||||
} as ModuleConfig;
|
|
||||||
};
|
|
||||||
@ -1,11 +0,0 @@
|
|||||||
import { CoolController, BaseController } from '@cool-midway/core';
|
|
||||||
import { DemoGoodsEntity } from '../../entity/goods';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 商品模块-商品信息
|
|
||||||
*/
|
|
||||||
@CoolController({
|
|
||||||
api: ['add', 'delete', 'update', 'info', 'list', 'page'],
|
|
||||||
entity: DemoGoodsEntity,
|
|
||||||
})
|
|
||||||
export class AdminDemoGoodsController extends BaseController {}
|
|
||||||
@ -1,37 +0,0 @@
|
|||||||
import { DemoCacheService } from '../../service/cache';
|
|
||||||
import { Inject, Post, Provide, Get, InjectClient } from '@midwayjs/decorator';
|
|
||||||
import { CoolController, BaseController } from '@cool-midway/core';
|
|
||||||
import { CachingFactory, MidwayCache } from '@midwayjs/cache-manager';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 缓存
|
|
||||||
*/
|
|
||||||
@CoolController()
|
|
||||||
export class OpenDemoCacheController extends BaseController {
|
|
||||||
@InjectClient(CachingFactory, 'default')
|
|
||||||
midwayCache: MidwayCache;
|
|
||||||
|
|
||||||
@Inject()
|
|
||||||
demoCacheService: DemoCacheService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置缓存
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
@Post('/set')
|
|
||||||
async set() {
|
|
||||||
await this.midwayCache.set('a', 1);
|
|
||||||
// 缓存10秒
|
|
||||||
await this.midwayCache.set('a', 1, 10 * 1000);
|
|
||||||
return this.ok(await this.midwayCache.get('a'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获得缓存
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
@Get('/get')
|
|
||||||
async get() {
|
|
||||||
return this.ok(await this.demoCacheService.get());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,27 +0,0 @@
|
|||||||
import { Inject, Post } from '@midwayjs/decorator';
|
|
||||||
import {
|
|
||||||
CoolController,
|
|
||||||
BaseController,
|
|
||||||
CoolEventManager,
|
|
||||||
} from '@cool-midway/core';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 事件
|
|
||||||
*/
|
|
||||||
@CoolController()
|
|
||||||
export class OpenDemoEventController extends BaseController {
|
|
||||||
@Inject()
|
|
||||||
coolEventManager: CoolEventManager;
|
|
||||||
|
|
||||||
@Post('/comm', { summary: '普通事件,本进程生效' })
|
|
||||||
async comm() {
|
|
||||||
await this.coolEventManager.emit('demo', { a: 2 }, 1);
|
|
||||||
return this.ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Post('/global', { summary: '全局事件,多进程都有效' })
|
|
||||||
async global() {
|
|
||||||
await this.coolEventManager.globalEmit('demo', false, { a: 2 }, 1);
|
|
||||||
return this.ok();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,32 +0,0 @@
|
|||||||
import { DemoGoodsService } from '../../service/goods';
|
|
||||||
import { DemoGoodsEntity } from '../../entity/goods';
|
|
||||||
import { Body, Config, Inject, Post, Provide } from '@midwayjs/decorator';
|
|
||||||
import { CoolController, BaseController } from '@cool-midway/core';
|
|
||||||
import { InjectEntityModel } from '@midwayjs/typeorm';
|
|
||||||
import { Repository } from 'typeorm';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 测试
|
|
||||||
*/
|
|
||||||
@CoolController({
|
|
||||||
api: ['add', 'delete', 'update', 'info', 'list', 'page'],
|
|
||||||
entity: DemoGoodsEntity,
|
|
||||||
service: DemoGoodsService,
|
|
||||||
})
|
|
||||||
export class OpenDemoGoodsController extends BaseController {
|
|
||||||
@InjectEntityModel(DemoGoodsEntity)
|
|
||||||
demoGoodsEntity: Repository<DemoGoodsEntity>;
|
|
||||||
|
|
||||||
@Inject()
|
|
||||||
demoGoodsService: DemoGoodsService;
|
|
||||||
|
|
||||||
@Post('/sqlPage', { summary: 'sql分页查询' })
|
|
||||||
async sqlPage(@Body() query) {
|
|
||||||
return this.ok(await this.demoGoodsService.sqlPage(query));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Post('/entityPage', { summary: 'entity分页查询' })
|
|
||||||
async entityPage(@Body() query) {
|
|
||||||
return this.ok(await this.demoGoodsService.entityPage(query));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,29 +0,0 @@
|
|||||||
import { CoolController, BaseController } from '@cool-midway/core';
|
|
||||||
import { PluginService } from '../../../plugin/service/info';
|
|
||||||
import { Get, Inject } from '@midwayjs/core';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 插件
|
|
||||||
*/
|
|
||||||
@CoolController()
|
|
||||||
export class OpenDemoPluginController extends BaseController {
|
|
||||||
@Inject()
|
|
||||||
pluginService: PluginService;
|
|
||||||
|
|
||||||
@Get('/invoke', { summary: '调用插件' })
|
|
||||||
async invoke() {
|
|
||||||
// 获取插件实例
|
|
||||||
const instance: any = await this.pluginService.getInstance('ollama');
|
|
||||||
// 调用chat
|
|
||||||
const messages = [
|
|
||||||
{ role: 'system', content: '你叫小酷,是一个智能助理' },
|
|
||||||
{ role: 'user', content: '写一个1000字的关于春天的文章' },
|
|
||||||
];
|
|
||||||
for (let i = 0; i < 3; i++) {
|
|
||||||
instance.chat(messages, { stream: true }, res => {
|
|
||||||
console.log(i, res.content);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return this.ok();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,49 +0,0 @@
|
|||||||
import { Get, Inject, Post, Provide } from '@midwayjs/decorator';
|
|
||||||
import { CoolController, BaseController } from '@cool-midway/core';
|
|
||||||
import { DemoCommQueue } from '../../queue/comm';
|
|
||||||
import { DemoGetterQueue } from '../../queue/getter';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 队列
|
|
||||||
*/
|
|
||||||
@CoolController()
|
|
||||||
export class OpenDemoQueueController extends BaseController {
|
|
||||||
// 普通队列
|
|
||||||
@Inject()
|
|
||||||
demoCommQueue: DemoCommQueue;
|
|
||||||
|
|
||||||
// 主动消费队列
|
|
||||||
@Inject()
|
|
||||||
demoGetterQueue: DemoGetterQueue;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 发送数据到队列
|
|
||||||
*/
|
|
||||||
@Post('/add', { summary: '发送队列数据' })
|
|
||||||
async queue() {
|
|
||||||
this.demoCommQueue.add({ a: 2 });
|
|
||||||
return this.ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Post('/addGetter')
|
|
||||||
async addGetter() {
|
|
||||||
await this.demoGetterQueue.add({ a: new Date() });
|
|
||||||
return this.ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获得队列中的数据,只有当队列类型为getter时有效
|
|
||||||
*/
|
|
||||||
@Get('/getter')
|
|
||||||
async getter() {
|
|
||||||
const job = await this.demoGetterQueue.getters.getJobs(
|
|
||||||
['wait'],
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
true
|
|
||||||
);
|
|
||||||
// 获得完将数据从队列移除
|
|
||||||
await job[0]?.remove();
|
|
||||||
return this.ok(job[0]?.data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,29 +0,0 @@
|
|||||||
import { Inject, Provide, Get } from '@midwayjs/decorator';
|
|
||||||
import { CoolController, BaseController } from '@cool-midway/core';
|
|
||||||
import { DemoRpcService } from '../../service/rpc';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 远程RPC调用
|
|
||||||
*/
|
|
||||||
@CoolController()
|
|
||||||
export class OpenDemoRpcController extends BaseController {
|
|
||||||
@Inject()
|
|
||||||
demoRpcService: DemoRpcService;
|
|
||||||
|
|
||||||
@Get('/call', { summary: '远程调用' })
|
|
||||||
async call() {
|
|
||||||
return this.ok(await this.demoRpcService.call());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Get('/event', { summary: '集群事件' })
|
|
||||||
async event() {
|
|
||||||
await this.demoRpcService.event();
|
|
||||||
return this.ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Get('/transaction', { summary: '分布式事务' })
|
|
||||||
async transaction() {
|
|
||||||
await this.demoRpcService.transaction({ a: 1 });
|
|
||||||
return this.ok();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,49 +0,0 @@
|
|||||||
import { CoolController, BaseController } from '@cool-midway/core';
|
|
||||||
import { Get, Inject } from '@midwayjs/core';
|
|
||||||
import { Context } from 'koa';
|
|
||||||
import { PluginService } from '../../../plugin/service/info';
|
|
||||||
import { PassThrough } from 'stream';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 事件流 服务端主动推送
|
|
||||||
*/
|
|
||||||
@CoolController()
|
|
||||||
export class OpenDemoSSEController extends BaseController {
|
|
||||||
@Inject()
|
|
||||||
ctx: Context;
|
|
||||||
|
|
||||||
@Inject()
|
|
||||||
pluginService: PluginService;
|
|
||||||
|
|
||||||
@Get('/call', { summary: '事件流 服务端主动推送' })
|
|
||||||
async call() {
|
|
||||||
// 设置响应头
|
|
||||||
this.ctx.set('Content-Type', 'text/event-stream');
|
|
||||||
this.ctx.set('Cache-Control', 'no-cache');
|
|
||||||
this.ctx.set('Connection', 'keep-alive');
|
|
||||||
|
|
||||||
const stream = new PassThrough();
|
|
||||||
|
|
||||||
// 发送数据
|
|
||||||
const send = (data: any) => {
|
|
||||||
stream.write(`data: ${JSON.stringify(data)}\n\n`);
|
|
||||||
};
|
|
||||||
|
|
||||||
// 获取插件实例
|
|
||||||
const instance: any = await this.pluginService.getInstance('ollama');
|
|
||||||
// 调用chat
|
|
||||||
const messages = [
|
|
||||||
{ role: 'system', content: '你叫小酷,是个编程助手' },
|
|
||||||
{ role: 'user', content: '用js写个Hello World' },
|
|
||||||
];
|
|
||||||
instance.chat(messages, { stream: true }, res => {
|
|
||||||
send(res);
|
|
||||||
if (res.isEnd) {
|
|
||||||
this.ctx.res.end();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.ctx.status = 200;
|
|
||||||
this.ctx.body = stream;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,14 +0,0 @@
|
|||||||
import { DemoGoodsEntity } from '../../entity/goods';
|
|
||||||
import { Provide } from '@midwayjs/decorator';
|
|
||||||
import { CoolController, BaseController } from '@cool-midway/core';
|
|
||||||
import { DemoTransactionService } from '../../service/transaction';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 事务
|
|
||||||
*/
|
|
||||||
@CoolController({
|
|
||||||
api: ['add', 'delete', 'update', 'info', 'list', 'page'],
|
|
||||||
entity: DemoGoodsEntity,
|
|
||||||
service: DemoTransactionService,
|
|
||||||
})
|
|
||||||
export class OpenDemoTransactionController extends BaseController {}
|
|
||||||
@ -1,32 +0,0 @@
|
|||||||
import { BaseEntity } from '@cool-midway/core';
|
|
||||||
import { Column, Entity, Index } from 'typeorm';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 商品模块-商品信息
|
|
||||||
*/
|
|
||||||
@Entity('demo_goods')
|
|
||||||
export class DemoGoodsEntity extends BaseEntity {
|
|
||||||
@Index()
|
|
||||||
@Column({ comment: '标题', length: 50 })
|
|
||||||
title: string;
|
|
||||||
|
|
||||||
@Column({
|
|
||||||
comment: '价格',
|
|
||||||
type: 'decimal',
|
|
||||||
precision: 5,
|
|
||||||
scale: 2,
|
|
||||||
})
|
|
||||||
price: number;
|
|
||||||
|
|
||||||
@Column({ comment: '描述', nullable: true })
|
|
||||||
description: string;
|
|
||||||
|
|
||||||
@Column({ comment: '主图', nullable: true })
|
|
||||||
mainImage: string;
|
|
||||||
|
|
||||||
@Column({ comment: '示例图', nullable: true, type: 'json' })
|
|
||||||
exampleImages: string[];
|
|
||||||
|
|
||||||
@Column({ comment: '库存', default: 0 })
|
|
||||||
stock: number;
|
|
||||||
}
|
|
||||||
@ -1,27 +0,0 @@
|
|||||||
import { CoolEvent, Event } from '@cool-midway/core';
|
|
||||||
import { EVENT_PLUGIN_READY } from '../../plugin/service/center';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 普通事件
|
|
||||||
*/
|
|
||||||
@CoolEvent()
|
|
||||||
export class DemoCommEvent {
|
|
||||||
/**
|
|
||||||
* 根据事件名接收事件
|
|
||||||
* @param msg
|
|
||||||
* @param a
|
|
||||||
*/
|
|
||||||
@Event('demo')
|
|
||||||
async demo(msg, a) {
|
|
||||||
console.log(`comm当前进程的ID是: ${process.pid}`);
|
|
||||||
console.log('comm收到消息', msg, a);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 插件已就绪
|
|
||||||
*/
|
|
||||||
@Event(EVENT_PLUGIN_READY)
|
|
||||||
async pluginReady() {
|
|
||||||
// TODO 插件已就绪
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,20 +0,0 @@
|
|||||||
import { BaseCoolQueue, CoolQueue } from '@cool-midway/task';
|
|
||||||
import { IMidwayApplication } from '@midwayjs/core';
|
|
||||||
import { App } from '@midwayjs/decorator';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 普通队列
|
|
||||||
*/
|
|
||||||
@CoolQueue()
|
|
||||||
export class DemoCommQueue extends BaseCoolQueue {
|
|
||||||
@App()
|
|
||||||
app: IMidwayApplication;
|
|
||||||
|
|
||||||
async data(job: any, done: any): Promise<void> {
|
|
||||||
// 这边可以执行定时任务具体的业务或队列的业务
|
|
||||||
console.log('数据', job.data);
|
|
||||||
// 抛出错误 可以让队列重试,默认重试5次
|
|
||||||
//throw new Error('错误');
|
|
||||||
done();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
import { BaseCoolQueue, CoolQueue } from '@cool-midway/task';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 主动消费队列
|
|
||||||
*/
|
|
||||||
@CoolQueue({ type: 'getter' })
|
|
||||||
export class DemoGetterQueue extends BaseCoolQueue {}
|
|
||||||
@ -1,20 +0,0 @@
|
|||||||
import { BaseCoolQueue, CoolQueue } from '@cool-midway/task';
|
|
||||||
import { IMidwayApplication } from '@midwayjs/core';
|
|
||||||
import { App } from '@midwayjs/decorator';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 单例队列,cluster 或 集群模式下 只会有一个实例消费数据
|
|
||||||
*/
|
|
||||||
@CoolQueue({ type: 'single' })
|
|
||||||
export class DemoSingleQueue extends BaseCoolQueue {
|
|
||||||
@App()
|
|
||||||
app: IMidwayApplication;
|
|
||||||
|
|
||||||
async data(job: any, done: any): Promise<void> {
|
|
||||||
// 这边可以执行定时任务具体的业务或队列的业务
|
|
||||||
console.log('数据', job.data);
|
|
||||||
// 抛出错误 可以让队列重试,默认重试5次
|
|
||||||
//throw new Error('错误');
|
|
||||||
done();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,18 +0,0 @@
|
|||||||
import { Provide } from '@midwayjs/decorator';
|
|
||||||
import { CoolCache } from '@cool-midway/core';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 缓存
|
|
||||||
*/
|
|
||||||
@Provide()
|
|
||||||
export class DemoCacheService {
|
|
||||||
// 数据缓存5秒
|
|
||||||
@CoolCache(5)
|
|
||||||
async get() {
|
|
||||||
console.log('执行方法');
|
|
||||||
return {
|
|
||||||
a: 1,
|
|
||||||
b: 2,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,40 +0,0 @@
|
|||||||
import { DemoGoodsEntity } from './../entity/goods';
|
|
||||||
import { Provide } from '@midwayjs/decorator';
|
|
||||||
import { BaseService } from '@cool-midway/core';
|
|
||||||
import { InjectEntityModel } from '@midwayjs/typeorm';
|
|
||||||
import { Repository } from 'typeorm';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 商品示例
|
|
||||||
*/
|
|
||||||
@Provide()
|
|
||||||
export class DemoGoodsService extends BaseService {
|
|
||||||
@InjectEntityModel(DemoGoodsEntity)
|
|
||||||
demoGoodsEntity: Repository<DemoGoodsEntity>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 执行sql分页
|
|
||||||
*/
|
|
||||||
async sqlPage(query) {
|
|
||||||
await this.demoGoodsEntity.save({
|
|
||||||
id: 1,
|
|
||||||
title: '标题',
|
|
||||||
price: 99.0,
|
|
||||||
description: '商品描述',
|
|
||||||
mainImage: 'https://cool-js.com/logo.png',
|
|
||||||
});
|
|
||||||
return this.sqlRenderPage(
|
|
||||||
'select * from demo_goods ORDER BY id ASC',
|
|
||||||
query,
|
|
||||||
false
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 执行entity分页
|
|
||||||
*/
|
|
||||||
async entityPage(query) {
|
|
||||||
const find = this.demoGoodsEntity.createQueryBuilder();
|
|
||||||
return this.entityRenderPage(find, query);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,70 +0,0 @@
|
|||||||
import { App, Provide } from '@midwayjs/decorator';
|
|
||||||
import { DemoGoodsEntity } from '../entity/goods';
|
|
||||||
import { IMidwayApplication, Inject } from '@midwayjs/core';
|
|
||||||
import {
|
|
||||||
BaseRpcService,
|
|
||||||
CoolRpc,
|
|
||||||
CoolRpcService,
|
|
||||||
CoolRpcTransaction,
|
|
||||||
} from '@cool-midway/rpc';
|
|
||||||
import { QueryRunner } from 'typeorm';
|
|
||||||
|
|
||||||
@Provide()
|
|
||||||
@CoolRpcService({
|
|
||||||
entity: DemoGoodsEntity,
|
|
||||||
method: ['info', 'add', 'page'],
|
|
||||||
})
|
|
||||||
export class DemoRpcService extends BaseRpcService {
|
|
||||||
@App()
|
|
||||||
app: IMidwayApplication;
|
|
||||||
|
|
||||||
@Inject()
|
|
||||||
rpc: CoolRpc;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 远程调用
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
async call() {
|
|
||||||
return await this.rpc.call('goods', 'demoGoodsService', 'test', {
|
|
||||||
a: 1,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 集群事件
|
|
||||||
*/
|
|
||||||
async event() {
|
|
||||||
this.rpc.event('test', { a: 1 });
|
|
||||||
}
|
|
||||||
|
|
||||||
async info(params) {
|
|
||||||
return params;
|
|
||||||
}
|
|
||||||
async getUser() {
|
|
||||||
return {
|
|
||||||
uid: '123',
|
|
||||||
username: 'mockedName',
|
|
||||||
phone: '12345678901',
|
|
||||||
email: 'xxx.xxx@xxx.com',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@CoolRpcTransaction()
|
|
||||||
async transaction(params, rpcTransactionId?, queryRunner?: QueryRunner) {
|
|
||||||
console.log('获得的参数', params);
|
|
||||||
const data = {
|
|
||||||
title: '商品标题',
|
|
||||||
pic: 'https://xxx',
|
|
||||||
price: 99.0,
|
|
||||||
type: 1,
|
|
||||||
};
|
|
||||||
await queryRunner.manager.save(DemoGoodsEntity, data);
|
|
||||||
|
|
||||||
// 将事务id传给调用的远程服务方法
|
|
||||||
await this.rpc.call('goods', 'demoGoodsService', 'transaction', {
|
|
||||||
rpcTransactionId,
|
|
||||||
...params,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,23 +0,0 @@
|
|||||||
import { DemoGoodsEntity } from './../entity/goods';
|
|
||||||
import { Provide } from '@midwayjs/decorator';
|
|
||||||
import { BaseService, CoolTransaction } from '@cool-midway/core';
|
|
||||||
import { QueryRunner } from 'typeorm';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 操作事务
|
|
||||||
*/
|
|
||||||
@Provide()
|
|
||||||
export class DemoTransactionService extends BaseService {
|
|
||||||
/**
|
|
||||||
* 事务操作
|
|
||||||
*/
|
|
||||||
@CoolTransaction({
|
|
||||||
connectionName: 'default',
|
|
||||||
})
|
|
||||||
async add(param, queryRunner?: QueryRunner) {
|
|
||||||
await queryRunner.manager.insert<DemoGoodsEntity>(DemoGoodsEntity, param);
|
|
||||||
return {
|
|
||||||
id: param.id,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,19 +0,0 @@
|
|||||||
import { ModuleConfig } from '@cool-midway/core';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 模块配置
|
|
||||||
*/
|
|
||||||
export default () => {
|
|
||||||
return {
|
|
||||||
// 模块名称
|
|
||||||
name: '字典管理',
|
|
||||||
// 模块描述
|
|
||||||
description: '数据字典等',
|
|
||||||
// 中间件,只对本模块有效
|
|
||||||
middlewares: [],
|
|
||||||
// 中间件,全局有效
|
|
||||||
globalMiddlewares: [],
|
|
||||||
// 模块加载顺序,默认为0,值越大越优先加载
|
|
||||||
order: 0,
|
|
||||||
} as ModuleConfig;
|
|
||||||
};
|
|
||||||
@ -1,30 +0,0 @@
|
|||||||
import { DictInfoEntity } from './../../entity/info';
|
|
||||||
import { Body, Inject, Post, Provide } from '@midwayjs/decorator';
|
|
||||||
import { CoolController, BaseController } from '@cool-midway/core';
|
|
||||||
import { DictInfoService } from '../../service/info';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 字典信息
|
|
||||||
*/
|
|
||||||
@Provide()
|
|
||||||
@CoolController({
|
|
||||||
api: ['add', 'delete', 'update', 'info', 'list', 'page'],
|
|
||||||
entity: DictInfoEntity,
|
|
||||||
service: DictInfoService,
|
|
||||||
listQueryOp: {
|
|
||||||
fieldEq: ['typeId'],
|
|
||||||
keyWordLikeFields: ['name'],
|
|
||||||
addOrderBy: {
|
|
||||||
createTime: 'ASC',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
export class AdminDictInfoController extends BaseController {
|
|
||||||
@Inject()
|
|
||||||
dictInfoService: DictInfoService;
|
|
||||||
|
|
||||||
@Post('/data', { summary: '获得字典数据' })
|
|
||||||
async data(@Body('types') types: string[] = []) {
|
|
||||||
return this.ok(await this.dictInfoService.data(types));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,18 +0,0 @@
|
|||||||
import { DictTypeEntity } from './../../entity/type';
|
|
||||||
import { Provide } from '@midwayjs/decorator';
|
|
||||||
import { CoolController, BaseController } from '@cool-midway/core';
|
|
||||||
import { DictTypeService } from '../../service/type';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 字典类型
|
|
||||||
*/
|
|
||||||
@Provide()
|
|
||||||
@CoolController({
|
|
||||||
api: ['add', 'delete', 'update', 'info', 'list', 'page'],
|
|
||||||
entity: DictTypeEntity,
|
|
||||||
service: DictTypeService,
|
|
||||||
listQueryOp: {
|
|
||||||
keyWordLikeFields: ['name'],
|
|
||||||
},
|
|
||||||
})
|
|
||||||
export class AdminDictTypeController extends BaseController {}
|
|
||||||
@ -1,26 +0,0 @@
|
|||||||
import { Body, Inject, Post, Provide } from '@midwayjs/decorator';
|
|
||||||
import {
|
|
||||||
CoolController,
|
|
||||||
BaseController,
|
|
||||||
CoolUrlTag,
|
|
||||||
TagTypes,
|
|
||||||
CoolTag,
|
|
||||||
} from '@cool-midway/core';
|
|
||||||
import { DictInfoService } from '../../service/info';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 字典信息
|
|
||||||
*/
|
|
||||||
@Provide()
|
|
||||||
@CoolController()
|
|
||||||
@CoolUrlTag()
|
|
||||||
export class AppDictInfoController extends BaseController {
|
|
||||||
@Inject()
|
|
||||||
dictInfoService: DictInfoService;
|
|
||||||
|
|
||||||
@CoolTag(TagTypes.IGNORE_TOKEN)
|
|
||||||
@Post('/data', { summary: '获得字典数据' })
|
|
||||||
async data(@Body('types') types: string[] = []) {
|
|
||||||
return this.ok(await this.dictInfoService.data(types));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,88 +0,0 @@
|
|||||||
{
|
|
||||||
"dict_info": [
|
|
||||||
{
|
|
||||||
"id": 21,
|
|
||||||
"typeId": 19,
|
|
||||||
"name": "COOL",
|
|
||||||
"orderNum": 1,
|
|
||||||
"remark": null,
|
|
||||||
"parentId": null,
|
|
||||||
"value": "cool"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 22,
|
|
||||||
"typeId": 19,
|
|
||||||
"name": "闪酷",
|
|
||||||
"orderNum": 2,
|
|
||||||
"remark": null,
|
|
||||||
"parentId": null,
|
|
||||||
"value": "https://show.cool-admin.com/api/public/uploads/20230308/c731b0cba84046268b10edbbcf36f948_315c243a448e1369fa145c5ea3f020da.gif"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 23,
|
|
||||||
"typeId": 20,
|
|
||||||
"name": "法师",
|
|
||||||
"orderNum": 1,
|
|
||||||
"remark": null,
|
|
||||||
"parentId": null,
|
|
||||||
"value": "4"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 24,
|
|
||||||
"typeId": 20,
|
|
||||||
"name": "战士",
|
|
||||||
"orderNum": 2,
|
|
||||||
"remark": null,
|
|
||||||
"parentId": null,
|
|
||||||
"value": "3"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 25,
|
|
||||||
"typeId": 20,
|
|
||||||
"name": "坦克",
|
|
||||||
"orderNum": 3,
|
|
||||||
"remark": null,
|
|
||||||
"parentId": null,
|
|
||||||
"value": "2"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 26,
|
|
||||||
"typeId": 20,
|
|
||||||
"name": "刺客",
|
|
||||||
"orderNum": 4,
|
|
||||||
"remark": null,
|
|
||||||
"parentId": null,
|
|
||||||
"value": "1"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 27,
|
|
||||||
"typeId": 20,
|
|
||||||
"name": "射手",
|
|
||||||
"orderNum": 5,
|
|
||||||
"remark": null,
|
|
||||||
"parentId": null,
|
|
||||||
"value": "0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 30,
|
|
||||||
"typeId": 20,
|
|
||||||
"name": "幻影刺客",
|
|
||||||
"orderNum": 1,
|
|
||||||
"remark": null,
|
|
||||||
"parentId": 26,
|
|
||||||
"value": "5"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"dict_type": [
|
|
||||||
{
|
|
||||||
"id": 19,
|
|
||||||
"name": "品牌",
|
|
||||||
"key": "brand"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 20,
|
|
||||||
"name": "职业",
|
|
||||||
"key": "occupation"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@ -1,26 +0,0 @@
|
|||||||
import { BaseEntity } from '@cool-midway/core';
|
|
||||||
import { Column, Entity } from 'typeorm';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 字典信息
|
|
||||||
*/
|
|
||||||
@Entity('dict_info')
|
|
||||||
export class DictInfoEntity extends BaseEntity {
|
|
||||||
@Column({ comment: '类型ID' })
|
|
||||||
typeId: number;
|
|
||||||
|
|
||||||
@Column({ comment: '名称' })
|
|
||||||
name: string;
|
|
||||||
|
|
||||||
@Column({ comment: '值', nullable: true })
|
|
||||||
value: string;
|
|
||||||
|
|
||||||
@Column({ comment: '排序', default: 0 })
|
|
||||||
orderNum: number;
|
|
||||||
|
|
||||||
@Column({ comment: '备注', nullable: true })
|
|
||||||
remark: string;
|
|
||||||
|
|
||||||
@Column({ comment: '父ID', default: null })
|
|
||||||
parentId: number;
|
|
||||||
}
|
|
||||||
@ -1,14 +0,0 @@
|
|||||||
import { BaseEntity } from '@cool-midway/core';
|
|
||||||
import { Column, Entity } from 'typeorm';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 字典类别
|
|
||||||
*/
|
|
||||||
@Entity('dict_type')
|
|
||||||
export class DictTypeEntity extends BaseEntity {
|
|
||||||
@Column({ comment: '名称' })
|
|
||||||
name: string;
|
|
||||||
|
|
||||||
@Column({ comment: '标识' })
|
|
||||||
key: string;
|
|
||||||
}
|
|
||||||
@ -1,137 +0,0 @@
|
|||||||
import { DictTypeEntity } from './../entity/type';
|
|
||||||
import { DictInfoEntity } from './../entity/info';
|
|
||||||
import { Config, Provide } from '@midwayjs/decorator';
|
|
||||||
import { BaseService } from '@cool-midway/core';
|
|
||||||
import { InjectEntityModel } from '@midwayjs/typeorm';
|
|
||||||
import { Repository, In } from 'typeorm';
|
|
||||||
import * as _ from 'lodash';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 字典信息
|
|
||||||
*/
|
|
||||||
@Provide()
|
|
||||||
export class DictInfoService extends BaseService {
|
|
||||||
@InjectEntityModel(DictInfoEntity)
|
|
||||||
dictInfoEntity: Repository<DictInfoEntity>;
|
|
||||||
|
|
||||||
@InjectEntityModel(DictTypeEntity)
|
|
||||||
dictTypeEntity: Repository<DictTypeEntity>;
|
|
||||||
|
|
||||||
@Config('typeorm.dataSource.default.type')
|
|
||||||
ormType: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获得字典数据
|
|
||||||
* @param types
|
|
||||||
*/
|
|
||||||
async data(types: string[]) {
|
|
||||||
const result = {};
|
|
||||||
let typeData = await this.dictTypeEntity.find();
|
|
||||||
if (!_.isEmpty(types)) {
|
|
||||||
typeData = await this.dictTypeEntity.findBy({ key: In(types) });
|
|
||||||
}
|
|
||||||
if (_.isEmpty(typeData)) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
const data = await this.dictInfoEntity
|
|
||||||
.createQueryBuilder('a')
|
|
||||||
.select([
|
|
||||||
'a.id',
|
|
||||||
'a.name',
|
|
||||||
'a.typeId',
|
|
||||||
'a.parentId',
|
|
||||||
'a.orderNum',
|
|
||||||
'a.value',
|
|
||||||
])
|
|
||||||
.where('a.typeId in(:...typeIds)', {
|
|
||||||
typeIds: typeData.map(e => {
|
|
||||||
return e.id;
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
.orderBy('a.orderNum', 'ASC')
|
|
||||||
.addOrderBy('a.createTime', 'ASC')
|
|
||||||
.getMany();
|
|
||||||
for (const item of typeData) {
|
|
||||||
result[item.key] = _.filter(data, { typeId: item.id }).map(e => {
|
|
||||||
const value = e.value ? Number(e.value) : e.value;
|
|
||||||
return {
|
|
||||||
...e,
|
|
||||||
value: isNaN(value) ? e.value : value,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获得单个或多个字典值
|
|
||||||
* @param value 字典值或字典值数组
|
|
||||||
* @param key 字典类型
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
async getValues(value: string | string[], key: string) {
|
|
||||||
// 获取字典类型
|
|
||||||
const type = await this.dictTypeEntity.findOneBy({ key });
|
|
||||||
if (!type) {
|
|
||||||
return null; // 或者适当的错误处理
|
|
||||||
}
|
|
||||||
|
|
||||||
// 根据typeId获取所有相关的字典信息
|
|
||||||
const dictValues = await this.dictInfoEntity.find({
|
|
||||||
where: { typeId: type.id },
|
|
||||||
});
|
|
||||||
|
|
||||||
// 如果value是字符串,直接查找
|
|
||||||
if (typeof value === 'string') {
|
|
||||||
return this.findValueInDictValues(value, dictValues);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果value是数组,遍历数组,对每个元素进行查找
|
|
||||||
return value.map(val => this.findValueInDictValues(val, dictValues));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 在字典值数组中查找指定的值
|
|
||||||
* @param value 要查找的值
|
|
||||||
* @param dictValues 字典值数组
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
findValueInDictValues(value: string, dictValues: any[]) {
|
|
||||||
let result = dictValues.find(dictValue => dictValue.value === value);
|
|
||||||
if (!result) {
|
|
||||||
result = dictValues.find(dictValue => dictValue.id === parseInt(value));
|
|
||||||
}
|
|
||||||
return result ? result.name : null; // 或者适当的错误处理
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 修改之后
|
|
||||||
* @param data
|
|
||||||
* @param type
|
|
||||||
*/
|
|
||||||
async modifyAfter(data: any, type: 'delete' | 'update' | 'add') {
|
|
||||||
if (type === 'delete') {
|
|
||||||
for (const id of data) {
|
|
||||||
await this.delChildDict(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 删除子字典
|
|
||||||
* @param id
|
|
||||||
*/
|
|
||||||
private async delChildDict(id) {
|
|
||||||
const delDict = await this.dictInfoEntity.findBy({ parentId: id });
|
|
||||||
if (_.isEmpty(delDict)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const delDictIds = delDict.map(e => {
|
|
||||||
return e.id;
|
|
||||||
});
|
|
||||||
await this.dictInfoEntity.delete(delDictIds);
|
|
||||||
for (const dictId of delDictIds) {
|
|
||||||
await this.delChildDict(dictId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,25 +0,0 @@
|
|||||||
import { DictInfoEntity } from './../entity/info';
|
|
||||||
import { Provide } from '@midwayjs/decorator';
|
|
||||||
import { BaseService } from '@cool-midway/core';
|
|
||||||
import { InjectEntityModel } from '@midwayjs/typeorm';
|
|
||||||
import { Repository, In } from 'typeorm';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 描述
|
|
||||||
*/
|
|
||||||
@Provide()
|
|
||||||
export class DictTypeService extends BaseService {
|
|
||||||
@InjectEntityModel(DictInfoEntity)
|
|
||||||
dictInfoEntity: Repository<DictInfoEntity>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 删除
|
|
||||||
* @param ids
|
|
||||||
*/
|
|
||||||
async delete(ids) {
|
|
||||||
super.delete(ids);
|
|
||||||
await this.dictInfoEntity.delete({
|
|
||||||
typeId: In(ids),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user