diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..46a8e39 Binary files /dev/null and b/.DS_Store differ diff --git a/.dockerignore b/.dockerignore deleted file mode 100644 index abe7af5..0000000 --- a/.dockerignore +++ /dev/null @@ -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/ diff --git a/.editorconfig b/.editorconfig deleted file mode 100644 index 4c7f8a8..0000000 --- a/.editorconfig +++ /dev/null @@ -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 \ No newline at end of file diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index 7dab201..0000000 --- a/.eslintrc.json +++ /dev/null @@ -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" - } -} \ No newline at end of file diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index 0b909d8..0000000 --- a/.gitattributes +++ /dev/null @@ -1,4 +0,0 @@ -*.js text eol=lf -*.json text eol=lf -*.ts text eol=lf -*.code-snippets text eol=lf \ No newline at end of file diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 4cafa26..0000000 --- a/.gitignore +++ /dev/null @@ -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/* diff --git a/.hintrc b/.hintrc deleted file mode 100644 index 82cba57..0000000 --- a/.hintrc +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": [ - "development" - ], - "hints": { - "typescript-config/consistent-casing": "off", - "typescript-config/strict": "off" - } -} \ No newline at end of file diff --git a/.prettierrc.js b/.prettierrc.js deleted file mode 100644 index b964930..0000000 --- a/.prettierrc.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - ...require('mwts/.prettierrc.json') -} diff --git a/.vscode/config.code-snippets b/.vscode/config.code-snippets deleted file mode 100644 index 2abbf4f..0000000 --- a/.vscode/config.code-snippets +++ /dev/null @@ -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代码片段" - } -} diff --git a/.vscode/controller.code-snippets b/.vscode/controller.code-snippets deleted file mode 100644 index 5bd7095..0000000 --- a/.vscode/controller.code-snippets +++ /dev/null @@ -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代码片段" - } -} diff --git a/.vscode/entity.code-snippets b/.vscode/entity.code-snippets deleted file mode 100644 index 992a066..0000000 --- a/.vscode/entity.code-snippets +++ /dev/null @@ -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代码片段" - } -} diff --git a/.vscode/event.code-snippets b/.vscode/event.code-snippets deleted file mode 100644 index dae6473..0000000 --- a/.vscode/event.code-snippets +++ /dev/null @@ -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代码片段" - } -} diff --git a/.vscode/middleware.code-snippets b/.vscode/middleware.code-snippets deleted file mode 100644 index 367be90..0000000 --- a/.vscode/middleware.code-snippets +++ /dev/null @@ -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 {", - " resolve() {", - " return async (ctx: Context, next: NextFunction) => {", - " // 控制器前执行的逻辑", - " const startTime = Date.now();", - " // 执行下一个 Web 中间件,最后执行到控制器", - " await next();", - " // 控制器之后执行的逻辑", - " console.log(Date.now() - startTime);", - " };", - " }", - "}", - "" - ], - "description": "cool-admin middleware代码片段" - } -} diff --git a/.vscode/queue.code-snippets b/.vscode/queue.code-snippets deleted file mode 100644 index 3518633..0000000 --- a/.vscode/queue.code-snippets +++ /dev/null @@ -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代码片段" - } -} diff --git a/.vscode/service.code-snippets b/.vscode/service.code-snippets deleted file mode 100644 index 4870279..0000000 --- a/.vscode/service.code-snippets +++ /dev/null @@ -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代码片段" - } -} \ No newline at end of file diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index b68ce7a..0000000 --- a/Dockerfile +++ /dev/null @@ -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"] \ No newline at end of file diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 5a6831d..0000000 --- a/LICENSE +++ /dev/null @@ -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. diff --git a/README.md b/README.md deleted file mode 100644 index a970153..0000000 --- a/README.md +++ /dev/null @@ -1,191 +0,0 @@ -

- Midway Logo -

- -

cool-admin(midway版)一个很酷的后台权限管理系统,开源免费,模块化、插件化、极速开发CRUD,方便快速构建迭代后台管理系统,支持serverless、docker、普通服务器等多种方式部署 -到 官网 进一步了解。 -

- GitHub license - GitHub tag - GitHub tag -

- -## 特性 - -Ai时代,很多老旧的框架已经无法满足现代化的开发需求,Cool-Admin开发了一系列的功能,让开发变得更简单、更快速、更高效。 - -- **Ai编码**:通过微调大模型学习框架特有写法,实现简单功能从Api接口到前端页面的一键生成 -- **流程编排**:通过拖拽编排方式,即可实现类似像智能客服这样的功能 -- **模块化**:代码是模块化的,清晰明了,方便维护 -- **插件化**:插件化的设计,可以通过安装插件的方式扩展如:支付、短信、邮件等功能 - -![](https://cool-show.oss-cn-shanghai.aliyuncs.com/admin/flow.png) - -## 技术栈 - -- 后端:**`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 - -Admin Home - -#### 项目前端 - -[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) - -## 微信群 - -Admin Wechat - -## 运行 - -#### 修改数据库配置,配置文件位于`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) diff --git a/bootstrap.js b/bootstrap.js deleted file mode 100644 index 9c096c2..0000000 --- a/bootstrap.js +++ /dev/null @@ -1,2 +0,0 @@ -const { Bootstrap } = require('@midwayjs/bootstrap'); -Bootstrap.run(); diff --git a/cool/obfuscate.js b/cool/obfuscate.js deleted file mode 100644 index b7d5530..0000000 --- a/cool/obfuscate.js +++ /dev/null @@ -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 目录不存在!'); -} diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index a296994..0000000 --- a/docker-compose.yml +++ /dev/null @@ -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 diff --git a/jest.config.js b/jest.config.js deleted file mode 100644 index c5bd388..0000000 --- a/jest.config.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = { - preset: 'ts-jest', - testEnvironment: 'node', - testPathIgnorePatterns: ['/test/fixtures'], - coveragePathIgnorePatterns: ['/test/'], -}; \ No newline at end of file diff --git a/package.json b/package.json deleted file mode 100644 index 02bdeb6..0000000 --- a/package.json +++ /dev/null @@ -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" -} diff --git a/public/css/welcome.css b/public/css/welcome.css deleted file mode 100644 index c838986..0000000 --- a/public/css/welcome.css +++ /dev/null @@ -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); - } -} diff --git a/public/favicon.ico b/public/favicon.ico deleted file mode 100644 index a0c3086..0000000 Binary files a/public/favicon.ico and /dev/null differ diff --git a/public/js/welcome.js b/public/js/welcome.js deleted file mode 100644 index 05054e8..0000000 --- a/public/js/welcome.js +++ /dev/null @@ -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); -}); diff --git a/public/uploads/说明.md b/public/uploads/说明.md deleted file mode 100644 index 22a298f..0000000 --- a/public/uploads/说明.md +++ /dev/null @@ -1 +0,0 @@ -文件上传目录 \ No newline at end of file diff --git a/src/comm/utils.ts b/src/comm/utils.ts deleted file mode 100644 index f9ba60c..0000000 --- a/src/comm/utils.ts +++ /dev/null @@ -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; - } -} diff --git a/src/config/config.default.ts b/src/config/config.default.ts deleted file mode 100644 index 2aa8331..0000000 --- a/src/config/config.default.ts +++ /dev/null @@ -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; diff --git a/src/config/config.local.ts b/src/config/config.local.ts deleted file mode 100644 index 862721b..0000000 --- a/src/config/config.local.ts +++ /dev/null @@ -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; diff --git a/src/config/config.prod.ts b/src/config/config.prod.ts deleted file mode 100644 index 35f2dbb..0000000 --- a/src/config/config.prod.ts +++ /dev/null @@ -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; diff --git a/src/configuration.ts b/src/configuration.ts deleted file mode 100644 index 9aaaa93..0000000 --- a/src/configuration.ts +++ /dev/null @@ -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() {} -} diff --git a/src/interface.ts b/src/interface.ts deleted file mode 100644 index 13daae8..0000000 --- a/src/interface.ts +++ /dev/null @@ -1,6 +0,0 @@ -/** - * @description User-Service parameters - */ -export interface IUserOptions { - uid: number; -} diff --git a/src/modules/base/config.ts b/src/modules/base/config.ts deleted file mode 100644 index 62e3189..0000000 --- a/src/modules/base/config.ts +++ /dev/null @@ -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; -}; diff --git a/src/modules/base/controller/admin/comm.ts b/src/modules/base/controller/admin/comm.ts deleted file mode 100644 index 439d7b4..0000000 --- a/src/modules/base/controller/admin/comm.ts +++ /dev/null @@ -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'); - } -} diff --git a/src/modules/base/controller/admin/open.ts b/src/modules/base/controller/admin/open.ts deleted file mode 100644 index b42785b..0000000 --- a/src/modules/base/controller/admin/open.ts +++ /dev/null @@ -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: '登录失效~', - }; - } - } -} diff --git a/src/modules/base/controller/admin/sys/department.ts b/src/modules/base/controller/admin/sys/department.ts deleted file mode 100644 index 4c2b0b2..0000000 --- a/src/modules/base/controller/admin/sys/department.ts +++ /dev/null @@ -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(); - } -} diff --git a/src/modules/base/controller/admin/sys/log.ts b/src/modules/base/controller/admin/sys/log.ts deleted file mode 100644 index caf463c..0000000 --- a/src/modules/base/controller/admin/sys/log.ts +++ /dev/null @@ -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')); - } -} diff --git a/src/modules/base/controller/admin/sys/menu.ts b/src/modules/base/controller/admin/sys/menu.ts deleted file mode 100644 index fd3f3d4..0000000 --- a/src/modules/base/controller/admin/sys/menu.ts +++ /dev/null @@ -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(); - } -} diff --git a/src/modules/base/controller/admin/sys/param.ts b/src/modules/base/controller/admin/sys/param.ts deleted file mode 100644 index a6082c7..0000000 --- a/src/modules/base/controller/admin/sys/param.ts +++ /dev/null @@ -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); - } -} diff --git a/src/modules/base/controller/admin/sys/role.ts b/src/modules/base/controller/admin/sys/role.ts deleted file mode 100644 index 586410e..0000000 --- a/src/modules/base/controller/admin/sys/role.ts +++ /dev/null @@ -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 {} diff --git a/src/modules/base/controller/admin/sys/user.ts b/src/modules/base/controller/admin/sys/user.ts deleted file mode 100644 index 82056de..0000000 --- a/src/modules/base/controller/admin/sys/user.ts +++ /dev/null @@ -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(); - } -} diff --git a/src/modules/base/controller/app/README.md b/src/modules/base/controller/app/README.md deleted file mode 100644 index df64e76..0000000 --- a/src/modules/base/controller/app/README.md +++ /dev/null @@ -1 +0,0 @@ -这里写对外的api接口 \ No newline at end of file diff --git a/src/modules/base/controller/app/comm.ts b/src/modules/base/controller/app/comm.ts deleted file mode 100644 index 4c477a3..0000000 --- a/src/modules/base/controller/app/comm.ts +++ /dev/null @@ -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()); - } -} diff --git a/src/modules/base/db.json b/src/modules/base/db.json deleted file mode 100644 index 81ffd6f..0000000 --- a/src/modules/base/db.json +++ /dev/null @@ -1,103 +0,0 @@ -{ - "base_sys_param": [ - { - "keyName": "rich", - "name": "富文本参数", - "data": "

这是一个富文本

xxx

xxxxxxxxxx


", - "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 - } - ] -} \ No newline at end of file diff --git a/src/modules/base/dto/login.ts b/src/modules/base/dto/login.ts deleted file mode 100644 index 5b4b30c..0000000 --- a/src/modules/base/dto/login.ts +++ /dev/null @@ -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; -} diff --git a/src/modules/base/entity/sys/conf.ts b/src/modules/base/entity/sys/conf.ts deleted file mode 100644 index fcfc5e1..0000000 --- a/src/modules/base/entity/sys/conf.ts +++ /dev/null @@ -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; -} diff --git a/src/modules/base/entity/sys/department.ts b/src/modules/base/entity/sys/department.ts deleted file mode 100644 index f340ecc..0000000 --- a/src/modules/base/entity/sys/department.ts +++ /dev/null @@ -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; -} diff --git a/src/modules/base/entity/sys/log.ts b/src/modules/base/entity/sys/log.ts deleted file mode 100644 index c5fb13d..0000000 --- a/src/modules/base/entity/sys/log.ts +++ /dev/null @@ -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; -} diff --git a/src/modules/base/entity/sys/menu.ts b/src/modules/base/entity/sys/menu.ts deleted file mode 100644 index d816713..0000000 --- a/src/modules/base/entity/sys/menu.ts +++ /dev/null @@ -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; -} diff --git a/src/modules/base/entity/sys/param.ts b/src/modules/base/entity/sys/param.ts deleted file mode 100644 index f147f89..0000000 --- a/src/modules/base/entity/sys/param.ts +++ /dev/null @@ -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; -} diff --git a/src/modules/base/entity/sys/role.ts b/src/modules/base/entity/sys/role.ts deleted file mode 100644 index c1498d1..0000000 --- a/src/modules/base/entity/sys/role.ts +++ /dev/null @@ -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[]; -} diff --git a/src/modules/base/entity/sys/role_department.ts b/src/modules/base/entity/sys/role_department.ts deleted file mode 100644 index e0a52a8..0000000 --- a/src/modules/base/entity/sys/role_department.ts +++ /dev/null @@ -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; -} diff --git a/src/modules/base/entity/sys/role_menu.ts b/src/modules/base/entity/sys/role_menu.ts deleted file mode 100644 index 667e312..0000000 --- a/src/modules/base/entity/sys/role_menu.ts +++ /dev/null @@ -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; -} diff --git a/src/modules/base/entity/sys/user.ts b/src/modules/base/entity/sys/user.ts deleted file mode 100644 index a97e7c9..0000000 --- a/src/modules/base/entity/sys/user.ts +++ /dev/null @@ -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; -} diff --git a/src/modules/base/entity/sys/user_role.ts b/src/modules/base/entity/sys/user_role.ts deleted file mode 100644 index c15f00c..0000000 --- a/src/modules/base/entity/sys/user_role.ts +++ /dev/null @@ -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; -} diff --git a/src/modules/base/event/app.ts b/src/modules/base/event/app.ts deleted file mode 100644 index 508b79b..0000000 --- a/src/modules/base/event/app.ts +++ /dev/null @@ -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); - } - } -} diff --git a/src/modules/base/event/menu.ts b/src/modules/base/event/menu.ts deleted file mode 100644 index 3257b43..0000000 --- a/src/modules/base/event/menu.ts +++ /dev/null @@ -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', {}); - } -} diff --git a/src/modules/base/job/log.ts b/src/modules/base/job/log.ts deleted file mode 100644 index 0e35727..0000000 --- a/src/modules/base/job/log.ts +++ /dev/null @@ -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`); - } -} diff --git a/src/modules/base/menu.json b/src/modules/base/menu.json deleted file mode 100644 index c0e0cfb..0000000 --- a/src/modules/base/menu.json +++ /dev/null @@ -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": [] - } - ] - } -] \ No newline at end of file diff --git a/src/modules/base/middleware/authority.ts b/src/modules/base/middleware/authority.ts deleted file mode 100644 index 47e4381..0000000 --- a/src/modules/base/middleware/authority.ts +++ /dev/null @@ -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 -{ - @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; - } -} diff --git a/src/modules/base/middleware/log.ts b/src/modules/base/middleware/log.ts deleted file mode 100644 index 2b3486e..0000000 --- a/src/modules/base/middleware/log.ts +++ /dev/null @@ -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 { - 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(); - }; - } -} diff --git a/src/modules/base/service/sys/conf.ts b/src/modules/base/service/sys/conf.ts deleted file mode 100644 index dbff81d..0000000 --- a/src/modules/base/service/sys/conf.ts +++ /dev/null @@ -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; - - /** - * 获得配置参数值 - * @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(); - } -} diff --git a/src/modules/base/service/sys/data.ts b/src/modules/base/service/sys/data.ts deleted file mode 100644 index 42b03c9..0000000 --- a/src/modules/base/service/sys/data.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { DataSource } from 'typeorm'; - -export class TempDataSource extends DataSource { - /** - * 重新构造元数据 - */ - async buildMetadatas() { - await super.buildMetadatas(); - } -} diff --git a/src/modules/base/service/sys/department.ts b/src/modules/base/service/sys/department.ts deleted file mode 100644 index 714e882..0000000 --- a/src/modules/base/service/sys/department.ts +++ /dev/null @@ -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; - - @InjectEntityModel(BaseSysUserEntity) - baseSysUserEntity: Repository; - - @InjectEntityModel(BaseSysRoleDepartmentEntity) - baseSysRoleDepartmentEntity: Repository; - - @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 } - ); - } - } - } -} diff --git a/src/modules/base/service/sys/log.ts b/src/modules/base/service/sys/log.ts deleted file mode 100644 index 2ed448e..0000000 --- a/src/modules/base/service/sys/log.ts +++ /dev/null @@ -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; - - @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(); - } - } -} diff --git a/src/modules/base/service/sys/login.ts b/src/modules/base/service/sys/login.ts deleted file mode 100644 index f4faf87..0000000 --- a/src/modules/base/service/sys/login.ts +++ /dev/null @@ -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; - - @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; - } - } -} diff --git a/src/modules/base/service/sys/menu.ts b/src/modules/base/service/sys/menu.ts deleted file mode 100644 index b07d132..0000000 --- a/src/modules/base/service/sys/menu.ts +++ /dev/null @@ -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; - - @InjectEntityModel(BaseSysRoleMenuEntity) - baseSysRoleMenuEntity: Repository; - - @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); - } - } - } -} diff --git a/src/modules/base/service/sys/param.ts b/src/modules/base/service/sys/param.ts deleted file mode 100644 index 7e75a26..0000000 --- a/src/modules/base/service/sys/param.ts +++ /dev/null @@ -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; - - @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 = '@title@content'; - 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 { - 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); - } - } -} diff --git a/src/modules/base/service/sys/perms.ts b/src/modules/base/service/sys/perms.ts deleted file mode 100644 index fc64f21..0000000 --- a/src/modules/base/service/sys/perms.ts +++ /dev/null @@ -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; - - @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 []; - } - } -} diff --git a/src/modules/base/service/sys/role.ts b/src/modules/base/service/sys/role.ts deleted file mode 100644 index e013b52..0000000 --- a/src/modules/base/service/sys/role.ts +++ /dev/null @@ -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; - - @InjectEntityModel(BaseSysUserRoleEntity) - baseSysUserRoleEntity: Repository; - - @InjectEntityModel(BaseSysRoleMenuEntity) - baseSysRoleMenuEntity: Repository; - - @InjectEntityModel(BaseSysRoleDepartmentEntity) - baseSysRoleDepartmentEntity: Repository; - - @Inject() - baseSysPermsService: BaseSysPermsService; - - @Inject() - ctx; - - /** - * 根据用户ID获得所有用户角色 - * @param userId - */ - async getByUser(userId: number): Promise { - 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(); - } -} diff --git a/src/modules/base/service/sys/user.ts b/src/modules/base/service/sys/user.ts deleted file mode 100644 index 96c3bc8..0000000 --- a/src/modules/base/service/sys/user.ts +++ /dev/null @@ -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; - - @InjectEntityModel(BaseSysUserRoleEntity) - baseSysUserRoleEntity: Repository; - - @InjectEntityModel(BaseSysDepartmentEntity) - baseSysDepartmentEntity: Repository; - - @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}`); - } -} diff --git a/src/modules/demo/config.ts b/src/modules/demo/config.ts deleted file mode 100644 index a0f978c..0000000 --- a/src/modules/demo/config.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { ModuleConfig } from '@cool-midway/core'; - -/** - * 模块配置 - */ -export default () => { - return { - // 模块名称 - name: 'demo模块', - // 模块描述 - description: '演示用', - // 中间件,只对本模块有效 - middlewares: [], - // 中间件,全局有效 - globalMiddlewares: [], - // 模块加载顺序,默认为0,值越大越优先加载 - order: 0, - } as ModuleConfig; -}; diff --git a/src/modules/demo/controller/admin/goods.ts b/src/modules/demo/controller/admin/goods.ts deleted file mode 100644 index 2bf6fdb..0000000 --- a/src/modules/demo/controller/admin/goods.ts +++ /dev/null @@ -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 {} diff --git a/src/modules/demo/controller/open/cache.ts b/src/modules/demo/controller/open/cache.ts deleted file mode 100644 index cf3ac4b..0000000 --- a/src/modules/demo/controller/open/cache.ts +++ /dev/null @@ -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()); - } -} diff --git a/src/modules/demo/controller/open/event.ts b/src/modules/demo/controller/open/event.ts deleted file mode 100644 index 826bf6f..0000000 --- a/src/modules/demo/controller/open/event.ts +++ /dev/null @@ -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(); - } -} diff --git a/src/modules/demo/controller/open/goods.ts b/src/modules/demo/controller/open/goods.ts deleted file mode 100644 index 8a42ecd..0000000 --- a/src/modules/demo/controller/open/goods.ts +++ /dev/null @@ -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; - - @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)); - } -} diff --git a/src/modules/demo/controller/open/plugin.ts b/src/modules/demo/controller/open/plugin.ts deleted file mode 100644 index c2d3310..0000000 --- a/src/modules/demo/controller/open/plugin.ts +++ /dev/null @@ -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(); - } -} diff --git a/src/modules/demo/controller/open/queue.ts b/src/modules/demo/controller/open/queue.ts deleted file mode 100644 index df5c639..0000000 --- a/src/modules/demo/controller/open/queue.ts +++ /dev/null @@ -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); - } -} diff --git a/src/modules/demo/controller/open/rpc.ts b/src/modules/demo/controller/open/rpc.ts deleted file mode 100644 index 2086169..0000000 --- a/src/modules/demo/controller/open/rpc.ts +++ /dev/null @@ -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(); - } -} diff --git a/src/modules/demo/controller/open/sse.ts b/src/modules/demo/controller/open/sse.ts deleted file mode 100644 index 9733dd2..0000000 --- a/src/modules/demo/controller/open/sse.ts +++ /dev/null @@ -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; - } -} diff --git a/src/modules/demo/controller/open/transaction.ts b/src/modules/demo/controller/open/transaction.ts deleted file mode 100644 index 804f055..0000000 --- a/src/modules/demo/controller/open/transaction.ts +++ /dev/null @@ -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 {} diff --git a/src/modules/demo/entity/goods.ts b/src/modules/demo/entity/goods.ts deleted file mode 100644 index 4667633..0000000 --- a/src/modules/demo/entity/goods.ts +++ /dev/null @@ -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; -} diff --git a/src/modules/demo/event/comm.ts b/src/modules/demo/event/comm.ts deleted file mode 100644 index ae00a64..0000000 --- a/src/modules/demo/event/comm.ts +++ /dev/null @@ -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 插件已就绪 - } -} diff --git a/src/modules/demo/queue/comm.ts b/src/modules/demo/queue/comm.ts deleted file mode 100644 index 7bb9134..0000000 --- a/src/modules/demo/queue/comm.ts +++ /dev/null @@ -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 { - // 这边可以执行定时任务具体的业务或队列的业务 - console.log('数据', job.data); - // 抛出错误 可以让队列重试,默认重试5次 - //throw new Error('错误'); - done(); - } -} diff --git a/src/modules/demo/queue/getter.ts b/src/modules/demo/queue/getter.ts deleted file mode 100644 index 8da42c9..0000000 --- a/src/modules/demo/queue/getter.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { BaseCoolQueue, CoolQueue } from '@cool-midway/task'; - -/** - * 主动消费队列 - */ -@CoolQueue({ type: 'getter' }) -export class DemoGetterQueue extends BaseCoolQueue {} diff --git a/src/modules/demo/queue/single.ts b/src/modules/demo/queue/single.ts deleted file mode 100644 index 67bcc6b..0000000 --- a/src/modules/demo/queue/single.ts +++ /dev/null @@ -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 { - // 这边可以执行定时任务具体的业务或队列的业务 - console.log('数据', job.data); - // 抛出错误 可以让队列重试,默认重试5次 - //throw new Error('错误'); - done(); - } -} diff --git a/src/modules/demo/service/cache.ts b/src/modules/demo/service/cache.ts deleted file mode 100644 index 01d3de8..0000000 --- a/src/modules/demo/service/cache.ts +++ /dev/null @@ -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, - }; - } -} diff --git a/src/modules/demo/service/goods.ts b/src/modules/demo/service/goods.ts deleted file mode 100644 index 979656a..0000000 --- a/src/modules/demo/service/goods.ts +++ /dev/null @@ -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; - - /** - * 执行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); - } -} diff --git a/src/modules/demo/service/rpc.ts b/src/modules/demo/service/rpc.ts deleted file mode 100644 index e95ca39..0000000 --- a/src/modules/demo/service/rpc.ts +++ /dev/null @@ -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, - }); - } -} diff --git a/src/modules/demo/service/transaction.ts b/src/modules/demo/service/transaction.ts deleted file mode 100644 index 3aa45e8..0000000 --- a/src/modules/demo/service/transaction.ts +++ /dev/null @@ -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, param); - return { - id: param.id, - }; - } -} diff --git a/src/modules/dict/config.ts b/src/modules/dict/config.ts deleted file mode 100644 index 0c7e579..0000000 --- a/src/modules/dict/config.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { ModuleConfig } from '@cool-midway/core'; - -/** - * 模块配置 - */ -export default () => { - return { - // 模块名称 - name: '字典管理', - // 模块描述 - description: '数据字典等', - // 中间件,只对本模块有效 - middlewares: [], - // 中间件,全局有效 - globalMiddlewares: [], - // 模块加载顺序,默认为0,值越大越优先加载 - order: 0, - } as ModuleConfig; -}; diff --git a/src/modules/dict/controller/admin/info.ts b/src/modules/dict/controller/admin/info.ts deleted file mode 100644 index ebe684a..0000000 --- a/src/modules/dict/controller/admin/info.ts +++ /dev/null @@ -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)); - } -} diff --git a/src/modules/dict/controller/admin/type.ts b/src/modules/dict/controller/admin/type.ts deleted file mode 100644 index e31cdd8..0000000 --- a/src/modules/dict/controller/admin/type.ts +++ /dev/null @@ -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 {} diff --git a/src/modules/dict/controller/app/info.ts b/src/modules/dict/controller/app/info.ts deleted file mode 100644 index b83a849..0000000 --- a/src/modules/dict/controller/app/info.ts +++ /dev/null @@ -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)); - } -} diff --git a/src/modules/dict/db.json b/src/modules/dict/db.json deleted file mode 100644 index 31c79a2..0000000 --- a/src/modules/dict/db.json +++ /dev/null @@ -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" - } - ] -} \ No newline at end of file diff --git a/src/modules/dict/entity/info.ts b/src/modules/dict/entity/info.ts deleted file mode 100644 index 68d4701..0000000 --- a/src/modules/dict/entity/info.ts +++ /dev/null @@ -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; -} diff --git a/src/modules/dict/entity/type.ts b/src/modules/dict/entity/type.ts deleted file mode 100644 index 1b5d1b4..0000000 --- a/src/modules/dict/entity/type.ts +++ /dev/null @@ -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; -} diff --git a/src/modules/dict/service/info.ts b/src/modules/dict/service/info.ts deleted file mode 100644 index 5643e09..0000000 --- a/src/modules/dict/service/info.ts +++ /dev/null @@ -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; - - @InjectEntityModel(DictTypeEntity) - dictTypeEntity: Repository; - - @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); - } - } -} diff --git a/src/modules/dict/service/type.ts b/src/modules/dict/service/type.ts deleted file mode 100644 index 7ff4b9d..0000000 --- a/src/modules/dict/service/type.ts +++ /dev/null @@ -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; - - /** - * 删除 - * @param ids - */ - async delete(ids) { - super.delete(ids); - await this.dictInfoEntity.delete({ - typeId: In(ids), - }); - } -} diff --git a/src/modules/plugin/config.ts b/src/modules/plugin/config.ts deleted file mode 100644 index 74aa56b..0000000 --- a/src/modules/plugin/config.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { ModuleConfig } from '@cool-midway/core'; - -/** - * 模块配置 - */ -export default options => { - return { - // 模块名称 - name: '插件模块', - // 模块描述 - description: '插件查看、安装、卸载、配置等', - // 中间件,只对本模块有效 - middlewares: [], - // 中间件,全局有效 - globalMiddlewares: [], - // 模块加载顺序,默认为0,值越大越优先加载 - order: 0, - // 基础插件配置 - hooks: { - // 文件上传 - upload: { - // 地址前缀 - domain: `http://127.0.0.1:${options?.app?.getConfig('koa.port')}`, - }, - }, - } as ModuleConfig; -}; diff --git a/src/modules/plugin/controller/admin/info.ts b/src/modules/plugin/controller/admin/info.ts deleted file mode 100644 index f8c9e15..0000000 --- a/src/modules/plugin/controller/admin/info.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { - CoolController, - BaseController, - CoolTag, - CoolUrlTag, - TagTypes, -} from '@cool-midway/core'; -import { PluginInfoEntity } from '../../entity/info'; -import { Body, Fields, Files, Inject, Post } from '@midwayjs/core'; -import { PluginService } from '../../service/info'; - -/** - * 插件信息 - */ -@CoolUrlTag({ - key: TagTypes.IGNORE_TOKEN, - value: [], -}) -@CoolController({ - api: ['add', 'delete', 'update', 'info', 'list', 'page'], - entity: PluginInfoEntity, - service: PluginService, - pageQueryOp: { - select: [ - 'a.id', - 'a.name', - 'a.keyName', - 'a.hook', - 'a.version', - 'a.status', - 'a.readme', - 'a.author', - 'a.logo', - 'a.description', - 'a.pluginJson', - 'a.config', - 'a.createTime', - 'a.updateTime', - ], - addOrderBy: { - id: 'DESC', - }, - }, -}) -export class AdminPluginInfoController extends BaseController { - @Inject() - pluginService: PluginService; - - @CoolTag(TagTypes.IGNORE_TOKEN) - @Post('/install', { summary: '安装插件' }) - async install(@Files() files, @Fields() fields) { - return this.ok( - await this.pluginService.install(files[0].data, fields.force) - ); - } -} diff --git a/src/modules/plugin/entity/info.ts b/src/modules/plugin/entity/info.ts deleted file mode 100644 index 2c75d57..0000000 --- a/src/modules/plugin/entity/info.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { BaseEntity } from '@cool-midway/core'; -import { Column, Entity, DataSource, Index } from 'typeorm'; - -console.log(DataSource); - -/** - * 插件信息 - */ -@Entity('plugin_info') -export class PluginInfoEntity extends BaseEntity { - @Column({ comment: '名称' }) - name: string; - - @Column({ comment: '简介' }) - description: string; - - @Index() - @Column({ comment: 'Key名' }) - keyName: string; - - @Column({ comment: 'Hook' }) - hook: string; - - @Column({ comment: '描述', type: 'text' }) - readme: string; - - @Column({ comment: '版本' }) - version: string; - - @Column({ comment: 'Logo(base64)', type: 'text', nullable: true }) - logo: string; - - @Column({ comment: '作者' }) - author: string; - - @Column({ comment: '状态 0-禁用 1-启用', default: 0 }) - status: number; - - @Column({ comment: '插件的plugin.json', type: 'json', nullable: true }) - pluginJson: any; - - @Column({ comment: '配置', type: 'json', nullable: true }) - config: any; -} diff --git a/src/modules/plugin/event/app.ts b/src/modules/plugin/event/app.ts deleted file mode 100644 index 2ef8f5c..0000000 --- a/src/modules/plugin/event/app.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { CoolEvent, Event } from '@cool-midway/core'; -import { CachingFactory, MidwayCache } from '@midwayjs/cache-manager'; -import { - App, - Config, - ILogger, - Inject, - InjectClient, - Logger, -} from '@midwayjs/core'; -import { IMidwayKoaApplication } from '@midwayjs/koa'; -import { PLUGIN_CACHE_KEY, PluginCenterService } from '../service/center'; -import { PluginTypesService } from '../service/types'; - -/** - * 插件事件 - */ -@CoolEvent() -export class PluginAppEvent { - @Logger() - coreLogger: ILogger; - - @Config('module') - config; - - @App() - app: IMidwayKoaApplication; - - @InjectClient(CachingFactory, 'default') - midwayCache: MidwayCache; - - @Inject() - pluginCenterService: PluginCenterService; - - @Inject() - pluginTypesService: PluginTypesService; - - @Event('onServerReady') - async onServerReady() { - await this.midwayCache.set(PLUGIN_CACHE_KEY, []); - this.pluginCenterService.init(); - // this.pluginTypesService.reGenerate(); - } -} diff --git a/src/modules/plugin/event/init.ts b/src/modules/plugin/event/init.ts deleted file mode 100644 index 4a55409..0000000 --- a/src/modules/plugin/event/init.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { CoolEvent, Event } from '@cool-midway/core'; -import { Inject } from '@midwayjs/core'; -import { PluginCenterService } from '../service/center'; - -// 插件初始化全局事件 -export const GLOBAL_EVENT_PLUGIN_INIT = 'globalPluginInit'; -// 插件移除全局事件 -export const GLOBAL_EVENT_PLUGIN_REMOVE = 'globalPluginRemove'; - -/** - * 接收事件 - */ -@CoolEvent() -export class PluginInitEvent { - @Inject() - pluginCenterService: PluginCenterService; - - /** - * 插件初始化事件,某个插件重新初始化 - * @param key - */ - @Event(GLOBAL_EVENT_PLUGIN_INIT) - async globalPluginInit(key: string) { - await this.pluginCenterService.initOne(key); - } - - /** - * 插件移除或者关闭事件 - * @param key - * @param isHook - */ - @Event(GLOBAL_EVENT_PLUGIN_REMOVE) - async globalPluginRemove(key: string, isHook: boolean) { - await this.pluginCenterService.remove(key, isHook); - } -} diff --git a/src/modules/plugin/hooks/base.ts b/src/modules/plugin/hooks/base.ts deleted file mode 100644 index 05aa206..0000000 --- a/src/modules/plugin/hooks/base.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { IMidwayContext, IMidwayApplication } from '@midwayjs/core'; -import { PluginInfo } from '../interface'; - -/** - * hook基类 - */ -export class BasePluginHook { - /** 请求上下文,用到此项无法本地调试,需安装到cool-admin中才能调试 */ - ctx: IMidwayContext; - /** 应用实例,用到此项无法本地调试,需安装到cool-admin中才能调试 */ - app: IMidwayApplication; - /** 插件信息 */ - pluginInfo: PluginInfo; - /** - * 初始化 - */ - async init( - pluginInfo: PluginInfo, - ctx?: IMidwayContext, - app?: IMidwayApplication - ) { - this.pluginInfo = pluginInfo; - this.ctx = ctx; - this.app = app; - } -} diff --git a/src/modules/plugin/hooks/upload/index.ts b/src/modules/plugin/hooks/upload/index.ts deleted file mode 100644 index a29df88..0000000 --- a/src/modules/plugin/hooks/upload/index.ts +++ /dev/null @@ -1,122 +0,0 @@ -import { BaseUpload, MODETYPE } from './interface'; -import { BasePluginHook } from '../base'; -import * as fs from 'fs'; -import * as path from 'path'; -import * as moment from 'moment'; -import { v1 as uuid } from 'uuid'; -import { CoolCommException } from '@cool-midway/core'; -import * as _ from 'lodash'; - -/** - * 文件上传 - */ -export class CoolPlugin extends BasePluginHook implements BaseUpload { - /** - * 获得上传模式 - * @returns - */ - async getMode() { - return { - mode: MODETYPE.LOCAL, - type: MODETYPE.LOCAL, - }; - } - - /** - * 获得原始操作对象 - * @returns - */ - async getMetaFileObj() { - return; - } - - /** - * 下载并上传 - * @param url - * @param fileName - */ - async downAndUpload(url: string, fileName?: string) { - const { domain } = this.pluginInfo.config; - // 从url获取扩展名 - const extend = path.extname(url); - const download = require('download'); - // 数据 - const data = url.includes('http') - ? await download(url) - : fs.readFileSync(url); - // 创建文件夹 - const dirPath = path.join( - this.app.getBaseDir(), - '..', - `public/uploads/${moment().format('YYYYMMDD')}` - ); - if (!fs.existsSync(dirPath)) { - fs.mkdirSync(dirPath, { recursive: true }); - } - const uuidStr = uuid(); - const name = `uploads/${moment().format('YYYYMMDD')}/${ - fileName ? fileName : uuidStr + extend - }`; - fs.writeFileSync( - `${dirPath}/${fileName ? fileName : uuid() + extend}`, - data - ); - return `${domain}/public/${name}`; - } - - /** - * 指定Key(路径)上传,本地文件上传到存储服务 - * @param filePath 文件路径 - * @param key 路径一致会覆盖源文件 - */ - async uploadWithKey(filePath: any, key: any) { - const { domain } = this.pluginInfo.config; - const data = fs.readFileSync(filePath); - fs.writeFileSync(path.join(this.app.getBaseDir(), '..', key), data); - return domain + key; - } - - /** - * 上传文件 - * @param ctx - * @param key 文件路径 - */ - async upload(ctx: any) { - const { domain } = this.pluginInfo.config; - try { - const { key } = ctx.fields; - if (_.isEmpty(ctx.files)) { - throw new CoolCommException('上传文件为空'); - } - // 检查public/uploads文件夹是否存在,不存在则创建 - const basePath = path.join( - this.app.getBaseDir(), - '..', - 'public', - 'uploads' - ); - if (!fs.existsSync(basePath)) { - fs.mkdirSync(basePath); - } - - const file = ctx.files[0]; - const extension = file.filename.split('.').pop(); - const name = - moment().format('YYYYMMDD') + '/' + (key || `${uuid()}.${extension}`); - const target = path.join(basePath, name); - const dirPath = path.join(basePath, moment().format('YYYYMMDD')); - if (!fs.existsSync(dirPath)) { - fs.mkdirSync(dirPath); - } - const data = fs.readFileSync(file.data); - fs.writeFileSync(target, data); - return domain + '/public/uploads/' + name; - } catch (err) { - console.error(err); - throw new CoolCommException('上传失败' + err.message); - } - } -} - -// 导出插件实例, Plugin名称不可修改 -export const Plugin = CoolPlugin; diff --git a/src/modules/plugin/hooks/upload/interface.ts b/src/modules/plugin/hooks/upload/interface.ts deleted file mode 100644 index 4f0cdfc..0000000 --- a/src/modules/plugin/hooks/upload/interface.ts +++ /dev/null @@ -1,56 +0,0 @@ -// 模式 -export enum MODETYPE { - // 本地 - LOCAL = 'local', - // 云存储 - CLOUD = 'cloud', - // 其他 - OTHER = 'other', -} - -/** - * 上传模式 - */ -export interface Mode { - // 模式 - mode: MODETYPE; - // 类型 - type: string; -} - -/** - * 文件上传 - */ -export interface BaseUpload { - /** - * 获得上传模式 - */ - getMode(): Promise; - - /** - * 获得原始操作对象 - * @returns - */ - getMetaFileObj(): Promise; - - /** - * 下载并上传 - * @param url - * @param fileName 文件名 - */ - downAndUpload(url: string, fileName?: string): Promise; - - /** - * 指定Key(路径)上传,本地文件上传到存储服务 - * @param filePath 文件路径 - * @param key 路径一致会覆盖源文件 - */ - uploadWithKey(filePath, key): Promise; - - /** - * 上传文件 - * @param ctx - * @param key 文件路径 - */ - upload(ctx): Promise; -} diff --git a/src/modules/plugin/interface.ts b/src/modules/plugin/interface.ts deleted file mode 100644 index 5af915d..0000000 --- a/src/modules/plugin/interface.ts +++ /dev/null @@ -1,25 +0,0 @@ -/** - * 插件信息 - */ -export interface PluginInfo { - /** 名称 */ - name?: string; - /** 唯一标识 */ - key?: string; - /** 钩子 */ - hook?: string; - /** 是否单例 */ - singleton?: boolean; - /** 版本 */ - version?: string; - /** 描述 */ - description?: string; - /** 作者 */ - author?: string; - /** logo */ - logo?: string; - /** README 使用说明 */ - readme?: string; - /** 配置 */ - config?: any; -} diff --git a/src/modules/plugin/service/center.ts b/src/modules/plugin/service/center.ts deleted file mode 100644 index a922a17..0000000 --- a/src/modules/plugin/service/center.ts +++ /dev/null @@ -1,200 +0,0 @@ -import { Provide } from '@midwayjs/decorator'; -import { - App, - IMidwayApplication, - Inject, - InjectClient, - Scope, - ScopeEnum, -} from '@midwayjs/core'; -import * as fs from 'fs'; -import * as path from 'path'; -import { PluginInfoEntity } from '../entity/info'; -import { InjectEntityModel } from '@midwayjs/typeorm'; -import { Repository } from 'typeorm'; -import { PluginInfo } from '../interface'; -import * as _ from 'lodash'; -import { CachingFactory, MidwayCache } from '@midwayjs/cache-manager'; -import { CoolEventManager } from '@cool-midway/core'; -import { PluginService } from './info'; - -export const PLUGIN_CACHE_KEY = 'plugin:init'; - -export const EVENT_PLUGIN_READY = 'EVENT_PLUGIN_READY'; - -/** - * 插件中心 - */ -@Provide() -@Scope(ScopeEnum.Singleton) -export class PluginCenterService { - // 插件列表 - plugins: Map = new Map(); - - // 插件配置 - pluginInfos: Map = new Map(); - - @App() - app: IMidwayApplication; - - @InjectEntityModel(PluginInfoEntity) - pluginInfoEntity: Repository; - - @InjectClient(CachingFactory, 'default') - midwayCache: MidwayCache; - - @Inject() - coolEventManager: CoolEventManager; - - @Inject() - pluginService: PluginService; - - /** - * 初始化 - * @returns - */ - async init() { - this.plugins.clear(); - await this.initHooks(); - await this.initPlugin(); - this.coolEventManager.emit(EVENT_PLUGIN_READY); - } - - /** - * 初始化一个 - * @param keyName key名 - */ - async initOne(keyName: string) { - await this.initPlugin({ - keyName, - }); - this.coolEventManager.emit(EVENT_PLUGIN_READY, keyName); - } - - /** - * 移除插件 - * @param keyName - * @param isHook - */ - async remove(keyName: string, isHook = false) { - this.plugins.delete(keyName); - this.pluginInfos.delete(keyName); - if (isHook) { - await this.initHooks(); - } - } - - /** - * 注册插件 - * @param key 唯一标识 - * @param cls 类 - * @param pluginInfo 插件信息 - */ - async register(key: string, cls: any, pluginInfo?: PluginInfo) { - // 单例插件 - if (pluginInfo?.singleton) { - const instance = new cls(); - await instance.init(this.pluginInfos.get(key), null, this.app, { - cache: this.midwayCache, - pluginService: this.pluginService, - }); - this.plugins.set(key, instance); - } else { - // 普通插件 - this.plugins.set(key, cls); - } - } - - /** - * 初始化钩子 - */ - async initHooks() { - const hooksPath = path.join( - this.app.getBaseDir(), - 'modules', - 'plugin', - 'hooks' - ); - for (const key of fs.readdirSync(hooksPath)) { - const stat = fs.statSync(path.join(hooksPath, key)); - if (!stat.isDirectory()) { - continue; - } - const { Plugin } = await import(path.join(hooksPath, key, 'index')); - await this.register(key, Plugin); - this.pluginInfos.set(key, { - name: key, - config: this.app.getConfig('module.plugin.hooks.' + key), - }); - } - } - - /** - * 初始化插件 - * @param condition 插件条件 - */ - async initPlugin(condition?: { - hook?: string; - id?: number; - keyName?: string; - }) { - let find: any = { status: 1 }; - if (condition) { - find = { - ...find, - ...condition, - }; - } - const plugins = await this.pluginInfoEntity.findBy(find); - for (const plugin of plugins) { - const data = await this.pluginService.getData(plugin.keyName); - if (!data) { - continue; - } - const instance = await this.getInstance(data.content.data); - const pluginInfo = { - ...plugin.pluginJson, - config: this.getConfig(plugin.config), - }; - if (plugin.hook) { - this.pluginInfos.set(plugin.hook, pluginInfo); - await this.register(plugin.hook, instance, pluginInfo); - } else { - this.pluginInfos.set(plugin.keyName, pluginInfo); - await this.register(plugin.keyName, instance, pluginInfo); - } - } - } - - /** - * 获得配置 - * @param config - * @returns - */ - private getConfig(config: any) { - const env = this.app.getEnv(); - let isMulti = false; - for (const key in config) { - if (key.includes('@')) { - isMulti = true; - break; - } - } - return isMulti ? config[`@${env}`] : config; - } - - /** - * 获得实例 - * @param content - * @returns - */ - async getInstance(content: string) { - let _instance; - const script = ` - ${content} - _instance = Plugin; - `; - eval(script); - return _instance; - } -} diff --git a/src/modules/plugin/service/info.ts b/src/modules/plugin/service/info.ts deleted file mode 100644 index ea977dc..0000000 --- a/src/modules/plugin/service/info.ts +++ /dev/null @@ -1,445 +0,0 @@ -import { App, Inject, Provide } from '@midwayjs/decorator'; -import { - BaseService, - CoolCommException, - CoolEventManager, -} from '@cool-midway/core'; -import { InjectEntityModel } from '@midwayjs/typeorm'; -import { Equal, In, Not, Repository } from 'typeorm'; -import { PluginInfoEntity } from '../entity/info'; -import { - Config, - ILogger, - IMidwayApplication, - IMidwayContext, - InjectClient, - Logger, -} from '@midwayjs/core'; -import * as _ from 'lodash'; -import { PluginInfo } from '../interface'; -import { PluginCenterService } from './center'; -import { CachingFactory, MidwayCache } from '@midwayjs/cache-manager'; -import { - GLOBAL_EVENT_PLUGIN_INIT, - GLOBAL_EVENT_PLUGIN_REMOVE, -} from '../event/init'; -import { PluginMap, AnyString } from '../../../../typings/plugin'; -import { PluginTypesService } from './types'; -import * as path from 'path'; -import * as fs from 'fs'; -/** - * 插件信息 - */ -@Provide() -export class PluginService extends BaseService { - @InjectEntityModel(PluginInfoEntity) - pluginInfoEntity: Repository; - - @Inject() - ctx: IMidwayContext; - - @App() - app: IMidwayApplication; - - @Inject() - pluginCenterService: PluginCenterService; - - @Config('module.plugin.hooks') - hooksConfig; - - @InjectClient(CachingFactory, 'default') - midwayCache: MidwayCache; - - @Inject() - coolEventManager: CoolEventManager; - - @Inject() - pluginTypesService: PluginTypesService; - - @Logger() - logger: ILogger; - - /** - * 新增或更新 - * @param param - * @param type - */ - async addOrUpdate(param: any, type?: 'add' | 'update') { - await super.addOrUpdate(param, type); - const info = await this.pluginInfoEntity - .createQueryBuilder('a') - .select(['a.id', 'a.keyName', 'a.status', 'a.hook']) - .where({ - id: Equal(param.id), - }) - .getOne(); - if (info.status == 1) { - await this.reInit(info.keyName); - } else { - await this.remove(info.keyName, !!info.hook); - } - } - - /** - * 重新初始化插件 - */ - async reInit(keyName: string) { - // 多进程发送全局事件,pm2下生效,本地开发则通过普通事件 - this.coolEventManager.globalEmit(GLOBAL_EVENT_PLUGIN_INIT, false, keyName); - } - - /** - * 移除插件 - * @param keyName - * @param isHook - */ - async remove(keyName: string, isHook = false) { - // 多进程发送全局事件,pm2下生效 - this.coolEventManager.globalEmit( - GLOBAL_EVENT_PLUGIN_REMOVE, - false, - keyName, - isHook - ); - this.pluginTypesService.deleteDtsFile(keyName); - } - - /** - * 删除不经过回收站 - * @param ids - */ - async delete(ids: any) { - const list = await this.pluginInfoEntity.findBy({ id: In(ids) }); - for (const item of list) { - await this.remove(item.keyName, !!item.hook); - // 删除文件 - await this.deleteData(item.keyName); - } - await this.pluginInfoEntity.delete(ids); - } - - /** - * 更新 - * @param param - */ - async update(param: any) { - const old = await this.pluginInfoEntity.findOne({ - where: { id: param.id }, - select: ['id', 'status', 'hook'], - }); - // 启用插件,禁用同名插件 - if (old.hook && param.status == 1 && old.status != param.status) { - await this.pluginInfoEntity.update( - { hook: old.hook, status: 1, id: Not(old.id) }, - { status: 0 } - ); - } - await super.update(param); - } - - /** - * 获得插件配置 - * @param key - */ - async getConfig(key: string) { - return this.pluginCenterService.pluginInfos.get(key)?.config; - } - - /** - * 调用插件 - * @param key 插件key - * @param method 方法 - * @param params 参数 - * @returns - */ - async invoke( - key: K | AnyString, - method: string, - ...params - ) { - // 实例 - const instance: any = await this.getInstance(key); - return await instance[method](...params); - } - - /** - * 获得插件实例 - * @param key - * @returns - */ - async getInstance( - key: K | AnyString - ): Promise { - const check = await this.checkStatus(key); - if (!check) throw new CoolCommException(`插件[${key}]不存在或已禁用`); - let instance; - const pluginInfo = this.pluginCenterService.pluginInfos.get(key); - if (pluginInfo.singleton) { - instance = this.pluginCenterService.plugins.get(key); - } else { - instance = new (await this.pluginCenterService.plugins.get(key))(); - await instance.init(pluginInfo, this.ctx, this.app, { - cache: this.midwayCache, - pluginService: this, - }); - } - return instance; - } - - /** - * 检查状态 - * @param key - */ - async checkStatus(key: string) { - if (Object.keys(this.hooksConfig).includes(key)) { - return true; - } - const info = await this.pluginInfoEntity - .createQueryBuilder('a') - .select(['a.id', 'a.status']) - .where({ status: 1, keyName: Equal(key) }) - .getOne(); - - return !!info; - } - - /** - * 检查 - * @param filePath - */ - async check(filePath: string) { - let data; - try { - data = await this.data(filePath); - } catch (e) { - return { - type: 0, - message: `插件信息不完整,请检查${data.errorData}`, - }; - } - const check = await this.pluginInfoEntity.findOne({ - where: { keyName: Equal(data.pluginJson.key) }, - select: ['id', 'hook', 'status'], - }); - if (check && !check.hook) { - return { - type: 1, - message: '插件已存在,继续安装将覆盖', - }; - } - if (check && check.hook && check.status == 1) { - return { - type: 2, - message: - '已存在同名Hook插件,你可以继续安装,但是多个相同的Hook插件只能同时开启一个', - }; - } - return { - type: 3, - message: '检查通过', - }; - } - - /** - * 获得插件数据 - * @param filePath - */ - async data(filePath: string): Promise<{ - pluginJson: any; - readme: string; - logo: string; - content: string; - tsContent: string; - errorData: string; - }> { - const decompress = require('decompress'); - const files = await decompress(filePath); - let errorData; - let pluginJson: PluginInfo, - readme: string, - logo: string, - content: string, - tsContent: string; - try { - errorData = 'plugin.json'; - pluginJson = JSON.parse( - _.find(files, { path: 'plugin.json', type: 'file' }).data.toString() - ); - errorData = 'readme'; - readme = _.find(files, { - path: pluginJson.readme, - type: 'file', - }).data.toString(); - errorData = 'logo'; - logo = _.find(files, { - path: pluginJson.logo, - type: 'file', - }).data.toString('base64'); - content = _.find(files, { - path: 'src/index.js', - type: 'file', - }).data.toString(); - tsContent = - _.find(files, { - path: 'source/index.ts', - type: 'file', - })?.data?.toString() || ''; - } catch (e) { - throw new CoolCommException('插件信息不完整'); - } - return { - pluginJson, - readme, - logo, - content, - tsContent, - errorData, - }; - } - - /** - * 安装插件 - * @param file 文件 - * @param force 是否强制安装 - */ - async install(filePath: string, force = false) { - const forceBool = typeof force === 'string' ? force === 'true' : force; - const checkResult = await this.check(filePath); - if (checkResult.type != 3 && !forceBool) { - return checkResult; - } - const { pluginJson, readme, logo, content, tsContent } = await this.data( - filePath - ); - if (pluginJson.key == 'plugin') { - throw new CoolCommException('插件key不能为plugin,请更换其他key'); - } - const check = await this.pluginInfoEntity.findOne({ - where: { keyName: Equal(pluginJson.key) }, - select: ['id', 'status', 'config'], - }); - const data = { - name: pluginJson.name, - keyName: pluginJson.key, - version: pluginJson.version, - author: pluginJson.author, - hook: pluginJson.hook, - readme, - logo, - description: pluginJson.description, - pluginJson, - config: pluginJson.config, - status: 1, - } as PluginInfoEntity; - // 存在同名插件,更新,保留配置 - if (check) { - await this.pluginInfoEntity.update(check.id, { - ...data, - status: check.status, - config: { - ...pluginJson.config, - ...check.config, - }, - }); - } else { - // 全新安装 - await this.pluginInfoEntity.insert(data); - } - // 保存插件内容 - await this.saveData( - { - content: { - type: 'comm', - data: content, - }, - tsContent: { - type: 'ts', - data: tsContent, - }, - }, - pluginJson.key - ); - this.pluginTypesService.generateDtsFile(pluginJson.key, tsContent); - // 初始化插件 - await this.reInit(pluginJson.key); - } - - /** - * 将插件内容保存到文件 - * @param content 内容 - * @param keyName 插件key - */ - async saveData( - data: { - content: { - type: 'comm' | 'module'; - data: string; - }; - tsContent: { - type: 'ts'; - data: string; - }; - }, - keyName: string - ) { - const filePath = this.pluginPath(keyName); - // 确保目录存在 - const dir = path.dirname(filePath); - if (!fs.existsSync(dir)) { - fs.mkdirSync(dir, { recursive: true }); - } - // 写入文件,如果存在则覆盖 - fs.writeFileSync(filePath, JSON.stringify(data, null, 0), { flag: 'w' }); - } - - /** - * 获得插件数据 - * @param keyName - * @returns - */ - async getData(keyName: string): Promise<{ - content: { - type: 'comm' | 'module'; - data: string; - }; - tsContent: { - type: 'ts'; - data: string; - }; - }> { - const filePath = this.pluginPath(keyName); - if (!fs.existsSync(filePath)) { - this.logger.warn( - `插件[${keyName}]文件不存在,请卸载后重新安装: ${filePath}` - ); - return null; - } - return JSON.parse(await fs.promises.readFile(filePath, 'utf-8')); - } - - /** - * 删除插件 - * @param keyName - */ - async deleteData(keyName: string) { - const filePath = this.pluginPath(keyName); - if (fs.existsSync(filePath)) { - fs.unlinkSync(filePath); - } - } - - /** - * 获得插件路径 - * @param keyName - * @returns - */ - pluginPath(keyName: string) { - return path.join( - this.app.getBaseDir(), - '..', - 'cool', - 'plugin', - `${keyName}.cool` - ); - } -} diff --git a/src/modules/plugin/service/types.ts b/src/modules/plugin/service/types.ts deleted file mode 100644 index 59db655..0000000 --- a/src/modules/plugin/service/types.ts +++ /dev/null @@ -1,257 +0,0 @@ -import { BaseService } from '@cool-midway/core'; -import { IMidwayApplication, Inject } from '@midwayjs/core'; -import { App, Provide } from '@midwayjs/decorator'; -import { InjectEntityModel } from '@midwayjs/typeorm'; -import * as fs from 'fs'; -import * as path from 'path'; -import * as prettier from 'prettier'; -import { Repository } from 'typeorm'; -import * as ts from 'typescript'; -import { Utils } from '../../../comm/utils'; -import { PluginInfoEntity } from '../entity/info'; -import { PluginService } from './info'; - -/** - * 插件类型服务 - */ -@Provide() -export class PluginTypesService extends BaseService { - @App() - app: IMidwayApplication; - - @InjectEntityModel(PluginInfoEntity) - pluginInfoEntity: Repository; - - @Inject() - pluginService: PluginService; - - @Inject() - utils: Utils; - - /** - * 生成d.ts文件 - * @param tsContent - * @returns - */ - async dtsContent(tsContent: string) { - let output = ''; - - const compilerHost: ts.CompilerHost = { - fileExists: ts.sys.fileExists, - getCanonicalFileName: ts.sys.useCaseSensitiveFileNames - ? s => s - : s => s.toLowerCase(), - getCurrentDirectory: ts.sys.getCurrentDirectory, - getDefaultLibFileName: options => ts.getDefaultLibFilePath(options), - getDirectories: ts.sys.getDirectories, - getNewLine: () => ts.sys.newLine, - getSourceFile: (fileName, languageVersion) => { - if (fileName === 'file.ts') { - return ts.createSourceFile( - fileName, - tsContent, - languageVersion, - true - ); - } - const filePath = ts.sys.resolvePath(fileName); - return ts.sys.readFile(filePath) - ? ts.createSourceFile( - filePath, - ts.sys.readFile(filePath)!, - languageVersion, - true - ) - : undefined; - }, - readFile: ts.sys.readFile, - useCaseSensitiveFileNames: () => ts.sys.useCaseSensitiveFileNames, - writeFile: (fileName, content) => { - if (fileName.includes('file.d.ts')) { - output = content || output; - } - }, - }; - - const options: ts.CompilerOptions = { - declaration: true, - emitDeclarationOnly: true, - outDir: './', - skipLibCheck: true, - skipDefaultLibCheck: true, - noEmitOnError: false, - target: ts.ScriptTarget.ES2018, - strict: false, - module: ts.ModuleKind.Node16, - moduleResolution: ts.ModuleResolutionKind.Node16, - types: ['node'], - }; - - const program = ts.createProgram(['file.ts'], options, compilerHost); - program.emit(); - - if (!output) { - // Provide a default value if the output is still empty - output = '/* No declaration content generated */'; - } - return output; - } - - /** - * 生成d.ts文件 - * @param key - * @param tsContent - * @returns - */ - async generateDtsFile(key: string, tsContent: string) { - const env = this.app.getEnv(); - // 不是本地开发环境不生成d.ts文件 - if (env != 'local' || !tsContent) { - return; - } - // 基础路径 - const basePath = path.join(this.app.getBaseDir(), '..', 'typings'); - // pluginDts文件路径 - const pluginDtsPath = path.join(basePath, 'plugin.d.ts'); - // plugin文件夹路径 - const pluginPath = path.join(basePath, `${key}.d.ts`); - // 生成d.ts文件 - const dtsContent = await this.dtsContent(tsContent); - - // 读取plugin.d.ts文件内容 - let pluginDtsContent = fs.readFileSync(pluginDtsPath, 'utf-8'); - - // 根据key判断是否在PluginMap中存在 - const keyWithHyphen = key.includes('-'); - const importStatement = keyWithHyphen - ? `import * as ${key.replace(/-/g, '_')} from './${key}';` - : `import * as ${key} from './${key}';`; - const pluginMapEntry = keyWithHyphen - ? `'${key}': ${key.replace(/-/g, '_')}.CoolPlugin;` - : `${key}: ${key}.CoolPlugin;`; - - // 检查import语句是否已经存在,若不存在则添加 - if (!pluginDtsContent.includes(importStatement)) { - pluginDtsContent = `${importStatement}\n${pluginDtsContent}`; - } - - // 检查PluginMap中的键是否存在,若不存在则添加 - if (pluginDtsContent.includes(pluginMapEntry)) { - // 键存在则覆盖 - const regex = new RegExp( - `(\\s*${keyWithHyphen ? `'${key}'` : key}:\\s*[^;]+;)` - ); - pluginDtsContent = pluginDtsContent.replace(regex, pluginMapEntry); - } else { - // 键不存在则追加 - const pluginMapRegex = /interface\s+PluginMap\s*{([^}]*)}/; - pluginDtsContent = pluginDtsContent.replace( - pluginMapRegex, - (match, p1) => { - return match.replace(p1, `${p1.trim()}\n ${pluginMapEntry}`); - } - ); - } - - // 格式化内容 - pluginDtsContent = await this.formatContent(pluginDtsContent); - - // 延迟2秒写入文件 - setTimeout(async () => { - // 写入d.ts文件,如果存在则覆盖 - fs.writeFile(pluginPath, await this.formatContent(dtsContent), () => {}); - - // 写入plugin.d.ts文件 - fs.writeFile(pluginDtsPath, pluginDtsContent, () => {}); - }, 2000); - } - - /** - * 删除d.ts文件中的指定key - * @param key - */ - async deleteDtsFile(key: string) { - const env = this.app.getEnv(); - // 不是本地开发环境不删除d.ts文件 - if (env != 'local') { - return; - } - // 基础路径 - const basePath = path.join(this.app.getBaseDir(), '..', 'typings'); - // pluginDts文件路径 - const pluginDtsPath = path.join(basePath, 'plugin.d.ts'); - // plugin文件夹路径 - const pluginPath = path.join(basePath, `${key}.d.ts`); - - // 读取plugin.d.ts文件内容 - let pluginDtsContent = fs.readFileSync(pluginDtsPath, 'utf-8'); - - // 根据key判断是否在PluginMap中存在 - const keyWithHyphen = key.includes('-'); - const importStatement = keyWithHyphen - ? `import \\* as ${key.replace(/-/g, '_')} from '\\./${key}';` - : `import \\* as ${key} from '\\./${key}';`; - const pluginMapEntry = keyWithHyphen - ? `'${key}': ${key.replace(/-/g, '_')}.CoolPlugin;` - : `${key}: ${key}.CoolPlugin;`; - - // 删除import语句 - const importRegex = new RegExp(`${importStatement}\\n`, 'g'); - pluginDtsContent = pluginDtsContent.replace(importRegex, ''); - - // 删除PluginMap中的键 - const pluginMapRegex = new RegExp(`\\s*${pluginMapEntry}`, 'g'); - pluginDtsContent = pluginDtsContent.replace(pluginMapRegex, ''); - - // 格式化内容 - pluginDtsContent = await this.formatContent(pluginDtsContent); - - // 延迟2秒写入文件 - setTimeout(async () => { - // 删除插件d.ts文件 - if (fs.existsSync(pluginPath)) { - fs.unlink(pluginPath, () => {}); - } - // 写入plugin.d.ts文件 - fs.writeFile(pluginDtsPath, pluginDtsContent, () => {}); - }, 2000); - } - - /** - * 格式化内容 - * @param content - */ - async formatContent(content: string) { - // 使用prettier格式化内容 - return prettier.format(content, { - parser: 'typescript', - singleQuote: true, - trailingComma: 'all', - bracketSpacing: true, - arrowParens: 'avoid', - printWidth: 80, - }); - } - - /** - * 重新生成d.ts文件 - */ - async reGenerate() { - const pluginInfos = await this.pluginInfoEntity - .createQueryBuilder('a') - .where('a.status = :status', { status: 1 }) - .select(['a.id', 'a.status', 'a.tsContent', 'a.keyName']) - .getMany(); - for (const pluginInfo of pluginInfos) { - const data = await this.pluginService.getData(pluginInfo.keyName); - if (!data) { - continue; - } - const tsContent = data.tsContent?.data; - if (tsContent) { - await this.generateDtsFile(pluginInfo.keyName, tsContent); - await this.utils.sleep(200); - } - } - } -} diff --git a/src/modules/recycle/config.ts b/src/modules/recycle/config.ts deleted file mode 100644 index 3421900..0000000 --- a/src/modules/recycle/config.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { ModuleConfig } from '@cool-midway/core'; - -/** - * 模块配置 - */ -export default () => { - return { - // 模块名称 - name: '数据回收', - // 模块描述 - description: '收集被删除的数据,管理和恢复', - // 中间件,只对本模块有效 - middlewares: [], - // 中间件,全局有效 - globalMiddlewares: [], - // 模块加载顺序,默认为0,值越大越优先加载 - order: 0, - } as ModuleConfig; -}; diff --git a/src/modules/recycle/controller/admin/data.ts b/src/modules/recycle/controller/admin/data.ts deleted file mode 100644 index 926cd5e..0000000 --- a/src/modules/recycle/controller/admin/data.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { BaseSysUserEntity } from './../../../base/entity/sys/user'; -import { RecycleDataEntity } from './../../entity/data'; -import { Body, Inject, Post, Provide } from '@midwayjs/decorator'; -import { CoolController, BaseController } from '@cool-midway/core'; -import { RecycleDataService } from '../../service/data'; - -/** - * 数据回收 - */ -@Provide() -@CoolController({ - api: ['info', 'page'], - entity: RecycleDataEntity, - pageQueryOp: { - keyWordLikeFields: ['b.name', 'a.url'], - select: ['a.*', 'b.name as userName'], - join: [ - { - entity: BaseSysUserEntity, - alias: 'b', - condition: 'a.userId = b.id', - }, - ], - }, -}) -export class AdminRecycleDataController extends BaseController { - @Inject() - recycleDataService: RecycleDataService; - - @Post('/restore', { summary: '恢复数据' }) - async restore(@Body('ids') ids: number[]) { - await this.recycleDataService.restore(ids); - return this.ok(); - } -} diff --git a/src/modules/recycle/entity/data.ts b/src/modules/recycle/entity/data.ts deleted file mode 100644 index e150f43..0000000 --- a/src/modules/recycle/entity/data.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { BaseEntity } from '@cool-midway/core'; -import { Entity, Column, Index } from 'typeorm'; - -/** - * 数据回收站 软删除的时候数据会回收到该表 - */ -@Entity('recycle_data') -export class RecycleDataEntity extends BaseEntity { - @Column({ comment: '表', type: 'json' }) - entityInfo: { - // 数据源名称 - dataSourceName: string; - // entity - entity: string; - }; - - @Index() - @Column({ comment: '操作人', nullable: true }) - userId: number; - - @Column({ comment: '被删除的数据', type: 'json' }) - data: object[]; - - @Column({ comment: '请求的接口', nullable: true }) - url: string; - - @Column({ comment: '请求参数', nullable: true, type: 'json' }) - params: string; - - @Column({ comment: '删除数据条数', default: 1 }) - count: number; -} diff --git a/src/modules/recycle/event/data.ts b/src/modules/recycle/event/data.ts deleted file mode 100644 index 5c96bab..0000000 --- a/src/modules/recycle/event/data.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { CoolEvent, EVENT, Event } from '@cool-midway/core'; -import { Inject } from '@midwayjs/core'; -import { RecycleDataService } from '../service/data'; - -/** - * 接受数据事件 - */ -@CoolEvent() -export class RecycleDataEvent { - @Inject() - recycleDataService: RecycleDataService; - - /** - * 数据被删除 - * @param params - */ - @Event(EVENT.SOFT_DELETE) - async softDelete(params) { - await this.recycleDataService.record(params); - } -} diff --git a/src/modules/recycle/schedule/data.ts b/src/modules/recycle/schedule/data.ts deleted file mode 100644 index 5ac87b9..0000000 --- a/src/modules/recycle/schedule/data.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { - Provide, - Inject, - CommonSchedule, - TaskLocal, - FORMAT, -} from '@midwayjs/decorator'; -import { ILogger } from '@midwayjs/logger'; -import { RecycleDataService } from '../service/data'; - -/** - * 数据定时清除定时任务 - */ -@Provide() -export class BaseRecycleSchedule implements CommonSchedule { - @Inject() - recycleDataService: RecycleDataService; - - @Inject() - logger: ILogger; - - // 定时执行的具体任务 - @TaskLocal(FORMAT.CRONTAB.EVERY_DAY) - async exec() { - this.logger.info('清除回收站数据定时任务开始执行'); - const startTime = Date.now(); - await this.recycleDataService.clear(); - this.logger.info( - `清除回收站数据定时任务结束,耗时:${Date.now() - startTime}ms` - ); - } -} diff --git a/src/modules/recycle/service/data.ts b/src/modules/recycle/service/data.ts deleted file mode 100644 index 7684736..0000000 --- a/src/modules/recycle/service/data.ts +++ /dev/null @@ -1,84 +0,0 @@ -import { RecycleDataEntity } from './../entity/data'; -import { Inject, Provide, Scope, ScopeEnum } from '@midwayjs/decorator'; -import { BaseService } from '@cool-midway/core'; -import { InjectEntityModel, TypeORMDataSourceManager } from '@midwayjs/typeorm'; -import { LessThan, Repository } from 'typeorm'; -import * as _ from 'lodash'; -import * as moment from 'moment'; -import { BaseSysConfService } from '../../base/service/sys/conf'; - -/** - * 数据回收 - */ -@Provide() -@Scope(ScopeEnum.Request, { allowDowngrade: true }) -export class RecycleDataService extends BaseService { - @InjectEntityModel(RecycleDataEntity) - recycleDataEntity: Repository; - - @Inject() - typeORMDataSourceManager: TypeORMDataSourceManager; - - @Inject() - baseSysConfService: BaseSysConfService; - - /** - * 恢复数据 - * @param ids - */ - async restore(ids: number[]) { - for (const id of ids) { - const info = await this.recycleDataEntity.findOneBy({ id }); - if (!info) { - continue; - } - let entityModel = this.typeORMDataSourceManager - .getDataSource(info.entityInfo.dataSourceName) - .getRepository(info.entityInfo.entity); - await entityModel.save(info.data); - await this.recycleDataEntity.delete(id); - } - } - - /** - * 记录数据 - * @param params - */ - async record(params) { - const { ctx, data, entity } = params; - if (!ctx?.req) return; - const dataSourceName = - this.typeORMDataSourceManager.getDataSourceNameByModel(entity.target); - const url = ctx?.url; - await this.recycleDataEntity.save({ - entityInfo: { - dataSourceName, - entity: entity.target.name, - }, - url, - params: - ctx?.req.method === 'GET' ? ctx?.request.query : ctx?.request.body, - data, - count: data.length, - userId: _.startsWith(url, '/admin/') ? ctx?.admin.userId : ctx?.user?.id, - }); - } - - /** - * 日志 - * @param isAll 是否清除全部 - */ - async clear(isAll?) { - if (isAll) { - await this.recycleDataEntity.clear(); - return; - } - const keepDay = await this.baseSysConfService.getValue('recycleKeep'); - if (keepDay) { - const beforeDate = moment().add(-keepDay, 'days').startOf('day').toDate(); - await this.recycleDataEntity.delete({ createTime: LessThan(beforeDate) }); - } else { - await this.recycleDataEntity.clear(); - } - } -} diff --git a/src/modules/space/config.ts b/src/modules/space/config.ts deleted file mode 100644 index 10e7cff..0000000 --- a/src/modules/space/config.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { ModuleConfig } from '@cool-midway/core'; - -/** - * 模块配置 - */ -export default () => { - return { - // 模块名称 - name: '文件空间', - // 模块描述 - description: '上传和管理文件资源', - // 中间件,只对本模块有效 - middlewares: [], - // 中间件,全局有效 - globalMiddlewares: [], - // 模块加载顺序,默认为0,值越大越优先加载 - order: 0, - // wps的配置 - wps: { - // 这是个测试的appId,会有水印 - appId: 'SX20230111NDUAGQ', - }, - } as ModuleConfig; -}; diff --git a/src/modules/space/controller/admin/info.ts b/src/modules/space/controller/admin/info.ts deleted file mode 100644 index 11f3a07..0000000 --- a/src/modules/space/controller/admin/info.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { Provide } from '@midwayjs/decorator'; -import { CoolController, BaseController } from '@cool-midway/core'; -import { SpaceInfoEntity } from '../../entity/info'; -import { SpaceInfoService } from '../../service/info'; - -/** - * 图片空间信息 - */ -@Provide() -@CoolController({ - api: ['add', 'delete', 'update', 'info', 'list', 'page'], - entity: SpaceInfoEntity, - service: SpaceInfoService, - pageQueryOp: { - fieldEq: ['type', 'classifyId'], - }, -}) -export class BaseAppSpaceInfoController extends BaseController {} diff --git a/src/modules/space/controller/admin/type.ts b/src/modules/space/controller/admin/type.ts deleted file mode 100644 index 6429242..0000000 --- a/src/modules/space/controller/admin/type.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Provide } from '@midwayjs/decorator'; -import { CoolController, BaseController } from '@cool-midway/core'; -import { SpaceTypeEntity } from '../../entity/type'; -import { SpaceTypeService } from '../../service/type'; - -/** - * 空间分类 - */ -@Provide() -@CoolController({ - api: ['add', 'delete', 'update', 'info', 'list', 'page'], - entity: SpaceTypeEntity, - service: SpaceTypeService, -}) -export class BaseAppSpaceTypeController extends BaseController {} diff --git a/src/modules/space/controller/说明.md b/src/modules/space/controller/说明.md deleted file mode 100644 index 440a373..0000000 --- a/src/modules/space/controller/说明.md +++ /dev/null @@ -1 +0,0 @@ -编写接口 \ No newline at end of file diff --git a/src/modules/space/entity/info.ts b/src/modules/space/entity/info.ts deleted file mode 100644 index 3c2d4fc..0000000 --- a/src/modules/space/entity/info.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { BaseEntity } from '@cool-midway/core'; -import { Column, Index, Entity } from 'typeorm'; - -/** - * 文件空间信息 - */ -@Entity('space_info') -export class SpaceInfoEntity extends BaseEntity { - @Column({ comment: '地址' }) - url: string; - - @Column({ comment: '类型' }) - type: string; - - @Column({ comment: '分类ID', nullable: true }) - classifyId: number; - - @Index() - @Column({ comment: '文件id' }) - fileId: string; - - @Column({ comment: '文件名' }) - name: string; - - @Column({ comment: '文件大小' }) - size: number; - - @Column({ comment: '文档版本', default: 1 }) - version: number; - - @Column({ comment: '文件位置' }) - key: string; -} diff --git a/src/modules/space/entity/type.ts b/src/modules/space/entity/type.ts deleted file mode 100644 index 15c4308..0000000 --- a/src/modules/space/entity/type.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { BaseEntity } from '@cool-midway/core'; -import { Column, Entity } from 'typeorm'; - -/** - * 图片空间信息分类 - */ -@Entity('space_type') -export class SpaceTypeEntity extends BaseEntity { - @Column({ comment: '类别名称' }) - name: string; - - @Column({ comment: '父分类ID', nullable: true }) - parentId: number; -} diff --git a/src/modules/space/service/info.ts b/src/modules/space/service/info.ts deleted file mode 100644 index 417588a..0000000 --- a/src/modules/space/service/info.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { SpaceInfoEntity } from './../entity/info'; -import { Inject, Provide } from '@midwayjs/decorator'; -import { BaseService, MODETYPE } from '@cool-midway/core'; -import { InjectEntityModel } from '@midwayjs/typeorm'; -import { Repository } from 'typeorm'; -import { PluginService } from '../../plugin/service/info'; - -/** - * 文件信息 - */ -@Provide() -export class SpaceInfoService extends BaseService { - @InjectEntityModel(SpaceInfoEntity) - spaceInfoEntity: Repository; - - @Inject() - pluginService: PluginService; - - /** - * 新增 - */ - async add(param) { - const result = await this.pluginService.invoke('upload', 'getMode'); - const config = await this.pluginService.getConfig('upload'); - if (result.mode == MODETYPE.LOCAL) { - param.key = param.url.replace(config.domain, ''); - } - return super.add(param); - } -} diff --git a/src/modules/space/service/type.ts b/src/modules/space/service/type.ts deleted file mode 100644 index a9a6704..0000000 --- a/src/modules/space/service/type.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { Provide } from '@midwayjs/decorator'; -import { BaseService } from '@cool-midway/core'; -import { InjectEntityModel } from '@midwayjs/typeorm'; -import { In, Repository } from 'typeorm'; -import { SpaceTypeEntity } from '../entity/type'; -import { SpaceInfoEntity } from '../entity/info'; - -/** - * 文件分类 - */ -@Provide() -export class SpaceTypeService extends BaseService { - @InjectEntityModel(SpaceTypeEntity) - spaceTypeEntity: Repository; - - @InjectEntityModel(SpaceInfoEntity) - spaceInfoEntity: Repository; - - /** - * 删除 - * @param ids - */ - async delete(ids: any) { - await super.delete(ids); - // 删除该分类下的文件信息 - await this.spaceInfoEntity.delete({ classifyId: In(ids) }); - } -} diff --git a/src/modules/task/config.ts b/src/modules/task/config.ts deleted file mode 100644 index b919075..0000000 --- a/src/modules/task/config.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { ModuleConfig } from '@cool-midway/core'; -import { TaskMiddleware } from './middleware/task'; - -/** - * 模块配置 - */ -export default () => { - return { - // 模块名称 - name: '任务调度', - // 模块描述 - description: '任务调度模块,支持分布式任务,由redis整个集群的任务', - // 中间件 - middlewares: [TaskMiddleware], - // 模块加载顺序,默认为0,值越大越优先加载 - order: 0, - } as ModuleConfig; -}; diff --git a/src/modules/task/controller/admin/info.ts b/src/modules/task/controller/admin/info.ts deleted file mode 100644 index bca8ee9..0000000 --- a/src/modules/task/controller/admin/info.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { - ALL, - Body, - Get, - Inject, - Post, - Provide, - Query, -} from '@midwayjs/decorator'; -import { CoolController, BaseController } from '@cool-midway/core'; -import { TaskInfoEntity } from '../../entity/info'; -import { TaskInfoService } from '../../service/info'; - -/** - * 任务 - */ -@Provide() -@CoolController({ - api: ['add', 'delete', 'update', 'info', 'page'], - entity: TaskInfoEntity, - service: TaskInfoService, - before: ctx => { - ctx.request.body.limit = ctx.request.body.repeatCount; - }, - pageQueryOp: { - fieldEq: ['status', 'type'], - }, -}) -export class TaskInfoController extends BaseController { - @Inject() - taskInfoService: TaskInfoService; - - /** - * 手动执行一次 - */ - @Post('/once', { summary: '执行一次' }) - async once(@Body('id') id: number) { - await this.taskInfoService.once(id); - this.ok(); - } - - /** - * 暂停任务 - */ - @Post('/stop', { summary: '停止' }) - async stop(@Body('id') id: number) { - await this.taskInfoService.stop(id); - this.ok(); - } - - /** - * 开始任务 - */ - @Post('/start', { summary: '开始' }) - async start(@Body('id') id: number, @Body('type') type: number) { - await this.taskInfoService.start(id, type); - this.ok(); - } - - /** - * 日志 - */ - @Get('/log', { summary: '日志' }) - async log(@Query(ALL) params: any) { - return this.ok(await this.taskInfoService.log(params)); - } -} diff --git a/src/modules/task/controller/说明.md b/src/modules/task/controller/说明.md deleted file mode 100644 index 440a373..0000000 --- a/src/modules/task/controller/说明.md +++ /dev/null @@ -1 +0,0 @@ -编写接口 \ No newline at end of file diff --git a/src/modules/task/db.json b/src/modules/task/db.json deleted file mode 100644 index 2e318c7..0000000 --- a/src/modules/task/db.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "task_info": [ - { - "id": 1, - "jobId": null, - "repeatConf": "{\"count\":1,\"type\":1,\"limit\":5,\"name\":\"每秒执行,总共5次\",\"taskType\":1,\"every\":1000,\"service\":\"taskDemoService.test()\",\"status\":1,\"id\":1,\"createTime\":\"2021-03-10 14:25:13\",\"updateTime\":\"2021-03-10 14:25:13\",\"jobId\":1}", - "name": "每秒执行一次", - "cron": null, - "limit": null, - "every": 1000, - "remark": null, - "status": 0, - "startDate": null, - "endDate": null, - "data": null, - "service": "taskDemoService.test(1,2)", - "type": 1, - "nextRunTime": "2021-3-10 14:25:18", - "taskType": 1 - }, - { - "id": 2, - "jobId": null, - "repeatConf": "{\"count\":1,\"id\":2,\"createTime\":\"2021-03-10 14:25:53\",\"updateTime\":\"2021-03-10 14:25:55\",\"name\":\"cron任务,5秒执行一次\",\"cron\":\"0/5 * * * * ? \",\"status\":1,\"service\":\"taskDemoService.test()\",\"type\":1,\"nextRunTime\":\"2021-03-10 14:26:00\",\"taskType\":0,\"jobId\":2}", - "name": "cron任务,5秒执行一次", - "cron": "0/5 * * * * ? ", - "limit": null, - "every": null, - "remark": null, - "status": 0, - "startDate": null, - "endDate": null, - "data": null, - "service": "taskDemoService.test()", - "type": 1, - "nextRunTime": null, - "taskType": 0 - } - ] -} \ No newline at end of file diff --git a/src/modules/task/entity/info.ts b/src/modules/task/entity/info.ts deleted file mode 100644 index 0393e24..0000000 --- a/src/modules/task/entity/info.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { BaseEntity } from '@cool-midway/core'; -import { Column, Entity } from 'typeorm'; - -/** - * 任务信息 - */ -@Entity('task_info') -export class TaskInfoEntity extends BaseEntity { - @Column({ comment: '任务ID', nullable: true }) - jobId: string; - - @Column({ comment: '任务配置', nullable: true, length: 1000 }) - repeatConf: string; - - @Column({ comment: '名称' }) - name: string; - - @Column({ comment: 'cron', nullable: true }) - cron: string; - - @Column({ comment: '最大执行次数 不传为无限次', nullable: true }) - limit: number; - - @Column({ - comment: '每间隔多少毫秒执行一次 如果cron设置了 这项设置就无效', - nullable: true, - }) - every: number; - - @Column({ comment: '备注', nullable: true }) - remark: string; - - @Column({ comment: '状态 0-停止 1-运行', default: 1 }) - status: number; - - @Column({ comment: '开始时间', nullable: true }) - startDate: Date; - - @Column({ comment: '结束时间', nullable: true }) - endDate: Date; - - @Column({ comment: '数据', nullable: true }) - data: string; - - @Column({ comment: '执行的service实例ID', nullable: true }) - service: string; - - @Column({ comment: '状态 0-系统 1-用户', default: 0 }) - type: number; - - @Column({ comment: '下一次执行时间', nullable: true }) - nextRunTime: Date; - - @Column({ comment: '状态 0-cron 1-时间间隔', default: 0 }) - taskType: number; -} diff --git a/src/modules/task/entity/log.ts b/src/modules/task/entity/log.ts deleted file mode 100644 index 2f9030a..0000000 --- a/src/modules/task/entity/log.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { BaseEntity } from '@cool-midway/core'; -import { Column, Index, Entity } from 'typeorm'; - -/** - * 任务日志 - */ -@Entity('task_log') -export class TaskLogEntity extends BaseEntity { - @Index() - @Column({ comment: '任务ID', nullable: true }) - taskId: number; - - @Column({ comment: '状态 0-失败 1-成功', default: 0 }) - status: number; - - @Column({ comment: '详情描述', nullable: true, type: 'text' }) - detail: string; -} diff --git a/src/modules/task/event/app.ts b/src/modules/task/event/app.ts deleted file mode 100644 index 48e5c43..0000000 --- a/src/modules/task/event/app.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { Inject } from '@midwayjs/core'; -import { TaskInfoService } from './../service/info'; -import { CoolEvent, Event } from '@cool-midway/core'; - -/** - * 应用事件 - */ -@CoolEvent() -export class TaskAppEvent { - @Inject() - taskInfoService: TaskInfoService; - - @Event('onServerReady') - async onServerReady() { - this.taskInfoService.initTask(); - } -} diff --git a/src/modules/task/middleware/task.ts b/src/modules/task/middleware/task.ts deleted file mode 100644 index 8926852..0000000 --- a/src/modules/task/middleware/task.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { CoolCommException } from '@cool-midway/core'; -import { Inject, Middleware } from '@midwayjs/decorator'; -import { NextFunction, Context } from '@midwayjs/koa'; -import { IMiddleware } from '@midwayjs/core'; -import { TaskInfoQueue } from '../queue/task'; - -/** - * 任务中间件 - */ -@Middleware() -export class TaskMiddleware implements IMiddleware { - @Inject() - taskInfoQueue: TaskInfoQueue; - resolve() { - return async (ctx: Context, next: NextFunction) => { - const urls = ctx.url.split('/'); - if ( - ['add', 'update', 'once', 'stop', 'start'].includes( - urls[urls.length - 1] - ) - ) { - if (!this.taskInfoQueue.metaQueue) { - throw new CoolCommException( - 'task插件未启用或redis配置错误或redis版本过低(>=6.x)' - ); - } - } - await next(); - }; - } -} diff --git a/src/modules/task/queue/task.ts b/src/modules/task/queue/task.ts deleted file mode 100644 index 57a713e..0000000 --- a/src/modules/task/queue/task.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { App, Inject } from '@midwayjs/decorator'; -import { BaseCoolQueue, CoolQueue } from '@cool-midway/task'; -import { TaskInfoService } from '../service/info'; -import { IMidwayApplication } from '@midwayjs/core'; - -/** - * 任务 - */ -@CoolQueue() -export abstract class TaskInfoQueue extends BaseCoolQueue { - @App() - app: IMidwayApplication; - - @Inject() - taskInfoService: TaskInfoService; - - async data(job, done: any): Promise { - try { - const result = await this.taskInfoService.invokeService(job.data.service); - this.taskInfoService.record(job.data, 1, JSON.stringify(result)); - } catch (error) { - this.taskInfoService.record(job.data, 0, error.message); - } - if (!job.data.isOnce) { - this.taskInfoService.updateNextRunTime(job.data.id); - this.taskInfoService.updateStatus(job.data.id); - } - done(); - } -} diff --git a/src/modules/task/service/demo.ts b/src/modules/task/service/demo.ts deleted file mode 100644 index 05ef055..0000000 --- a/src/modules/task/service/demo.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { Logger, Provide } from '@midwayjs/decorator'; -import { BaseService } from '@cool-midway/core'; -import { ILogger } from '@midwayjs/logger'; - -/** - * 描述 - */ -@Provide() -export class TaskDemoService extends BaseService { - @Logger() - logger: ILogger; - /** - * 描述 - */ - async test(a, b) { - this.logger.info('我被调用了', a, b); - return '任务执行成功'; - } -} diff --git a/src/modules/task/service/info.ts b/src/modules/task/service/info.ts deleted file mode 100644 index 95504f4..0000000 --- a/src/modules/task/service/info.ts +++ /dev/null @@ -1,361 +0,0 @@ -import { - App, - Inject, - Logger, - Provide, - Scope, - ScopeEnum, -} from '@midwayjs/decorator'; -import { BaseService } from '@cool-midway/core'; -import { InjectEntityModel } from '@midwayjs/typeorm'; -import { Repository } from 'typeorm'; -import { TaskInfoEntity } from '../entity/info'; -import { TaskLogEntity } from '../entity/log'; -import { ILogger } from '@midwayjs/logger'; -import * as _ from 'lodash'; -import { Utils } from '../../../comm/utils'; -import { TaskInfoQueue } from '../queue/task'; -import { IMidwayApplication } from '@midwayjs/core'; - -/** - * 任务 - */ -@Provide() -@Scope(ScopeEnum.Request, { allowDowngrade: true }) -export class TaskInfoService extends BaseService { - @InjectEntityModel(TaskInfoEntity) - taskInfoEntity: Repository; - - @Logger() - logger: ILogger; - - @InjectEntityModel(TaskLogEntity) - taskLogEntity: Repository; - - @Inject() - taskInfoQueue: TaskInfoQueue; - - @App() - app: IMidwayApplication; - - @Inject() - utils: Utils; - - /** - * 停止任务 - * @param id - */ - async stop(id) { - const task = await this.taskInfoEntity.findOneBy({ id }); - if (task) { - const result = await this.taskInfoQueue.getRepeatableJobs(); - const job = _.find(result, { id: task.id + '' }); - if (job) { - await this.taskInfoQueue.removeRepeatableByKey(job.key); - } - task.status = 0; - await this.taskInfoEntity.update(task.id, task); - await this.updateNextRunTime(task.id); - } - } - - /** - * 移除任务 - * @param taskId - */ - async remove(taskId) { - const result = await this.taskInfoQueue.getRepeatableJobs(); - const job = _.find(result, { id: taskId + '' }); - await this.taskInfoQueue.removeRepeatableByKey(job.key); - } - - /** - * 开始任务 - * @param id - * @param type - */ - async start(id, type?) { - const task = await this.taskInfoEntity.findOneBy({ id }); - task.status = 1; - if (type || type == 0) { - task.type = type; - } - await this.addOrUpdate(task); - } - - /** - * 手动执行一次 - * @param id - */ - async once(id) { - const task = await this.taskInfoEntity.findOneBy({ id }); - if (task) { - await this.taskInfoQueue.add( - { - ...task, - isOnce: true, - }, - { - jobId: task.id.toString(), - removeOnComplete: true, - removeOnFail: true, - } - ); - } - } - - /** - * 检查任务是否存在 - * @param jobId - */ - async exist(jobId) { - const result = await this.taskInfoQueue.getRepeatableJobs(); - const ids = result.map(e => { - return e.id; - }); - return ids.includes(jobId.toString()); - } - - /** - * 新增或修改 - * @param params - */ - async addOrUpdate(params) { - delete params.repeatCount; - let repeatConf; - await this.getOrmManager().transaction(async transactionalEntityManager => { - if (params.taskType === 0) { - params.limit = null; - params.every = null; - } else { - params.cron = null; - } - await transactionalEntityManager.save(TaskInfoEntity, params); - - if (params.status === 1) { - const exist = await this.exist(params.id); - if (exist) { - await this.remove(params.id); - } - const { every, limit, startDate, endDate, cron } = params; - const repeat = { - every, - limit, - jobId: params.id, - startDate, - endDate, - cron, - }; - await this.utils.removeEmptyP(repeat); - const result = await this.taskInfoQueue.add(params, { - jobId: params.id, - removeOnComplete: true, - removeOnFail: true, - repeat, - }); - if (!result) { - throw new Error('任务添加失败,请检查任务配置'); - } - // await transactionalEntityManager.update(TaskInfoEntity, params.id, { - // jobId: params.id, - // type: params.type, - // }); - repeatConf = result.opts; - } - }); - if (params.status === 1) { - this.utils.sleep(1000); - await this.updateNextRunTime(params.id); - await this.nativeQuery( - 'update task_info a set a.repeatConf = ? where a.id = ?', - [JSON.stringify(repeatConf.repeat), params.id] - ); - } - } - - /** - * 删除 - * @param ids - */ - async delete(ids) { - let idArr; - if (ids instanceof Array) { - idArr = ids; - } else { - idArr = ids.split(','); - } - for (const id of idArr) { - const task = await this.taskInfoEntity.findOneBy({ id }); - const exist = await this.exist(task.id); - if (exist) { - this.stop(task.id); - } - await this.taskInfoEntity.delete({ id }); - await this.taskLogEntity.delete({ taskId: id }); - } - } - - /** - * 任务日志 - * @param query - */ - async log(query) { - const { id, status } = query; - return await this.sqlRenderPage( - ` - SELECT - a.*, - b.name AS taskName - FROM - task_log a - JOIN task_info b ON a.taskId = b.id - where 1=1 - ${this.setSql(id, 'and a.taskId = ?', [id])} - ${this.setSql(status, 'and a.status = ?', [status])} - `, - query - ); - } - - /** - * 保存任务记录,成功任务每个任务保留最新20条日志,失败日志不会删除 - * @param task - * @param status - * @param detail - */ - async record(task, status, detail?) { - await this.taskLogEntity.save({ - taskId: task.id, - status, - detail: detail || '', - }); - await this.nativeQuery( - `DELETE a - FROM - task_log a, - ( SELECT id FROM task_log where taskId = ? AND status = 1 ORDER BY id DESC LIMIT ?, 1 ) b - WHERE - a.taskId = ? AND - a.status = 1 AND - a.id < b.id`, - [task.id, 19, task.id] - ); // 日志保留最新的20条 - } - - /** - * 初始化任务 - */ - async initTask() { - try { - await this.utils.sleep(3000); - this.logger.info('init task....'); - const runningTasks = await this.taskInfoEntity.findBy({ status: 1 }); - if (!_.isEmpty(runningTasks)) { - for (const task of runningTasks) { - const job = await this.exist(task.id); // 任务已存在就不添加 - if (!job) { - this.logger.info(`init task ${task.name}`); - await this.addOrUpdate(task); - } - } - } - } catch (e) {} - } - - /** - * 任务ID - * @param jobId - */ - async getNextRunTime(jobId) { - let nextRunTime; - const result = await this.taskInfoQueue.getRepeatableJobs(); - const task = _.find(result, { id: jobId + '' }); - if (task) { - nextRunTime = new Date(task.next); - } - return nextRunTime; - } - - /** - * 更新下次执行时间 - * @param jobId - */ - async updateNextRunTime(jobId) { - await this.taskInfoEntity.update(jobId, { - nextRunTime: await this.getNextRunTime(jobId), - }); - } - - /** - * 详情 - * @param id - * @returns - */ - async info(id: any): Promise { - const info = await this.taskInfoEntity.findOneBy({ id }); - return { - ...info, - repeatCount: info.limit, - }; - } - - /** - * 刷新任务状态 - */ - async updateStatus(jobId) { - const result = await this.taskInfoQueue.getRepeatableJobs(); - const job = _.find(result, { id: jobId + '' }); - if (!job) { - return; - } - const task = await this.taskInfoEntity.findOneBy({ id: job.id }); - const nextTime = await this.getNextRunTime(task.id); - if (task) { - // if (task.nextRunTime.getTime() == nextTime.getTime()) { - // task.status = 0; - // task.nextRunTime = nextTime; - // this.taskInfoQueue.removeRepeatableByKey(job.key); - // } else { - task.nextRunTime = nextTime; - // } - await this.taskInfoEntity.update(task.id, task); - } - } - - /** - * 调用service - * @param serviceStr - */ - async invokeService(serviceStr) { - if (serviceStr) { - const arr = serviceStr.split('.'); - const service = await this.app - .getApplicationContext() - .getAsync(_.lowerFirst(arr[0])); - - for (let i = 1; i < arr.length; i++) { - const child = arr[i]; - if (child.includes('(')) { - const [methodName, paramsStr] = child.split('('); - const params = paramsStr - .replace(')', '') - .split(',') - .map(param => param.trim()); - - if (params.length === 1 && params[0] === '') { - return service[methodName](); - } else { - const parsedParams = params.map(param => { - try { - return JSON.parse(param); - } catch (e) { - return param; // 如果不是有效的JSON,则返回原始字符串 - } - }); - return service[methodName](...parsedParams); - } - } - } - } - } -} diff --git a/src/modules/user/config.ts b/src/modules/user/config.ts deleted file mode 100644 index f0e14f3..0000000 --- a/src/modules/user/config.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { ModuleConfig } from '@cool-midway/core'; -import { UserMiddleware } from './middleware/app'; - -/** - * 模块配置 - */ -export default () => { - return { - // 模块名称 - name: '用户模块', - // 模块描述 - description: 'APP、小程序、公众号等用户', - // 中间件,只对本模块有效 - middlewares: [], - // 中间件,全局有效 - globalMiddlewares: [UserMiddleware], - // 模块加载顺序,默认为0,值越大越优先加载 - order: 0, - // 短信 - sms: { - // 验证码有效期,单位秒 - timeout: 60 * 3, - }, - // jwt - jwt: { - // token 过期时间,单位秒 - expire: 60 * 60 * 24, - // 刷新token 过期时间,单位秒 - refreshExpire: 60 * 60 * 24 * 30, - // jwt 秘钥 - secret: 'cool-app-xxxxxx', - }, - } as ModuleConfig; -}; diff --git a/src/modules/user/controller/admin/address.ts b/src/modules/user/controller/admin/address.ts deleted file mode 100644 index fa18ade..0000000 --- a/src/modules/user/controller/admin/address.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { CoolController, BaseController } from '@cool-midway/core'; -import { UserAddressEntity } from '../../entity/address'; -import { UserAddressService } from '../../service/address'; - -/** - * 用户-地址 - */ -@CoolController({ - api: ['add', 'delete', 'update', 'info', 'list', 'page'], - entity: UserAddressEntity, - service: UserAddressService, -}) -export class AdminUserAddressesController extends BaseController {} diff --git a/src/modules/user/controller/admin/info.ts b/src/modules/user/controller/admin/info.ts deleted file mode 100644 index 12f1480..0000000 --- a/src/modules/user/controller/admin/info.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { CoolController, BaseController } from '@cool-midway/core'; -import { UserInfoEntity } from '../../entity/info'; - -/** - * 用户信息 - */ -@CoolController({ - api: ['add', 'delete', 'update', 'info', 'list', 'page'], - entity: UserInfoEntity, - pageQueryOp: { - fieldEq: ['status', 'gender', 'loginType'], - keyWordLikeFields: ['nickName', 'phone'], - }, -}) -export class AdminUserInfoController extends BaseController {} diff --git a/src/modules/user/controller/app/address.ts b/src/modules/user/controller/app/address.ts deleted file mode 100644 index a10a7fc..0000000 --- a/src/modules/user/controller/app/address.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { Get, Inject, Provide } from '@midwayjs/decorator'; -import { CoolController, BaseController } from '@cool-midway/core'; -import { UserAddressEntity } from '../../entity/address'; -import { UserAddressService } from '../../service/address'; - -/** - * 地址 - */ -@Provide() -@CoolController({ - api: ['add', 'delete', 'update', 'info', 'list', 'page'], - entity: UserAddressEntity, - service: UserAddressService, - insertParam: ctx => { - return { - userId: ctx.user.id, - }; - }, - pageQueryOp: { - where: async ctx => { - return [['userId =:userId', { userId: ctx.user.id }]]; - }, - addOrderBy: { - isDefault: 'DESC', - }, - }, -}) -export class AppUserAddressController extends BaseController { - @Inject() - userAddressService: UserAddressService; - - @Inject() - ctx; - - @Get('/default', { summary: '默认地址' }) - async default() { - return this.ok(await this.userAddressService.default(this.ctx.user.id)); - } -} diff --git a/src/modules/user/controller/app/comm.ts b/src/modules/user/controller/app/comm.ts deleted file mode 100644 index be06d6c..0000000 --- a/src/modules/user/controller/app/comm.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { - CoolController, - BaseController, - CoolUrlTag, - TagTypes, - CoolTag, -} from '@cool-midway/core'; -import { Body, Inject, Post } from '@midwayjs/core'; -import { UserWxService } from '../../service/wx'; - -/** - * 通用 - */ -@CoolUrlTag() -@CoolController() -export class UserCommController extends BaseController { - @Inject() - userWxService: UserWxService; - - @CoolTag(TagTypes.IGNORE_TOKEN) - @Post('/wxMpConfig', { summary: '获取微信公众号配置' }) - public async getWxMpConfig(@Body('url') url: string) { - return this.ok(await this.userWxService.getWxMpConfig(url)); - } -} diff --git a/src/modules/user/controller/app/info.ts b/src/modules/user/controller/app/info.ts deleted file mode 100644 index b1a94ab..0000000 --- a/src/modules/user/controller/app/info.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { CoolController, BaseController } from '@cool-midway/core'; -import { Body, Get, Inject, Post } from '@midwayjs/core'; -import { UserInfoService } from '../../service/info'; -import { UserInfoEntity } from '../../entity/info'; - -/** - * 用户信息 - */ -@CoolController({ - api: [], - entity: UserInfoEntity, -}) -export class AppUserInfoController extends BaseController { - @Inject() - ctx; - - @Inject() - userInfoService: UserInfoService; - - @Get('/person', { summary: '获取用户信息' }) - async person() { - return this.ok(await this.userInfoService.person(this.ctx.user.id)); - } - - @Post('/updatePerson', { summary: '更新用户信息' }) - async updatePerson(@Body() body) { - return this.ok( - await this.userInfoService.updatePerson(this.ctx.user.id, body) - ); - } - - @Post('/updatePassword', { summary: '更新用户密码' }) - async updatePassword( - @Body('password') password: string, - @Body('code') code: string - ) { - await this.userInfoService.updatePassword(this.ctx.user.id, password, code); - return this.ok(); - } - - @Post('/logoff', { summary: '注销' }) - async logoff() { - await this.userInfoService.logoff(this.ctx.user.id); - return this.ok(); - } - - @Post('/bindPhone', { summary: '绑定手机号' }) - async bindPhone(@Body('phone') phone: string, @Body('code') code: string) { - await this.userInfoService.bindPhone(this.ctx.user.id, phone, code); - return this.ok(); - } - - @Post('/miniPhone', { summary: '绑定小程序手机号' }) - async miniPhone(@Body() body) { - const { code, encryptedData, iv } = body; - return this.ok( - await this.userInfoService.miniPhone( - this.ctx.user.id, - code, - encryptedData, - iv - ) - ); - } -} diff --git a/src/modules/user/controller/app/login.ts b/src/modules/user/controller/app/login.ts deleted file mode 100644 index a64ce97..0000000 --- a/src/modules/user/controller/app/login.ts +++ /dev/null @@ -1,107 +0,0 @@ -import { - CoolController, - BaseController, - CoolUrlTag, - TagTypes, - CoolTag, -} from '@cool-midway/core'; -import { Body, Get, Inject, Post, Query } from '@midwayjs/core'; -import { UserLoginService } from '../../service/login'; -import { BaseSysLoginService } from '../../../base/service/sys/login'; - -/** - * 登录 - */ -@CoolUrlTag() -@CoolController() -export class AppUserLoginController extends BaseController { - @Inject() - userLoginService: UserLoginService; - - @Inject() - baseSysLoginService: BaseSysLoginService; - - @CoolTag(TagTypes.IGNORE_TOKEN) - @Post('/mini', { summary: '小程序登录' }) - async mini(@Body() body) { - const { code, encryptedData, iv } = body; - return this.ok(await this.userLoginService.mini(code, encryptedData, iv)); - } - - @CoolTag(TagTypes.IGNORE_TOKEN) - @Post('/mp', { summary: '公众号登录' }) - async mp(@Body('code') code: string) { - return this.ok(await this.userLoginService.mp(code)); - } - - @CoolTag(TagTypes.IGNORE_TOKEN) - @Post('/wxApp', { summary: '微信APP授权登录' }) - async app(@Body('code') code: string) { - return this.ok(await this.userLoginService.wxApp(code)); - } - - @CoolTag(TagTypes.IGNORE_TOKEN) - @Post('/phone', { summary: '手机号登录' }) - async phone(@Body('phone') phone: string, @Body('smsCode') smsCode: string) { - return this.ok(await this.userLoginService.phoneVerifyCode(phone, smsCode)); - } - - @CoolTag(TagTypes.IGNORE_TOKEN) - @Post('/uniPhone', { summary: '一键手机号登录' }) - async uniPhone( - @Body('access_token') access_token: string, - @Body('openid') openid: string, - @Body('appId') appId: string - ) { - return this.ok( - await this.userLoginService.uniPhone(access_token, openid, appId) - ); - } - - @CoolTag(TagTypes.IGNORE_TOKEN) - @Post('/miniPhone', { summary: '绑定小程序手机号' }) - async miniPhone(@Body() body) { - const { code, encryptedData, iv } = body; - return this.ok( - await this.userLoginService.miniPhone(code, encryptedData, iv) - ); - } - - @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) - ); - } - - @CoolTag(TagTypes.IGNORE_TOKEN) - @Post('/smsCode', { summary: '验证码' }) - async smsCode( - @Body('phone') phone: string, - @Body('captchaId') captchaId: string, - @Body('code') code: string - ) { - return this.ok(await this.userLoginService.smsCode(phone, captchaId, code)); - } - - @CoolTag(TagTypes.IGNORE_TOKEN) - @Post('/refreshToken', { summary: '刷新token' }) - public async refreshToken(@Body('refreshToken') refreshToken) { - return this.ok(await this.userLoginService.refreshToken(refreshToken)); - } - - @CoolTag(TagTypes.IGNORE_TOKEN) - @Post('/password', { summary: '密码登录' }) - async password( - @Body('phone') phone: string, - @Body('password') password: string - ) { - return this.ok(await this.userLoginService.password(phone, password)); - } -} diff --git a/src/modules/user/entity/address.ts b/src/modules/user/entity/address.ts deleted file mode 100644 index 6b93391..0000000 --- a/src/modules/user/entity/address.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { BaseEntity } from '@cool-midway/core'; -import { Entity, Column, Index } from 'typeorm'; - -/** - * 用户模块-收货地址 - */ -@Entity('user_address') -export class UserAddressEntity extends BaseEntity { - @Index() - @Column({ comment: '用户ID' }) - userId: number; - - @Column({ comment: '联系人' }) - contact: string; - - @Index() - @Column({ comment: '手机号', length: 11 }) - phone: string; - - @Column({ comment: '省' }) - province: string; - - @Column({ comment: '市' }) - city: string; - - @Column({ comment: '区' }) - district: string; - - @Column({ comment: '地址' }) - address: string; - - @Column({ comment: '是否默认', default: false }) - isDefault: boolean; -} diff --git a/src/modules/user/entity/info.ts b/src/modules/user/entity/info.ts deleted file mode 100644 index d0bbac3..0000000 --- a/src/modules/user/entity/info.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { BaseEntity } from '@cool-midway/core'; -import { Column, Entity, Index } from 'typeorm'; - -/** - * 用户信息 - */ -@Entity('user_info') -export class UserInfoEntity extends BaseEntity { - @Index({ unique: true }) - @Column({ comment: '登录唯一ID', nullable: true }) - unionid: string; - - @Column({ comment: '头像', nullable: true }) - avatarUrl: string; - - @Column({ comment: '昵称', nullable: true }) - nickName: string; - - @Index({ unique: true }) - @Column({ comment: '手机号', nullable: true }) - phone: string; - - @Column({ comment: '性别 0-未知 1-男 2-女', default: 0 }) - gender: number; - - @Column({ comment: '状态 0-禁用 1-正常 2-已注销', default: 1 }) - status: number; - - @Column({ comment: '登录方式 0-小程序 1-公众号 2-H5', default: 0 }) - loginType: number; - - @Column({ comment: '密码', nullable: true }) - password: string; -} diff --git a/src/modules/user/entity/wx.ts b/src/modules/user/entity/wx.ts deleted file mode 100644 index ca0ae59..0000000 --- a/src/modules/user/entity/wx.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { BaseEntity } from '@cool-midway/core'; -import { Column, Entity, Index } from 'typeorm'; - -/** - * 微信用户 - */ -@Entity('user_wx') -export class UserWxEntity extends BaseEntity { - @Index() - @Column({ comment: '微信unionid', nullable: true }) - unionid: string; - - @Index() - @Column({ comment: '微信openid' }) - openid: string; - - @Column({ comment: '头像', nullable: true }) - avatarUrl: string; - - @Column({ comment: '昵称', nullable: true }) - nickName: string; - - @Column({ comment: '性别 0-未知 1-男 2-女', default: 0 }) - gender: number; - - @Column({ comment: '语言', nullable: true }) - language: string; - - @Column({ comment: '城市', nullable: true }) - city: string; - - @Column({ comment: '省份', nullable: true }) - province: string; - - @Column({ comment: '国家', nullable: true }) - country: string; - - @Column({ comment: '类型 0-小程序 1-公众号 2-H5 3-APP', default: 0 }) - type: number; -} diff --git a/src/modules/user/event/app.ts b/src/modules/user/event/app.ts deleted file mode 100644 index d7861f6..0000000 --- a/src/modules/user/event/app.ts +++ /dev/null @@ -1,56 +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 UserAppEvent { - @Logger() - coreLogger: ILogger; - - @Config('module') - config; - - @App() - app: IMidwayKoaApplication; - - @Event('onMenuInit') - async onMenuInit() { - if (this.app.getEnv() != 'local') return; - this.checkConfig(); - } - - /** - * 检查配置 - */ - async checkConfig() { - if (this.config.user.jwt.secret == 'cool-app-xxxxxx') { - this.coreLogger.warn( - '\x1B[36m 检测到模块[user] jwt.secret 配置是默认值,请不要关闭!即将自动修改... \x1B[0m' - ); - setTimeout(() => { - const filePath = path.join( - this.app.getBaseDir(), - '..', - 'src', - 'modules', - 'user', - 'config.ts' - ); - // 替换文件内容 - let fileData = fs.readFileSync(filePath, 'utf8'); - const secret = uuid().replace(/-/g, ''); - this.config.user.jwt.secret = secret; - fs.writeFileSync(filePath, fileData.replace('cool-app-xxxxxx', secret)); - this.coreLogger.info( - '\x1B[36m [cool:module:user] midwayjs cool module user auto modify jwt.secret\x1B[0m' - ); - }, 6000); - } - } -} diff --git a/src/modules/user/middleware/app.ts b/src/modules/user/middleware/app.ts deleted file mode 100644 index 7fbba3a..0000000 --- a/src/modules/user/middleware/app.ts +++ /dev/null @@ -1,96 +0,0 @@ -import { ALL, Config, Middleware } from '@midwayjs/decorator'; -import { NextFunction, Context } from '@midwayjs/koa'; -import { IMiddleware, Init, Inject } from '@midwayjs/core'; -import * as jwt from 'jsonwebtoken'; -import * as _ from 'lodash'; -import { CoolUrlTagData, RESCODE, TagTypes } from '@cool-midway/core'; - -/** - * 用户 - */ -@Middleware() -export class UserMiddleware implements IMiddleware { - @Config(ALL) - coolConfig; - - @Inject() - coolUrlTagData: CoolUrlTagData; - - @Config('module.user.jwt') - jwtConfig; - - ignoreUrls: string[] = []; - - @Config('koa.globalPrefix') - prefix; - - @Init() - async init() { - this.ignoreUrls = this.coolUrlTagData.byKey(TagTypes.IGNORE_TOKEN, 'app'); - } - - resolve() { - return async (ctx: Context, next: NextFunction) => { - let { url } = ctx; - url = url.replace(this.prefix, '').split('?')[0]; - if (_.startsWith(url, '/app/')) { - const token = ctx.get('Authorization'); - try { - ctx.user = jwt.verify(token, this.jwtConfig.secret); - if (ctx.user.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; - } else { - if (!ctx.user) { - ctx.status = 401; - 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; - } -} diff --git a/src/modules/user/service/address.ts b/src/modules/user/service/address.ts deleted file mode 100644 index 6a3a3a7..0000000 --- a/src/modules/user/service/address.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { Init, Inject, Provide } from '@midwayjs/decorator'; -import { BaseService } from '@cool-midway/core'; -import { Equal, Repository } from 'typeorm'; -import { UserAddressEntity } from '../entity/address'; -import { InjectEntityModel } from '@midwayjs/typeorm'; - -/** - * 地址 - */ -@Provide() -export class UserAddressService extends BaseService { - @InjectEntityModel(UserAddressEntity) - userAddressEntity: Repository; - - @Inject() - ctx; - - @Init() - async init() { - await super.init(); - this.setEntity(this.userAddressEntity); - } - - /** - * 列表信息 - */ - async list() { - return this.userAddressEntity - .createQueryBuilder() - .where('userId = :userId ', { userId: this.ctx.user.id }) - .addOrderBy('isDefault', 'DESC') - .getMany(); - } - - /** - * 修改之后 - * @param data - * @param type - */ - async modifyAfter(data: any, type: 'add' | 'update' | 'delete') { - if (type == 'add' || type == 'update') { - if (data.isDefault) { - await this.userAddressEntity - .createQueryBuilder() - .update() - .set({ isDefault: false }) - .where('userId = :userId ', { userId: this.ctx.user.id }) - .andWhere('id != :id', { id: data.id }) - .execute(); - } - } - } - - /** - * 默认地址 - */ - async default(userId) { - return await this.userAddressEntity.findOneBy({ - userId: Equal(userId), - isDefault: true, - }); - } -} diff --git a/src/modules/user/service/info.ts b/src/modules/user/service/info.ts deleted file mode 100644 index 8a340d4..0000000 --- a/src/modules/user/service/info.ts +++ /dev/null @@ -1,124 +0,0 @@ -import { BaseService, CoolCommException } from '@cool-midway/core'; -import { Inject, Provide } from '@midwayjs/decorator'; -import { InjectEntityModel } from '@midwayjs/typeorm'; -import * as md5 from 'md5'; -import { Equal, Repository } from 'typeorm'; -import { v1 as uuid } from 'uuid'; -import { PluginService } from '../../plugin/service/info'; -import { UserInfoEntity } from '../entity/info'; -import { UserSmsService } from './sms'; -import { UserWxService } from './wx'; - -/** - * 用户信息 - */ -@Provide() -export class UserInfoService extends BaseService { - @InjectEntityModel(UserInfoEntity) - userInfoEntity: Repository; - - @Inject() - pluginService: PluginService; - - @Inject() - userSmsService: UserSmsService; - - @Inject() - userWxService: UserWxService; - - /** - * 绑定小程序手机号 - * @param userId - * @param code - * @param encryptedData - * @param iv - */ - async miniPhone(userId: number, code: any, encryptedData: any, iv: any) { - const phone = await this.userWxService.miniPhone(code, encryptedData, iv); - await this.userInfoEntity.update({ id: Equal(userId) }, { phone }); - return phone; - } - - /** - * 获取用户信息 - * @param id - * @returns - */ - async person(id) { - const info = await this.userInfoEntity.findOneBy({ id: Equal(id) }); - delete info.password; - return info; - } - - /** - * 注销 - * @param userId - */ - async logoff(userId: number) { - await this.userInfoEntity.update( - { id: userId }, - { - status: 2, - phone: null, - unionid: null, - nickName: `已注销-00${userId}`, - avatarUrl: null, - } - ); - } - - /** - * 更新用户信息 - * @param id - * @param param - * @returns - */ - async updatePerson(id, param) { - const info = await this.person(id); - if (!info) throw new CoolCommException('用户不存在'); - try { - // 修改了头像要重新处理 - if (param.avatarUrl && info.avatarUrl != param.avatarUrl) { - const file = await this.pluginService.getInstance('upload'); - param.avatarUrl = await file.downAndUpload( - param.avatarUrl, - uuid() + '.png' - ); - } - } catch (err) {} - try { - return await this.userInfoEntity.update({ id }, param); - } catch (err) { - throw new CoolCommException('更新失败,参数错误或者手机号已存在'); - } - } - - /** - * 更新密码 - * @param userId - * @param password - * @param 验证码 - */ - async updatePassword(userId, password, code) { - const user = await this.userInfoEntity.findOneBy({ id: userId }); - const check = await this.userSmsService.checkCode(user.phone, code); - if (!check) { - throw new CoolCommException('验证码错误'); - } - await this.userInfoEntity.update(user.id, { password: md5(password) }); - } - - /** - * 绑定手机号 - * @param userId - * @param phone - * @param code - */ - async bindPhone(userId, phone, code) { - const check = await this.userSmsService.checkCode(phone, code); - if (!check) { - throw new CoolCommException('验证码错误'); - } - await this.userInfoEntity.update({ id: userId }, { phone }); - } -} diff --git a/src/modules/user/service/login.ts b/src/modules/user/service/login.ts deleted file mode 100644 index 6d32603..0000000 --- a/src/modules/user/service/login.ts +++ /dev/null @@ -1,307 +0,0 @@ -import { Config, Inject, Provide } from '@midwayjs/decorator'; -import { BaseService, CoolCommException } from '@cool-midway/core'; -import { InjectEntityModel } from '@midwayjs/typeorm'; -import { Equal, Repository } from 'typeorm'; -import { UserInfoEntity } from '../entity/info'; -import { UserWxService } from './wx'; -import * as jwt from 'jsonwebtoken'; -import { UserWxEntity } from '../entity/wx'; -import { BaseSysLoginService } from '../../base/service/sys/login'; -import { UserSmsService } from './sms'; -import { v1 as uuid } from 'uuid'; -import * as md5 from 'md5'; -import { PluginService } from '../../plugin/service/info'; - -/** - * 登录 - */ -@Provide() -export class UserLoginService extends BaseService { - @InjectEntityModel(UserInfoEntity) - userInfoEntity: Repository; - - @InjectEntityModel(UserWxEntity) - userWxEntity: Repository; - - @Inject() - userWxService: UserWxService; - - @Config('module.user.jwt') - jwtConfig; - - @Inject() - baseSysLoginService: BaseSysLoginService; - - @Inject() - pluginService: PluginService; - - @Inject() - userSmsService: UserSmsService; - - /** - * 发送手机验证码 - * @param phone - * @param captchaId - * @param code - */ - async smsCode(phone, captchaId, code) { - // 1、检查图片验证码 2、发送短信验证码 - const check = await this.baseSysLoginService.captchaCheck(captchaId, code); - if (!check) { - throw new CoolCommException('图片验证码错误'); - } - await this.userSmsService.sendSms(phone); - } - - /** - * 手机验证码登录 - * @param phone - * @param smsCode - */ - async phoneVerifyCode(phone, smsCode) { - // 1、检查短信验证码 2、登录 - const check = await this.userSmsService.checkCode(phone, smsCode); - if (check) { - return await this.phone(phone); - } else { - throw new CoolCommException('验证码错误'); - } - } - - /** - * 小程序手机号登录 - * @param code - * @param encryptedData - * @param iv - */ - async miniPhone(code, encryptedData, iv) { - const phone = await this.userWxService.miniPhone(code, encryptedData, iv); - if (phone) { - return await this.phone(phone); - } else { - throw new CoolCommException('获得手机号失败,请检查配置'); - } - } - - /** - * 手机号一键登录 - * @param access_token - * @param openid - */ - async uniPhone(access_token, openid, appId) { - const instance: any = await this.pluginService.getInstance('uniphone'); - const phone = await instance.getPhone(access_token, openid, appId); - if (phone) { - return await this.phone(phone); - } else { - throw new CoolCommException('获得手机号失败,请检查配置'); - } - } - - /** - * 手机登录 - * @param phone - * @returns - */ - async phone(phone: string) { - let user: any = await this.userInfoEntity.findOneBy({ - phone: Equal(phone), - }); - if (!user) { - user = { - phone, - unionid: phone, - loginType: 2, - nickName: phone.replace(/^(\d{3})\d{4}(\d{4})$/, '$1****$2'), - }; - await this.userInfoEntity.insert(user); - } - return this.token({ id: user.id }); - } - - /** - * 公众号登录 - * @param code - */ - async mp(code: string) { - let wxUserInfo = await this.userWxService.mpUserInfo(code); - if (wxUserInfo) { - delete wxUserInfo.privilege; - wxUserInfo = await this.saveWxInfo( - { - openid: wxUserInfo.openid, - unionid: wxUserInfo.unionid, - avatarUrl: wxUserInfo.headimgurl, - nickName: wxUserInfo.nickname, - gender: wxUserInfo.sex, - city: wxUserInfo.city, - province: wxUserInfo.province, - country: wxUserInfo.country, - }, - 1 - ); - return this.wxLoginToken(wxUserInfo); - } else { - throw new Error('微信登录失败'); - } - } - - /** - * 微信APP授权登录 - * @param code - */ - async wxApp(code: string) { - let wxUserInfo = await this.userWxService.appUserInfo(code); - if (wxUserInfo) { - delete wxUserInfo.privilege; - wxUserInfo = await this.saveWxInfo( - { - openid: wxUserInfo.openid, - unionid: wxUserInfo.unionid, - avatarUrl: wxUserInfo.headimgurl, - nickName: wxUserInfo.nickname, - gender: wxUserInfo.sex, - city: wxUserInfo.city, - province: wxUserInfo.province, - country: wxUserInfo.country, - }, - 1 - ); - return this.wxLoginToken(wxUserInfo); - } else { - throw new Error('微信登录失败'); - } - } - - /** - * 保存微信信息 - * @param wxUserInfo - * @param type - * @returns - */ - async saveWxInfo(wxUserInfo, type) { - const find: any = { openid: wxUserInfo.openid }; - let wxInfo: any = await this.userWxEntity.findOneBy(find); - if (wxInfo) { - wxUserInfo.id = wxInfo.id; - } - await this.userWxEntity.save({ - ...wxUserInfo, - type, - }); - return wxUserInfo; - } - - /** - * 小程序登录 - * @param code - * @param encryptedData - * @param iv - */ - async mini(code, encryptedData, iv) { - let wxUserInfo = await this.userWxService.miniUserInfo( - code, - encryptedData, - iv - ); - if (wxUserInfo) { - // 保存 - wxUserInfo = await this.saveWxInfo(wxUserInfo, 0); - return await this.wxLoginToken(wxUserInfo); - } - } - - /** - * 微信登录 获得token - * @param wxUserInfo 微信用户信息 - * @returns - */ - async wxLoginToken(wxUserInfo) { - const unionid = wxUserInfo.unionid ? wxUserInfo.unionid : wxUserInfo.openid; - let userInfo: any = await this.userInfoEntity.findOneBy({ unionid }); - if (!userInfo) { - const file = await this.pluginService.getInstance('upload'); - const avatarUrl = await file.downAndUpload( - wxUserInfo.avatarUrl, - uuid() + '.png' - ); - userInfo = { - unionid, - nickName: wxUserInfo.nickName, - avatarUrl, - gender: wxUserInfo.gender, - }; - await this.userInfoEntity.insert(userInfo); - } - return this.token({ id: userInfo.id }); - } - - /** - * 刷新token - * @param refreshToken - */ - async refreshToken(refreshToken) { - try { - const info = jwt.verify(refreshToken, this.jwtConfig.secret); - if (!info['isRefresh']) { - throw new CoolCommException('token类型非refreshToken'); - } - const userInfo = await this.userInfoEntity.findOneBy({ - id: info['id'], - }); - return this.token({ id: userInfo.id }); - } catch (e) { - throw new CoolCommException( - '刷新token失败,请检查refreshToken是否正确或过期' - ); - } - } - - /** - * 密码登录 - * @param phone - * @param password - */ - async password(phone, password) { - const user = await this.userInfoEntity.findOneBy({ phone }); - - if (user && user.password == md5(password)) { - return this.token({ - id: user.id, - }); - } else { - throw new CoolCommException('账号或密码错误'); - } - } - - /** - * 获得token - * @param info - * @returns - */ - async token(info) { - const { expire, refreshExpire } = this.jwtConfig; - return { - expire, - token: await this.generateToken(info), - refreshExpire, - refreshToken: await this.generateToken(info, true), - }; - } - - /** - * 生成token - * @param tokenInfo 信息 - * @param roleIds 角色集合 - */ - async generateToken(info, isRefresh = false) { - const { expire, refreshExpire, secret } = this.jwtConfig; - const tokenInfo = { - isRefresh, - ...info, - }; - return jwt.sign(tokenInfo, secret, { - expiresIn: isRefresh ? refreshExpire : expire, - }); - } -} diff --git a/src/modules/user/service/sms.ts b/src/modules/user/service/sms.ts deleted file mode 100644 index 561d4ec..0000000 --- a/src/modules/user/service/sms.ts +++ /dev/null @@ -1,85 +0,0 @@ -import { - Provide, - Config, - Inject, - Init, - InjectClient, -} from '@midwayjs/decorator'; -import { BaseService, CoolCommException } from '@cool-midway/core'; -import * as _ from 'lodash'; -import { CachingFactory, MidwayCache } from '@midwayjs/cache-manager'; -import { PluginService } from '../../plugin/service/info'; - -/** - * 描述 - */ -@Provide() -export class UserSmsService extends BaseService { - // 获得模块的配置信息 - @Config('module.user.sms') - config; - - @InjectClient(CachingFactory, 'default') - midwayCache: MidwayCache; - - @Inject() - pluginService: PluginService; - - plugin; - - @Init() - async init() { - for (const key of ['sms-tx', 'sms-ali']) { - try { - this.plugin = await this.pluginService.getInstance(key); - if (this.plugin) { - this.config.pluginKey = key; - break; - } - } catch (e) { - continue; - } - } - } - - /** - * 发送验证码 - * @param phone - */ - async sendSms(phone) { - // 随机四位验证码 - const code = _.random(1000, 9999); - const pluginKey = this.config.pluginKey; - if (!this.plugin) - throw new CoolCommException( - '未配置短信插件,请到插件市场下载安装配置:https://cool-js.com/plugin?keyWord=短信' - ); - try { - if (pluginKey == 'sms-tx') { - await this.plugin.send([phone], [code]); - } - if (pluginKey == 'sms-ali') { - await this.plugin.send([phone], { - code, - }); - } - this.midwayCache.set(`sms:${phone}`, code, this.config.timeout * 1000); - } catch (error) { - throw new CoolCommException('发送过于频繁,请稍后再试'); - } - } - - /** - * 验证验证码 - * @param phone - * @param code - * @returns - */ - async checkCode(phone, code) { - const cacheCode = await this.midwayCache.get(`sms:${phone}`); - if (code && cacheCode == code) { - return true; - } - return false; - } -} diff --git a/src/modules/user/service/wx.ts b/src/modules/user/service/wx.ts deleted file mode 100644 index 7e126db..0000000 --- a/src/modules/user/service/wx.ts +++ /dev/null @@ -1,281 +0,0 @@ -import { BaseService, CoolCommException } from '@cool-midway/core'; -import { Config, Inject, Provide } from '@midwayjs/decorator'; -import { InjectEntityModel } from '@midwayjs/typeorm'; -import axios from 'axios'; -import * as crypto from 'crypto'; -import * as moment from 'moment'; -import { Equal, Repository } from 'typeorm'; -import { v1 as uuid } from 'uuid'; -import { PluginService } from '../../plugin/service/info'; -import { UserInfoEntity } from '../entity/info'; -import { UserWxEntity } from '../entity/wx'; - -/** - * 微信 - */ -@Provide() -export class UserWxService extends BaseService { - @Config('module.user') - config; - - @InjectEntityModel(UserInfoEntity) - userInfoEntity: Repository; - - @InjectEntityModel(UserWxEntity) - userWxEntity: Repository; - - @Inject() - pluginService: PluginService; - - /** - * 获得插件实例 - * @returns - */ - async getPlugin() { - try { - const wxPlugin: any = await this.pluginService.getInstance('wx'); - return wxPlugin; - } catch (error) { - throw new CoolCommException( - '未配置微信插件,请到插件市场下载安装配置:https://cool-js.com/plugin/70' - ); - } - } - - /** - * 获得小程序实例 - * @returns - */ - async getMiniApp() { - const wxPlugin: any = await this.getPlugin(); - return wxPlugin.MiniApp(); - } - - /** - * 获得公众号实例 - * @returns - */ - async getOfficialAccount() { - const wxPlugin: any = await this.getPlugin(); - return wxPlugin.OfficialAccount(); - } - - /** - * 获得App实例 - * @returns - */ - async getOpenPlatform() { - const wxPlugin: any = await this.getPlugin(); - return wxPlugin.OpenPlatform(); - } - - /** - * 获得用户的openId - * @param userId - * @param type 0-小程序 1-公众号 2-App - */ - async getOpenid(userId: number, type = 0) { - const user = await this.userInfoEntity.findOneBy({ - id: Equal(userId), - status: 1, - }); - if (!user) { - throw new CoolCommException('用户不存在或已被禁用'); - } - const wx = await this.userWxEntity - .createQueryBuilder('a') - .where('a.type = :type', { type }) - .andWhere('(a.unionid = :unionid or a.openid =:openid )', { - unionid: user.unionid, - openid: user.unionid, - }) - .getOne(); - return wx ? wx.openid : null; - } - - /** - * 获得微信配置 - * @param appId - * @param appSecret - * @param url 当前网页的URL,不包含#及其后面部分(必须是调用JS接口页面的完整URL) - */ - public async getWxMpConfig(url: string) { - const token = await this.getWxToken(); - const ticket = await axios.get( - 'https://api.weixin.qq.com/cgi-bin/ticket/getticket', - { - params: { - access_token: token, - type: 'jsapi', - }, - } - ); - - const account = (await this.getOfficialAccount()).getAccount(); - const appid = account.getAppId(); - // 返回结果集 - const result = { - timestamp: parseInt(moment().valueOf() / 1000 + ''), - nonceStr: uuid(), - appId: appid, //appid - signature: '', - }; - const signArr = []; - signArr.push('jsapi_ticket=' + ticket.data.ticket); - signArr.push('noncestr=' + result.nonceStr); - signArr.push('timestamp=' + result.timestamp); - signArr.push('url=' + decodeURI(url)); - // 敏感信息加密处理 - result.signature = crypto - .createHash('sha1') - .update(signArr.join('&')) - .digest('hex') - .toUpperCase(); - return result; - } - - /** - * 获得公众号用户信息 - * @param code - */ - async mpUserInfo(code) { - const token = await this.openOrMpToken(code, 'mp'); - return await this.openOrMpUserInfo(token); - } - - /** - * 获得app用户信息 - * @param code - */ - async appUserInfo(code) { - const token = await this.openOrMpToken(code, 'open'); - return await this.openOrMpUserInfo(token); - } - - /** - * 获得微信token 不用code - * @param appid - * @param secret - */ - public async getWxToken(type = 'mp') { - let app; - if (type == 'mp') { - app = await this.getOfficialAccount(); - } else { - app = await this.getOpenPlatform(); - } - return await app.getAccessToken().getToken(); - } - - /** - * 获得用户信息 - * @param token - */ - async openOrMpUserInfo(token) { - return await axios - .get('https://api.weixin.qq.com/sns/userinfo', { - params: { - access_token: token.access_token, - openid: token.openid, - lang: 'zh_CN', - }, - }) - .then(res => { - return res.data; - }); - } - - /** - * 获得token嗯 - * @param code - * @param type - */ - async openOrMpToken(code, type = 'mp') { - const account = - type == 'mp' - ? (await this.getOfficialAccount()).getAccount() - : (await this.getMiniApp()).getAccount(); - const result = await axios.get( - 'https://api.weixin.qq.com/sns/oauth2/access_token', - { - params: { - appid: account.getAppId(), - secret: account.getSecret(), - code, - grant_type: 'authorization_code', - }, - } - ); - return result.data; - } - - /** - * 获得小程序session - * @param code 微信code - * @param conf 配置 - */ - async miniSession(code) { - const app = await this.getMiniApp(); - const utils = app.getUtils(); - const result = await utils.codeToSession(code); - return result; - } - - /** - * 获得小程序用户信息 - * @param code - * @param encryptedData - * @param iv - */ - async miniUserInfo(code, encryptedData, iv) { - const session = await this.miniSession(code); - if (session.errcode) { - throw new CoolCommException('登录失败,请重试'); - } - const info: any = await this.miniDecryptData( - encryptedData, - iv, - session.session_key - ); - if (info) { - delete info['watermark']; - return { - ...info, - openid: session['openid'], - unionid: session['unionid'], - }; - } - return null; - } - - /** - * 获得小程序手机 - * @param code - * @param encryptedData - * @param iv - */ - async miniPhone(code, encryptedData, iv) { - const session = await this.miniSession(code); - if (session.errcode) { - throw new CoolCommException('获取手机号失败,请刷新重试'); - } - const result = await this.miniDecryptData( - encryptedData, - iv, - session.session_key - ); - return result.phoneNumber; - } - - /** - * 小程序信息解密 - * @param encryptedData - * @param iv - * @param sessionKey - */ - async miniDecryptData(encryptedData, iv, sessionKey) { - const app = await this.getMiniApp(); - const utils = app.getUtils(); - return await utils.decryptSession(sessionKey, iv, encryptedData); - } -} diff --git a/src/welcome.ts b/src/welcome.ts deleted file mode 100644 index 0d937e8..0000000 --- a/src/welcome.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { Controller, Get, Inject } from '@midwayjs/decorator'; -import { Context } from '@midwayjs/koa'; -import * as packageJson from '../package.json'; - -/** - * 欢迎界面 - */ -@Controller('/') -export class WelcomeController { - @Inject() - ctx: Context; - - @Get('/', { summary: '欢迎界面' }) - public async welcome() { - await this.ctx.render('welcome', { - text: `HELLO COOL-ADMIN v${packageJson.version} 全栈开发就用COOL!!!`, - }); - } -} diff --git a/test/README.md b/test/README.md deleted file mode 100644 index 7effc7e..0000000 --- a/test/README.md +++ /dev/null @@ -1,12 +0,0 @@ -# 测试方式 - -考虑到cool-admin采用了自动化路由技术,它与官方集成的jest测试工具并不兼容。为确保测试环境与实际的开发环境保持一致,我们并不推荐使用jest进行测试。 - -# 自动化测试API工具 - -我们为您推荐以下的自动化API测试工具: - -- [Apifox](https://apifox.com/) -- [ApiPost](https://www.apipost.cn/) - -同时这些工具也方便写API接口文档,更加灵活有用 \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json deleted file mode 100644 index 9e88494..0000000 --- a/tsconfig.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "compileOnSave": true, - "compilerOptions": { - "target": "es2018", - "module": "commonjs", - "moduleResolution": "node", - "experimentalDecorators": true, - "emitDecoratorMetadata": true, - "inlineSourceMap": true, - "noImplicitThis": true, - "noUnusedLocals": false, - "stripInternal": true, - "skipLibCheck": true, - "resolveJsonModule": true, - "pretty": true, - "declaration": false, - "noImplicitAny": false, - "typeRoots": [ - "typings", - "./node_modules/@types" - ], - "outDir": "dist", - "rootDir": "src" - }, - "exclude": [ - "dist", - "node_modules", - "test" - ] -} \ No newline at end of file diff --git a/typings/plugin.d.ts b/typings/plugin.d.ts deleted file mode 100644 index e2ae5a0..0000000 --- a/typings/plugin.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { BaseUpload, MODETYPE } from './upload'; -type AnyString = string & {}; -/** - * 插件类型声明 - */ -interface PluginMap { - upload: BaseUpload; -} diff --git a/typings/upload.d.ts b/typings/upload.d.ts deleted file mode 100644 index 4f0cdfc..0000000 --- a/typings/upload.d.ts +++ /dev/null @@ -1,56 +0,0 @@ -// 模式 -export enum MODETYPE { - // 本地 - LOCAL = 'local', - // 云存储 - CLOUD = 'cloud', - // 其他 - OTHER = 'other', -} - -/** - * 上传模式 - */ -export interface Mode { - // 模式 - mode: MODETYPE; - // 类型 - type: string; -} - -/** - * 文件上传 - */ -export interface BaseUpload { - /** - * 获得上传模式 - */ - getMode(): Promise; - - /** - * 获得原始操作对象 - * @returns - */ - getMetaFileObj(): Promise; - - /** - * 下载并上传 - * @param url - * @param fileName 文件名 - */ - downAndUpload(url: string, fileName?: string): Promise; - - /** - * 指定Key(路径)上传,本地文件上传到存储服务 - * @param filePath 文件路径 - * @param key 路径一致会覆盖源文件 - */ - uploadWithKey(filePath, key): Promise; - - /** - * 上传文件 - * @param ctx - * @param key 文件路径 - */ - upload(ctx): Promise; -} diff --git a/view/welcome.html b/view/welcome.html deleted file mode 100644 index 923ac48..0000000 --- a/view/welcome.html +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - COOL-AMIND 一个很酷的后台权限管理系统 - - - - - - -
<%= text %>
- - - - - - - -