lrf 1 anno fa
parent
commit
92455e776c

+ 7 - 0
src/config/config.default.ts

@@ -6,7 +6,14 @@ export default {
   koa: {
     port: 7001,
   },
+  // 请求记录在redis留存时间,超过时间.数据变化将不会记录.以秒为单位--5分钟
+  requestTimeLimit: 300,
   i18n: {
+    defaultLocale: 'zh-cn',
+    fallbacks: {
+      'en*': 'en_us',
+      'zh*': 'zh-cn',
+    },
     localeTable: {
       en_us: {
         default: require('../locales/en_us/defaults'),

+ 1 - 0
src/config/config.local.ts

@@ -28,6 +28,7 @@ export default {
       password: 'NAjqFz_7tS2DkdpU7p*x',
     },
   },
+  dbName: projectDB,
   mongoose: {
     dataSource: {
       default: {

+ 1 - 0
src/config/config.prod.ts

@@ -24,6 +24,7 @@ export default {
       password: 'NAjqFz_7tS2DkdpU7p*x',
     },
   },
+  dbName: projectDB,
   mongoose: {
     dataSource: {
       default: {

+ 4 - 2
src/configuration.ts

@@ -12,9 +12,10 @@ import * as redis from '@midwayjs/redis';
 import { CheckOnePointLoginMiddleware } from './middleware/checkOnePointLogin.middleware';
 import * as i18n from '@midwayjs/i18n';
 import { SetLocaleToCtxMiddleware } from './middleware/setLocaleToCtx.middleware';
-import { DataRecordInit } from './decorator/dataRecord';
 import * as bull from '@midwayjs/bull';
 import { ElasticsearchService } from './service/elasticsearch';
+import { DataRecordMiddleware } from './middleware/dataRecord.middleware';
+import { DBService } from './service/db.service';
 @Configuration({
   imports: [
     koa,
@@ -44,15 +45,16 @@ export class MainConfiguration {
   async onReady() {
     this.app.getMiddleware().insertFirst(SetLocaleToCtxMiddleware)
     this.app.getMiddleware().insertAfter(CheckOnePointLoginMiddleware, 'checkToken');
+    this.app.getMiddleware().insertAfter(DataRecordMiddleware, 'checkOnePonitLogin');
     // 注解
     VerifyTokenInit(this.decoratorService);
     CheckPermissionCodeInit(this.decoratorService);
-    DataRecordInit(this.decoratorService)
   }
   // 应用服务已启动后执行
   async onServerReady?(container: IMidwayContainer, app: IMidwayApplication) {
     // 初始化es
     const esService = await container.getAsync(ElasticsearchService);
     await esService.preparMapping();
+    await container.getAsync(DBService);
   }
 }

+ 68 - 0
src/controller/record/dataLogs.controller.ts

@@ -0,0 +1,68 @@
+import { Body, Controller, Del, Get, Inject, Param, Post, Query } from '@midwayjs/decorator';
+import { BaseController } from 'free-midway-component';
+import { DataLogsService } from '../../service/record/dataLogs.service';
+import { CDTO_dataLogs, CVO_dataLogs, FVO_dataLogs, QDTO_dataLogs, QVO_dataLogs, UDTO_dataLogs, UVAO_dataLogs } from '../../interface/record/dataLogs.interface';
+import { ApiResponse, ApiTags, ApiQuery } from '@midwayjs/swagger';
+import { Validate } from '@midwayjs/validate';
+@ApiTags(['mongodb oplog'])
+@Controller('/dataLogs')
+export class DataLogsController extends BaseController {
+  @Inject()
+  service: DataLogsService;
+
+  @Post('/')
+  @Validate()
+  @ApiResponse({ type: CVO_dataLogs })
+  async create(@Body() data: CDTO_dataLogs) {
+    const dbData = await this.service.create(data);
+    const result = new CVO_dataLogs(dbData);
+    return result;
+  }
+  @Get('/')
+  @ApiQuery({ name: 'query' })
+  @ApiResponse({ type: QVO_dataLogs })
+  async query(@Query() filter: QDTO_dataLogs, @Query('skip') skip: number, @Query('limit') limit: number) {
+    const list = await this.service.query(filter, { skip, limit });
+    const data = [];
+    for (const i of list) {
+      const newData = new QVO_dataLogs(i);
+      data.push(newData);
+    }
+    const total = await this.service.count(filter);
+    return { data, total };
+  }
+
+  @Get('/:id')
+  @ApiResponse({ type: FVO_dataLogs })
+  async fetch(@Param('id') id: string) {
+    const data = await this.service.fetch(id);
+    const result = new FVO_dataLogs(data);
+    return result;
+  }
+
+  @Post('/:id')
+  @Validate()
+  @ApiResponse({ type: UVAO_dataLogs })
+  async update(@Param('id') id: string, @Body() body: UDTO_dataLogs) {
+    const result = await this.service.updateOne(id, body);
+    return result;
+  }
+
+  @Del('/:id')
+  @Validate()
+  async delete(@Param('id') id: string) {
+    await this.service.delete(id);
+    return 'ok';
+  }
+  async createMany(...args: any[]) {
+    throw new Error('Method not implemented.');
+  }
+
+  async updateMany(...args: any[]) {
+    throw new Error('Method not implemented.');
+  }
+
+  async deleteMany(...args: any[]) {
+    throw new Error('Method not implemented.');
+  }
+}

+ 0 - 4
src/controller/system/role.controller.ts

@@ -7,7 +7,6 @@ import { Validate } from '@midwayjs/validate';
 import { MenusService } from '../../service/system/menus.service';
 import { verifyToken } from '../../decorator/verifyToken.decorator';
 import { checkPermissionCode } from '../../decorator/checkPermissionCode';
-import { dataRecord } from '../../decorator/dataRecord';
 @ApiTags(['角色表'])
 @Controller('/role')
 export class RoleController extends BaseController {
@@ -20,7 +19,6 @@ export class RoleController extends BaseController {
   @verifyToken()
   @Validate()
   @ApiResponse({ type: CVO_role })
-  @dataRecord()
   async create(@Body() data: CDTO_role) {
     const dbData = await this.service.create(data);
     const result = new CVO_role(dbData);
@@ -56,7 +54,6 @@ export class RoleController extends BaseController {
   @checkPermissionCode({ roleCode: 'system_role.update' })
   @Validate()
   @ApiResponse({ type: UVAO_role })
-  @dataRecord()
   async update(@Param('id') id: string, @Body() body: UDTO_role) {
     const result = await this.service.updateOne(id, body);
     return result;
@@ -65,7 +62,6 @@ export class RoleController extends BaseController {
   @Del('/:id')
   @verifyToken()
   @Validate()
-  @dataRecord()
   async delete(@Param('id') id: string) {
     await this.service.delete(id);
     return 'ok';

+ 4 - 2
src/decorator/checkPermissionCode.ts

@@ -2,6 +2,8 @@ import { JoinPoint, MidwayDecoratorService, REQUEST_OBJ_CTX_KEY, createCustomMet
 import { FrameworkErrorEnum, ServiceError } from 'free-midway-component';
 import { get } from 'lodash';
 import { RoleService } from '../service/system/role.service';
+import { I18nService } from '../service/i18n.service';
+import { FrameErrorEnum } from '../error/frame.error';
 export const CHECKPERMISSIONCODE_KEY = 'decorator:check_permission_code';
 export const checkPermissionCode = options => {
   return createCustomMethodDecorator(CHECKPERMISSIONCODE_KEY, options);
@@ -31,8 +33,8 @@ export const CheckPermissionCodeInit = (decoratorService: MidwayDecoratorService
             let roleMenus = await roleService.getUserMenus(true);
             roleMenus = resetRoleMenus(roleMenus);
             if (!roleMenus.includes(roleCode)) {
-              console.log(options);
-              throw new ServiceError('您没有当前功能的权限!', FrameworkErrorEnum.SERVICE_FAULT);
+              const i18n = await ctx.requestContext.getAsync(I18nService);
+              throw new ServiceError(i18n.translateError(FrameErrorEnum.NO_PERMISSION), FrameErrorEnum.NO_PERMISSION);
             }
             const result = await joinPoint.proceed(...joinPoint.args);
             return result;

+ 17 - 0
src/entityRecord/dataLogs.entity.ts

@@ -0,0 +1,17 @@
+import { modelOptions, prop } from '@typegoose/typegoose';
+import { BaseModel } from 'free-midway-component';
+@modelOptions({
+  schemaOptions: { collection: 'dataLogs' },
+})
+export class DataLogs extends BaseModel {
+  @prop({ required: false, index: true, zh: '表' }) //, esType: 'keyword'
+  coll: string;
+  @prop({ required: false, index: false, zh: '数据id' })
+  data_id: string;
+  @prop({ required: false, index: false, zh: '时间' })
+  time: string;
+  @prop({ required: false, index: false, zh: '数据库操作方法' })
+  method: string;
+  @prop({ required: false, index: false, zh: '数据' })
+  data: object;
+}

+ 13 - 0
src/error/frame.error.ts

@@ -0,0 +1,13 @@
+import { registerErrorCode } from '@midwayjs/core';
+
+export enum ErrorCode {
+  NO_PERMISSION = '401',
+  USER_NOT_FOUND = '401-1',
+  BAD_PASSWORD = '401-2',
+  NOT_LOGIN = '401-3',
+  ACCOUNT_HAS_EXPIRED = '401-4',
+  ACCOUNT_LOGGED_IN_ELESWHERE = '401-5',
+  USER_IS_DISABLED = '401-6',
+  ROLE_IS_DISABLED = '401-7',
+}
+export const FrameErrorEnum = registerErrorCode('FrameError', ErrorCode);

+ 83 - 0
src/interface/record/dataLogs.interface.ts

@@ -0,0 +1,83 @@
+import { Rule, RuleType } from '@midwayjs/validate';
+import { ApiProperty } from '@midwayjs/swagger';
+import { SearchBase } from 'free-midway-component';
+import get = require('lodash/get');
+const dealVO = (cla, data) => {
+  for (const key in cla) {
+    const val = get(data, key);
+    if (val || val === 0) cla[key] = val;
+  }
+};
+export class FVO_dataLogs {
+  constructor(data: object) {
+    dealVO(this, data);
+  }
+  @ApiProperty({ description: '数据id' })
+  _id: string = undefined;
+  @ApiProperty({ description: '表' })
+  'collection': string = undefined;
+  @ApiProperty({ description: '数据id' })
+  'id': string = undefined;
+  @ApiProperty({ description: '时间' })
+  'time': string = undefined;
+  @ApiProperty({ description: '数据库操作方法' })
+  'method': string = undefined;
+  @ApiProperty({ description: '数据' })
+  'data': object = undefined;
+}
+
+export class QDTO_dataLogs extends SearchBase {
+  constructor() {
+    const like_prop = [];
+    const props = ['collection'];
+    const mapping = [];
+    super({ like_prop, props, mapping });
+  }
+  @ApiProperty({ description: '表' })
+  'collection': string = undefined;
+}
+
+export class QVO_dataLogs extends FVO_dataLogs {
+  constructor(data: object) {
+    super(data);
+    dealVO(this, data);
+  }
+}
+
+export class CDTO_dataLogs {
+  @ApiProperty({ description: '表' })
+  @Rule(RuleType['string']().empty(''))
+  'collection': string = undefined;
+  @ApiProperty({ description: '数据id' })
+  @Rule(RuleType['string']().empty(''))
+  'id': string = undefined;
+  @ApiProperty({ description: '时间' })
+  @Rule(RuleType['string']().empty(''))
+  'time': string = undefined;
+  @ApiProperty({ description: '数据库操作方法' })
+  @Rule(RuleType['string']().empty(''))
+  'method': string = undefined;
+  @ApiProperty({ description: '数据' })
+  @Rule(RuleType['object']().empty(''))
+  'data': object = undefined;
+}
+
+export class CVO_dataLogs extends FVO_dataLogs {
+  constructor(data: object) {
+    super(data);
+    dealVO(this, data);
+  }
+}
+
+export class UDTO_dataLogs extends CDTO_dataLogs {
+  @ApiProperty({ description: '数据id' })
+  @Rule(RuleType['string']().empty(''))
+  _id: string = undefined;
+}
+
+export class UVAO_dataLogs extends FVO_dataLogs {
+  constructor(data: object) {
+    super(data);
+    dealVO(this, data);
+  }
+}

+ 18 - 4
src/locales/en_us/errors.ts

@@ -1,5 +1,4 @@
-export default {
-  locale: 'error language is: {locale}',
+const codes = {
   '-1': 'unknown error',
   '-2': 'need params',
   '-20': 'params error',
@@ -11,9 +10,24 @@ export default {
   '-50': 'bad args',
   '-10': 'data not found',
   '-100': 'service fault',
-  '-101': 'not login',
-  '-102': 'bad password',
   '-500': 'request falut',
   '-3000': 'ElasticSearch error',
   '-3001': 'ElasticSearch error, index not found',
+  '401': 'You do not have permission for the current function!',
+  '401-1': 'User not found',
+  '401-2': 'Password error',
+  '401-3': 'No login information detected, please log in again!',
+  '401-4': 'Account login has expired, please log in again!',
+  '401-5': 'This account has been logged in elsewhere, please log in again!',
+  '401-6': 'The user has been disabled',
+  '401-7': 'Users in the current role are unable to use',
+};
+const errCodes = {};
+const prefix = 'SERVICEERROR_';
+for (const key in codes) {
+  errCodes[`${prefix}${key}`] = codes[key];
+}
+export default {
+  test: 'error language is: {locale}',
+  ...errCodes,
 };

+ 19 - 4
src/locales/zh_cn/errors.ts

@@ -1,5 +1,4 @@
-export default {
-  locale: '错误测试: {locale}',
+const codes = {
   '-1': '未知错误',
   '-2': '缺少params',
   '-20': 'params错误',
@@ -11,9 +10,25 @@ export default {
   '-50': '参数错误',
   '-10': '未找到数据',
   '-100': '服务发生错误',
-  '-101': '未登录',
-  '-102': '密码错误',
   '-500': '请求错误',
   '-3000': 'ElasticSearch发生错误',
   '-3001': 'ElasticSearch发生错误,未找到索引',
+  '401': '您没有当前功能的权限!',
+  '401-1': '未找到用户',
+  '401-2': '密码错误',
+  '401-3': '未检测到登录信息,请重新登录!',
+  '401-4': '账号登录已失效,请重新登录!',
+  '401-5': '本账号已在其他地方登录,请重新登录!',
+  '401-6': '该用户已被禁用',
+  '401-7': '当前角色下的用户无法使用',
+};
+const errCodes = {};
+const prefix = 'SERVICEERROR_';
+for (const key in codes) {
+  errCodes[`${prefix}${key}`] = codes[key];
+}
+
+export default {
+  locale: '错误测试: {locale}',
+  ...errCodes,
 };

+ 49 - 0
src/middleware/dataRecord.middleware.ts

@@ -0,0 +1,49 @@
+import { App, Config, IMiddleware, Inject, MidwayWebRouterService } from '@midwayjs/core';
+import { Middleware } from '@midwayjs/decorator';
+import { NextFunction, Context, Application } from '@midwayjs/koa';
+import { RedisService } from '@midwayjs/redis';
+import { get } from 'lodash';
+import { DataRecordService } from '../service/record/dataRecord.service';
+import { Types } from 'mongoose';
+const ObjectId = Types.ObjectId;
+@Middleware()
+export class DataRecordMiddleware implements IMiddleware<Context, NextFunction> {
+  @App()
+  app: Application;
+  @Inject()
+  webRouterService: MidwayWebRouterService;
+  @Inject()
+  redisService: RedisService;
+  @Config('requestTimeLimit')
+  requestTimeLimit: number;
+  recordRequestList = ['post', 'delete'];
+  resolve() {
+    return async (ctx: Context, next: NextFunction) => {
+      const routeInfo = await this.webRouterService.getMatchedRouterInfo(ctx.path, ctx.method);
+      if (!routeInfo) {
+        await next();
+        return;
+      }
+      if (!this.recordRequestList.includes(routeInfo.requestMethod)) await next();
+      else {
+        // 只记录post和delete请求的数据变化
+        const controller = get(routeInfo, 'controllerClz.name');
+        const method = get(routeInfo, 'method') as string;
+        // 实例操作记录服务
+        const dataRecordService = await ctx.requestContext.getAsync(DataRecordService);
+        // 组织操作记录数据
+        const dataRecord = await dataRecordService.makeLogs(controller, method);
+        // 生成操作记录数据
+        const result = await dataRecordService.create(dataRecord);
+        if (result) {
+          const id = get(result, '_id');
+          if (id) {
+            // 将id放到app中.因为单例模式只能通过app获取;而不用单例模式,会引发多个监听.会重复记录
+            this.app.setAttr('record_id', new ObjectId(id).toString());
+          }
+        }
+        await next();
+      }
+    };
+  }
+}

+ 0 - 2
src/queue/esSync.queue.ts

@@ -18,7 +18,6 @@ export class EsSyncProcessor implements IProcessor {
     // ...
     console.log('in es sync processor');
     const result = await this.dataRecord.noDealQuery({ es_sync: false });
-    console.log(result.length);
     for (const i of result) {
       const origin_data = this.hasContext(get(i, 'origin_data'));
       const new_data = this.hasContext(get(i, 'new_data'));
@@ -46,7 +45,6 @@ export class EsSyncProcessor implements IProcessor {
         const d2 = difference(ndkeys, odkeys);
         // d3: 两组数据共有的表,都是修改
         const d3 = intersection(odkeys, ndkeys);
-        console.log(d1, d2, d3);
         if (d1.length > 0) {
           // 全部删除
           await this.allDeleteData(i, d1);

+ 106 - 0
src/service/db.service.ts

@@ -0,0 +1,106 @@
+import { App, Config, Init, Inject, Logger, Provide, Singleton } from '@midwayjs/decorator';
+import { Application, Context } from '@midwayjs/koa';
+import { InjectEntityModel } from '@midwayjs/typegoose';
+import { ReturnModelType } from '@typegoose/typegoose';
+import { get, head, last } from 'lodash';
+import { DataLogs } from '../entityRecord/dataLogs.entity';
+import { mongoose } from '@typegoose/typegoose';
+import * as dayjs from 'dayjs';
+import { Types } from 'mongoose';
+import { DataRecordService } from './record/dataRecord.service';
+import { GetModel } from 'free-midway-component';
+import { ILogger } from '@midwayjs/core';
+const ObjectId = Types.ObjectId;
+
+@Provide()
+@Singleton()
+export class DBService {
+  @Config('dbName')
+  dbName: string;
+  @Logger()
+  logger: ILogger;
+  @Config('mongoose.dataSource')
+  mongooseConfig: any;
+  @InjectEntityModel(DataLogs)
+  dataLogsModel: ReturnModelType<typeof DataLogs>;
+  @Inject()
+  dataRecordService: DataRecordService;
+
+  conn: any;
+  @App()
+  app: Application;
+  @Init()
+  async init() {
+    const conns = mongoose.connections;
+    const conn = conns.find(f => f.name === this.dbName);
+    console.log('change stream init');
+    conn.watch([], { fullDocument: 'updateLookup' }).on('change', async data => {
+      const record_id: string = this.app.getAttr('record_id');
+      if (!record_id) return;
+      // 查询日志数据,没有直接返回
+      const record: any = await this.dataRecordService.fetch(record_id);
+      if (!record) return;
+      const { operationType } = data;
+      const modelName: string = get(data, 'ns.coll');
+      // 没有表名不能继续
+      if (!modelName) return;
+      const model = GetModel(modelName);
+      // 未找到model不能继续
+      if (!model) return;
+      const allowOpera = ['insert', 'update', 'delete'];
+      // 只对表数据变化做处理
+      if (!allowOpera.includes(operationType)) return;
+      let data_id;
+      if (get(data, 'documentKey._id') && ObjectId.isValid(get(data, 'documentKey._id'))) data_id = new ObjectId(get(data, 'documentKey._id')).toString();
+      else {
+        console.log('id error');
+        return false;
+      }
+      const logsObj = { coll: modelName, time: dayjs().format('YYYY-MM-DD HH:mm:ss'), data_id, data: get(data, 'fullDocument'), method: operationType };
+      // 多个数据同步,不过根据logsObj去查询.不重复添加记录.一个数据同一个时间只允许记录一个,先来先记
+      const num = await this.dataLogsModel.count(logsObj);
+      if (num > 0) {
+        console.log('多个变更记录');
+        return;
+      }
+      let new_data, origin_data;
+      if (operationType === 'insert') {
+        // 无原数据
+        // 可以直接创建数据
+        await this.dataLogsModel.create(logsObj);
+        new_data = logsObj.data;
+      } else if (operationType === 'update') {
+        // 可以直接创建数据并且取最后两条
+        await this.dataLogsModel.create(logsObj);
+        const logs = await this.dataLogsModel.find({ coll: logsObj.coll, data_id: logsObj.data_id }).sort({ time: -1 }).limit(2).lean();
+        const newLogs = head(logs);
+        const originLogs = last(logs);
+        if (newLogs) new_data = get(newLogs, 'data');
+        if (originLogs) origin_data = get(originLogs, 'data');
+      } else if (operationType === 'delete') {
+        // 无新数据
+        // 先取最后一条,再创建
+        const logs = await this.dataLogsModel.find({ coll: logsObj.coll, data_id: logsObj.data_id }).sort({ time: -1 }).limit(1).lean();
+        const originLogs = head(logs);
+        if (originLogs) origin_data = get(originLogs, 'data');
+        await this.dataLogsModel.create(logsObj);
+      }
+      // 处理数据
+      if (origin_data) {
+        const rod = get(record, 'origin_data', {});
+        if (!rod[modelName]) rod[modelName] = [];
+        rod[modelName].push(origin_data);
+        record.origin_data = rod;
+      }
+      if (new_data) {
+        const nod = get(record, 'new_data', {});
+        if (!nod[modelName]) nod[modelName] = [];
+        nod[modelName].push(new_data);
+        record.new_data = nod;
+      }
+      // 更新记录
+      await this.dataRecordService.updateOne(record_id, record);
+      this.logger.warn('record success')
+    });
+  }
+}

+ 23 - 0
src/service/i18n.service.ts

@@ -0,0 +1,23 @@
+import { Config, Inject, Provide } from '@midwayjs/decorator';
+import { MidwayI18nService } from '@midwayjs/i18n';
+import { Context } from '@midwayjs/koa';
+
+@Provide()
+export class I18nService {
+  @Config('i18n.defaultLocale')
+  defaultLocale: string;
+  @Inject()
+  ctx: Context;
+  @Inject()
+  i18n: MidwayI18nService;
+
+  translate(code:any) {
+    return this.i18n.translate(`${code}`, { locale: this.ctx.locale });
+  }
+  translateError(code:any) {
+    return this.i18n.translate(`${code}`, { locale: this.ctx.locale, group: 'error' });
+  }
+  translateMethod(code:any) {
+    return this.i18n.translate(`${code}`, { locale: this.ctx.locale, group: 'error' });
+  }
+}

+ 15 - 11
src/service/login.service.ts

@@ -1,11 +1,13 @@
 import { Config, Inject, Provide } from '@midwayjs/core';
-import { FrameworkErrorEnum, GetModel, ServiceError } from 'free-midway-component';
+import { GetModel, ServiceError } from 'free-midway-component';
 import { get, isEqual, upperFirst } from 'lodash';
 import { LoginDTO, LoginType, UPwdDTO } from '../interface/login.interface';
 import { RoleService } from '../service/system/role.service';
 import { RedisService } from '@midwayjs/redis';
 import * as Crypto from 'crypto-js';
 import { Context } from '@midwayjs/koa';
+import { I18nService } from './i18n.service';
+import { FrameErrorEnum } from '../error/frame.error';
 @Provide()
 export class LoginService {
   @Inject()
@@ -20,6 +22,8 @@ export class LoginService {
   jwtExpiresIn;
   @Inject()
   redisService: RedisService;
+  @Inject()
+  i18n: I18nService;
 
   async onePointLogin(loginVo) {
     const { _id, role } = loginVo;
@@ -37,9 +41,9 @@ export class LoginService {
 
   async onePointCheck() {
     const user = this.ctx.user;
-    if (!user) throw new ServiceError('未检测到登录信息,请重新登录!', FrameworkErrorEnum.NOT_LOGIN);
+    if (!user) throw new ServiceError(this.i18n.translateError(FrameErrorEnum.NOT_LOGIN), FrameErrorEnum.NOT_LOGIN);
     const { _id, role, login_code } = user;
-    if (!login_code) throw new ServiceError('未检测到登录标识,请重新登录!', FrameworkErrorEnum.NOT_LOGIN);
+    if (!login_code) throw new ServiceError(this.i18n.translateError(FrameErrorEnum.NOT_LOGIN), FrameErrorEnum.NOT_LOGIN);
     // 解密
     const decodeResult = Crypto.AES.decrypt(login_code, this.jwtSecret);
     const decode = Crypto.enc.Utf8.stringify(decodeResult).toString();
@@ -50,13 +54,13 @@ export class LoginService {
     const rediskey = `${this.loginSign}:${role}:${_id}`;
     // 取出当前记录在案的 code
     const redisCode = await this.redisService.get(rediskey);
-    if(!redisCode) throw new ServiceError('账号登录已失效,请重新登录!', FrameworkErrorEnum.NOT_LOGIN);
+    if(!redisCode) throw new ServiceError(this.i18n.translateError(`${FrameErrorEnum.ACCOUNT_HAS_EXPIRED}`), FrameErrorEnum.ACCOUNT_HAS_EXPIRED);
     // 判断是否一致
     if (code === redisCode) {
       // 一致,延时
       await this.redisService.expire(rediskey, this.jwtExpiresIn);
     } else {
-      throw new ServiceError('本账号已在其他地方登录,请重新登录!', FrameworkErrorEnum.NOT_LOGIN);
+      throw new ServiceError(this.i18n.translateError(`${FrameErrorEnum.ACCOUNT_LOGGED_IN_ELESWHERE}`), FrameErrorEnum.ACCOUNT_LOGGED_IN_ELESWHERE);
     }
   }
 
@@ -69,9 +73,9 @@ export class LoginService {
   async loginByAccount(data: LoginDTO, type: LoginType) {
     const model = GetModel(upperFirst(type));
     const user = await model.findOne({ account: data.account }, '+password').lean();
-    if (!user) throw new ServiceError('未找到用户信息', FrameworkErrorEnum.NOT_FOUND_DATA);
+    if (!user) throw new ServiceError(this.i18n.translateError(FrameErrorEnum.USER_NOT_FOUND), FrameErrorEnum.USER_NOT_FOUND);
     await this.checkAccountCanLogin(user, type);
-    if (!isEqual(user.password.secret, data.password)) throw new ServiceError('密码错误', FrameworkErrorEnum.SERVICE_FAULT);
+    if (!isEqual(user.password.secret, data.password)) throw new ServiceError(this.i18n.translateError(FrameErrorEnum.BAD_PASSWORD), FrameErrorEnum.BAD_PASSWORD);
     return user;
   }
   /**
@@ -85,19 +89,19 @@ export class LoginService {
     // 其他用户需要看status是不是'1';
     if (type === 'Admin') {
       if (get(user, 'is_super') === '1') {
-        if (get(user, 'is_use') === '1') throw new ServiceError('该用户已被禁用', FrameworkErrorEnum.SERVICE_FAULT);
+        if (get(user, 'is_use') === '1') throw new ServiceError(this.i18n.translateError(FrameErrorEnum.USER_IS_DISABLED), FrameErrorEnum.USER_IS_DISABLED);
       }
     } else {
-      if (get(user, 'status') !== '1') throw new ServiceError('该用户已被禁用', FrameworkErrorEnum.SERVICE_FAULT);
+      if (get(user, 'status') !== '1') throw new ServiceError(this.i18n.translateError(FrameErrorEnum.USER_IS_DISABLED), FrameErrorEnum.USER_IS_DISABLED);
       const role = await this.roleService.findOne({ code: type, is_use: '0' });
-      if (!role) throw new ServiceError('当前角色下的用户无法使用!', FrameworkErrorEnum.SERVICE_FAULT);
+      if (!role) throw new ServiceError(this.i18n.translateError(FrameErrorEnum.ROLE_IS_DISABLED), FrameErrorEnum.ROLE_IS_DISABLED);
     }
   }
 
   async updatePwd(data: UPwdDTO, type: LoginType) {
     const model = GetModel(upperFirst(type));
     const user = await model.findById(data._id);
-    if (!user) new ServiceError('未找到用户信息!', FrameworkErrorEnum.DATA_NOT_FOUND);
+    if (!user) new ServiceError(this.i18n.translateError(FrameErrorEnum.USER_NOT_FOUND), FrameErrorEnum.USER_NOT_FOUND);
     user.password = data.password;
     await user.save();
   }

+ 11 - 0
src/service/record/dataLogs.service.ts

@@ -0,0 +1,11 @@
+import { Provide } from '@midwayjs/decorator';
+import { InjectEntityModel } from '@midwayjs/typegoose';
+import { ReturnModelType } from '@typegoose/typegoose';
+import { BaseService } from 'free-midway-component';
+import { DataLogs } from '../../entityRecord/dataLogs.entity';
+type modelType = ReturnModelType<typeof DataLogs>;
+@Provide()
+export class DataLogsService extends BaseService<modelType> {
+  @InjectEntityModel(DataLogs)
+  model: modelType;
+}

+ 3 - 2
src/service/record/dataRecord.service.ts

@@ -1,4 +1,4 @@
-import { Provide } from '@midwayjs/decorator';
+import { Provide, Scope, ScopeEnum } from '@midwayjs/decorator';
 import { InjectEntityModel } from '@midwayjs/typegoose';
 import { ReturnModelType } from '@typegoose/typegoose';
 import { BaseService } from 'free-midway-component';
@@ -8,6 +8,7 @@ import dayjs = require('dayjs');
 
 type modelType = ReturnModelType<typeof DataRecord>;
 @Provide()
+@Scope(ScopeEnum.Request, { allowDowngrade: true })
 export class DataRecordService extends BaseService<modelType> {
   @InjectEntityModel(DataRecord)
   model: modelType;
@@ -54,7 +55,7 @@ export class DataRecordService extends BaseService<modelType> {
     let data = null;
     if (method === 'delete') return data;
     const modelName = get(service, 'model.modelName');
-    if (method === 'update') {
+    if (method === 'update' || method === 'status') {
       if (origin_data) {
         const list = get(origin_data, modelName);
         const arr = [];

+ 6 - 3
src/service/system/role.service.ts

@@ -1,4 +1,4 @@
-import { Provide, Inject, Init } from '@midwayjs/decorator';
+import { Provide, Inject } from '@midwayjs/decorator';
 import { InjectEntityModel } from '@midwayjs/typegoose';
 import { ReturnModelType } from '@typegoose/typegoose';
 import { BaseService, ServiceError, FrameworkErrorEnum } from 'free-midway-component';
@@ -7,6 +7,8 @@ import { Menus } from '../../entity/system/menus.entity';
 import { MenusService } from './menus.service';
 import { flattenDeep, uniq, get, lowerFirst, upperFirst, last } from 'lodash';
 import { Context } from '@midwayjs/koa';
+import { I18nService } from '../i18n.service';
+import { FrameErrorEnum } from '../../error/frame.error';
 type modelType = ReturnModelType<typeof Role>;
 @Provide()
 export class RoleService extends BaseService<modelType> {
@@ -19,7 +21,8 @@ export class RoleService extends BaseService<modelType> {
   menusService: MenusService;
   @Inject()
   ctx: Context;
-
+  @Inject()
+  i18n: I18nService;
   //是否是超级管理员
   isSuperAdmin() {
     const user = this.ctx.user;
@@ -35,7 +38,7 @@ export class RoleService extends BaseService<modelType> {
     }
     const roleCode = [lowerFirst(user.role), upperFirst(user.role)];
     const role = await this.model.findOne({ code: roleCode, is_use: '0' }).lean();
-    if (!role) throw new ServiceError('当前角色下的用户无法使用!', FrameworkErrorEnum.SERVICE_FAULT);
+    if (!role) throw new ServiceError(this.i18n.translateError(FrameErrorEnum.ROLE_IS_DISABLED), FrameworkErrorEnum.SERVICE_FAULT);
     const roleMenu = get(role, 'menu', []);
     const menu = roleMenu.map(i => {
       const arr = i.split('.');