Forráskód Böngészése

update:权限部分可以尝试放到代理项目中处理,思路见readme

lrf 11 hónapja
szülő
commit
1e98b54155

+ 19 - 2
README.md

@@ -1,4 +1,5 @@
 # vue3js-template-service
+## 本项目是服务,包含处理逻辑,前端部分最好再弄个项目,区分开
 ## 1.单点登录
 * 1.不需要登录就可以使用的接口: 请求函数的方法注解参数添加 description: 'ignore'即可
 
@@ -6,9 +7,25 @@
 * checkPermissionCode
 |注解名|类型|说明|
 |:-:|:-:|:-:|
-|roleCode|string|该接口权限所需标识 ${路由名称}.${功能}|
+|roleCode|string|该接口权限所需标识 ${路由名称}.${功能}. 如果是query, 只写${路由名称},其他查询方法自己规定|
 
-* dataRecord
+
+统一: 
+  添加:create
+  修改:update
+  删除:delete
+  自定义: 
+    vue中的method(函数名) 要与 菜单中功能列表 的函数名对上----保证按钮正常判断
+    method中调用的api的roleCode 需要与功能列表中的 code 能对应上: 
+      e.g.: 更换 状态 只是点击 启用/禁用 不过用的是 修改接口 所以该接口是需要有 修改接口的权限 与 页面上可以使用该接口的按钮
+
+对于权限这里有的想法:
+  按当前确定好的数据来看, 可以直接得出:
+    1.某功能全路径的编码
+  而当前用户需要检验用户编码时,一定能得到该用户所有权限编码(可以是全路径)
+  然后在用 权限编码 核对
+  那么现在主要就是 不知道 当前是哪个权限编码,如果可以确定这个权限编码,就可以在代理项目中处理权限问题
+* dataRecord (应该不用了)
 |注解名|类型|说明|
 |:-:|:-:|:-:|
 |before|string|获取原数据的函数名;该service下的函数名,纯自定义|

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

@@ -26,6 +26,11 @@ export default {
       },
     },
   },
+  validate: {
+    validationOptions: {
+      allowUnknown: true, // 全局生效
+    },
+  },
   webSocket: {
     serverHeartbeatInterval: 30000,
     enableServerHeartbeatCheck: true,

+ 2 - 2
src/config/config.local.ts

@@ -1,6 +1,6 @@
 import { MidwayConfig } from '@midwayjs/core';
-const ip = '127.0.0.1'; //120.48.146.1
-const redisHost = '127.0.0.1';
+const ip = '120.48.146.1'; //120.48.146.1
+const redisHost = '120.48.146.1';
 const redisPwd = '123456';
 const redisDB = 6;
 const projectDB = 'vue3js-template-test';

+ 1 - 3
src/configuration.ts

@@ -10,7 +10,6 @@ import { VerifyTokenInit } from './decorator/verifyToken.decorator';
 import { CheckPermissionCodeInit } from './decorator/checkPermissionCode';
 import * as swagger from '@midwayjs/swagger';
 import * as redis from '@midwayjs/redis';
-import { CheckOnePointLoginMiddleware } from './middleware/checkOnePointLogin.middleware';
 import { newsQueryMiddleware } from './middleware/newsQuery.middleware';
 import * as i18n from '@midwayjs/i18n';
 import { SetLocaleToCtxMiddleware } from './middleware/setLocaleToCtx.middleware';
@@ -48,8 +47,7 @@ export class MainConfiguration {
 
   async onReady() {
     this.app.getMiddleware().insertFirst(SetLocaleToCtxMiddleware)
-    this.app.getMiddleware().insertAfter(CheckOnePointLoginMiddleware, 'checkToken');
-    this.app.getMiddleware().insertAfter(DataRecordMiddleware, 'checkOnePonitLogin');
+    this.app.getMiddleware().insertAfter(DataRecordMiddleware, 'SetLocaleToCtxMiddleware');
     this.app.getMiddleware().insertAfter(newsQueryMiddleware, 'newsQuery');
     this.app.getMiddleware().insertFirst(ReportMiddleware)
     // 注解

+ 3 - 1
src/controller/system/admin.controller.ts

@@ -4,7 +4,8 @@ import { AdminService } from '../../service/system/admin.service';
 import { CDTO_admin, CVO_admin, FVO_admin, QDTO_admin, QVO_admin, UDTO_admin, UVAO_admin } from '../../interface/system/admin.interface';
 import { ApiResponse, ApiTags, ApiQuery } from '@midwayjs/swagger';
 import { Validate } from '@midwayjs/validate';
-@ApiTags(['管理员表'])
+import { checkPermissionCode } from '../../decorator/checkPermissionCode';
+@ApiTags(['管理用户表'])
 @Controller('/admin')
 export class AdminController extends BaseController {
   @Inject()
@@ -12,6 +13,7 @@ export class AdminController extends BaseController {
 
   @Post('/')
   @Validate()
+  @checkPermissionCode({ roleCode: 'system_admin.add' })
   @ApiResponse({ type: CVO_admin })
   async create(@Body() data: CDTO_admin) {
     const dbData = await this.service.create(data);

+ 76 - 0
src/controller/system/dept.controller.ts

@@ -0,0 +1,76 @@
+import { Body, Controller, Del, Get, Inject, Param, Post, Query } from '@midwayjs/decorator';
+import { BaseController } from 'free-midway-component';
+import { DeptService } from '../../service/system/dept.service';
+import { CDTO_dept, CVO_dept, FVO_dept, QDTO_dept, QVO_dept, UDTO_dept, UVAO_dept } from '../../interface/system/dept.interface';
+import { ApiResponse, ApiTags, ApiQuery } from '@midwayjs/swagger';
+import { Validate } from '@midwayjs/validate';
+import { checkPermissionCode } from '../../decorator/checkPermissionCode';
+@ApiTags(['部门表'])
+@Controller('/dept')
+export class DeptController extends BaseController {
+  @Inject()
+  service: DeptService;
+
+  @Post('/')
+  @Validate()
+  @checkPermissionCode({ roleCode: 'system_dept.create' })
+  @ApiResponse({ type: CVO_dept })
+  async create(@Body() data: CDTO_dept) {
+    const dbData = await this.service.create(data);
+    const result = new CVO_dept(dbData);
+    return result;
+  }
+  @Get('/')
+  @ApiQuery({ name: 'query' })
+  @checkPermissionCode({ roleCode: 'system_dept' })
+  @ApiResponse({ type: QVO_dept })
+  async query() {
+    const data = await this.service.queryAll();
+    return data;
+  }
+  @Get('/nextLevel/:id')
+  @ApiQuery({ name: 'nextLevel' })
+  @checkPermissionCode({ roleCode: 'system_dept.nextLevel' })
+  @ApiResponse({ type: QVO_dept })
+  async nextLevel(@Param('id') id: string, @Query('skip') skip: number, @Query('limit') limit: number) {
+    const { data, total } = await this.service.getNextLevel(id, { skip, limit });
+    return { data, total };
+  }
+
+  @Get('/:id')
+  @checkPermissionCode({ roleCode: 'system_dept' })
+  @ApiResponse({ type: FVO_dept })
+  async fetch(@Param('id') id: string) {
+    const data = await this.service.fetch(id);
+    const result = new FVO_dept(data);
+    return result;
+  }
+
+  @Post('/:id')
+  @Validate()
+  @checkPermissionCode({ roleCode: 'system_dept.update' })
+  @ApiResponse({ type: UVAO_dept })
+  async update(@Param('id') id: string, @Body() body: UDTO_dept) {
+    const result = await this.service.updateOne(id, body);
+    return result;
+  }
+
+  @Del('/:id')
+  @checkPermissionCode({ roleCode: 'system_dept.delete' })
+  @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.');
+  }
+}

+ 6 - 0
src/controller/system/dictData.controller.ts

@@ -4,6 +4,7 @@ import { DictDataService } from '../../service/system/dictData.service';
 import { CDTO_dictData, CVO_dictData, FVO_dictData, QDTO_dictData, QVO_dictData, UDTO_dictData, UVAO_dictData } from '../../interface/system/dictData.interface';
 import { ApiResponse, ApiTags, ApiQuery } from '@midwayjs/swagger';
 import { Validate } from '@midwayjs/validate';
+import { checkPermissionCode } from '../../decorator/checkPermissionCode';
 @ApiTags(['字典数据表'])
 @Controller('/dictData')
 export class DictDataController extends BaseController {
@@ -12,6 +13,7 @@ export class DictDataController extends BaseController {
 
   @Post('/')
   @Validate()
+  @checkPermissionCode({ roleCode: 'system_dict.create' })
   @ApiResponse({ type: CVO_dictData })
   async create(@Body() data: CDTO_dictData) {
     const dbData = await this.service.create(data);
@@ -20,6 +22,7 @@ export class DictDataController extends BaseController {
   }
   @Get('/')
   @ApiQuery({ name: 'query' })
+  @checkPermissionCode({ roleCode: 'system_dict' })
   @ApiResponse({ type: QVO_dictData })
   async query(@Query() filter: QDTO_dictData, @Query('skip') skip: number, @Query('limit') limit: number) {
     const list = await this.service.query(filter, { skip, limit, sort: { sort: 1 } });
@@ -33,6 +36,7 @@ export class DictDataController extends BaseController {
   }
 
   @Get('/:id')
+  @checkPermissionCode({ roleCode: 'system_dict' })
   @ApiResponse({ type: FVO_dictData })
   async fetch(@Param('id') id: string) {
     const data = await this.service.fetch(id);
@@ -42,6 +46,7 @@ export class DictDataController extends BaseController {
 
   @Post('/:id')
   @Validate()
+  @checkPermissionCode({ roleCode: 'system_dict.update' })
   @ApiResponse({ type: UVAO_dictData })
   async update(@Param('id') id: string, @Body() body: UDTO_dictData) {
     const result = await this.service.updateOne(id, body);
@@ -49,6 +54,7 @@ export class DictDataController extends BaseController {
   }
 
   @Del('/:id')
+  @checkPermissionCode({ roleCode: 'system_dict.delete' })
   @Validate()
   async delete(@Param('id') id: string) {
     await this.service.delete(id);

+ 6 - 0
src/controller/system/dictType.controller.ts

@@ -4,6 +4,7 @@ import { DictTypeService } from '../../service/system/dictType.service';
 import { CDTO_dictType, CVO_dictType, FVO_dictType, QDTO_dictType, QVO_dictType, UDTO_dictType, UVAO_dictType } from '../../interface/system/dictType.interface';
 import { ApiResponse, ApiTags, ApiQuery } from '@midwayjs/swagger';
 import { Validate } from '@midwayjs/validate';
+import { checkPermissionCode } from '../../decorator/checkPermissionCode';
 @ApiTags(['字典类型表'])
 @Controller('/dictType')
 export class DictTypeController extends BaseController {
@@ -12,6 +13,7 @@ export class DictTypeController extends BaseController {
 
   @Post('/')
   @Validate()
+  @checkPermissionCode({ roleCode: 'system_dict.create' })
   @ApiResponse({ type: CVO_dictType })
   async create(@Body() data: CDTO_dictType) {
     const dbData = await this.service.create(data);
@@ -20,6 +22,7 @@ export class DictTypeController extends BaseController {
   }
   @Get('/')
   @ApiQuery({ name: 'query' })
+  @checkPermissionCode({ roleCode: 'system_dict' })
   @ApiResponse({ type: QVO_dictType })
   async query(@Query() filter: QDTO_dictType, @Query('skip') skip: number, @Query('limit') limit: number) {
     const list = await this.service.query(filter, { skip, limit });
@@ -33,6 +36,7 @@ export class DictTypeController extends BaseController {
   }
 
   @Get('/:id')
+  @checkPermissionCode({ roleCode: 'system_dict' })
   @ApiResponse({ type: FVO_dictType })
   async fetch(@Param('id') id: string) {
     const data = await this.service.fetch(id);
@@ -42,6 +46,7 @@ export class DictTypeController extends BaseController {
 
   @Post('/:id')
   @Validate()
+  @checkPermissionCode({ roleCode: 'system_dict.update' })
   @ApiResponse({ type: UVAO_dictType })
   async update(@Param('id') id: string, @Body() body: UDTO_dictType) {
     const result = await this.service.updateOne(id, body);
@@ -49,6 +54,7 @@ export class DictTypeController extends BaseController {
   }
 
   @Del('/:id')
+  @checkPermissionCode({ roleCode: 'system_dict.delete' })
   @Validate()
   async delete(@Param('id') id: string) {
     await this.service.delete(id);

+ 6 - 0
src/controller/system/menus.controller.ts

@@ -4,6 +4,7 @@ import { MenusService } from '../../service/system/menus.service';
 import { CDTO_menus, CVO_menus, FVO_menus, QVO_menus, UDTO_menus, UVAO_menus } from '../../interface/system/menus.interface';
 import { ApiResponse, ApiTags, ApiQuery } from '@midwayjs/swagger';
 import { Validate } from '@midwayjs/validate';
+import { checkPermissionCode } from '../../decorator/checkPermissionCode';
 @ApiTags(['菜单表'])
 @Controller('/menus')
 export class MenusController extends BaseController {
@@ -12,6 +13,7 @@ export class MenusController extends BaseController {
 
   @Post('/')
   @Validate()
+  @checkPermissionCode({ roleCode: 'system_menus.create' })
   @ApiResponse({ type: CVO_menus })
   async create(@Body() data: CDTO_menus) {
     const dbData = await this.service.create(data);
@@ -20,6 +22,7 @@ export class MenusController extends BaseController {
   }
   @Get('/')
   @ApiQuery({ name: 'query' })
+  @checkPermissionCode({ roleCode: 'system_menus' })
   @ApiResponse({ type: QVO_menus })
   async query() {
     const list = await this.service.queryMenu();
@@ -27,6 +30,7 @@ export class MenusController extends BaseController {
   }
 
   @Get('/:id')
+  @checkPermissionCode({ roleCode: 'system_menus' })
   @ApiResponse({ type: FVO_menus })
   async fetch(@Param('id') id: string) {
     const data = await this.service.fetch(id);
@@ -36,6 +40,7 @@ export class MenusController extends BaseController {
 
   @Post('/:id')
   @Validate()
+  @checkPermissionCode({ roleCode: 'system_menus.update' })
   @ApiResponse({ type: UVAO_menus })
   async update(@Param('id') id: string, @Body() body: UDTO_menus) {
     const result = await this.service.updateOne(id, body);
@@ -43,6 +48,7 @@ export class MenusController extends BaseController {
   }
 
   @Del('/:id')
+  @checkPermissionCode({ roleCode: 'system_menus.delete' })
   @Validate()
   async delete(@Param('id') id: string) {
     await this.service.delete(id);

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

@@ -18,6 +18,7 @@ export class RoleController extends BaseController {
   @Post('/')
   @verifyToken()
   @Validate()
+  @checkPermissionCode({ roleCode: 'system_role.create' })
   @ApiResponse({ type: CVO_role })
   async create(@Body() data: CDTO_role) {
     const dbData = await this.service.create(data);
@@ -42,6 +43,7 @@ export class RoleController extends BaseController {
 
   @Get('/:id')
   @verifyToken()
+  @checkPermissionCode({ roleCode: 'system_role' })
   @ApiResponse({ type: FVO_role })
   async fetch(@Param('id') id: string) {
     const data = await this.service.fetch(id);
@@ -61,6 +63,7 @@ export class RoleController extends BaseController {
 
   @Del('/:id')
   @verifyToken()
+  @checkPermissionCode({ roleCode: 'system_role.delete' })
   @Validate()
   async delete(@Param('id') id: string) {
     await this.service.delete(id);

+ 11 - 19
src/decorator/checkPermissionCode.ts

@@ -8,17 +8,6 @@ export const CHECKPERMISSIONCODE_KEY = 'decorator:check_permission_code';
 export const checkPermissionCode = options => {
   return createCustomMethodDecorator(CHECKPERMISSIONCODE_KEY, options);
 };
-// 第二层及以后的权限,去掉第一层级
-const resetRoleMenus = list => {
-  list = list.map(i => {
-    const arr = i.split('.');
-    if (arr.length <= 1) return i;
-    arr.shift();
-    return arr.join('.');
-  });
-  return list;
-};
-
 export const CheckPermissionCodeInit = (decoratorService: MidwayDecoratorService) => {
   decoratorService.registerMethodHandler(CHECKPERMISSIONCODE_KEY, options => {
     return {
@@ -28,19 +17,22 @@ export const CheckPermissionCodeInit = (decoratorService: MidwayDecoratorService
           const instance = joinPoint.target;
           const ctx = instance[REQUEST_OBJ_CTX_KEY];
           const roleService = await ctx.requestContext.getAsync(RoleService);
-          const isAdmin = roleService.isSuperAdmin();
+          const isAdmin = await roleService.isSuperAdmin();
           if (!isAdmin) {
-            let roleMenus = await roleService.getUserMenus(true);
-            roleMenus = resetRoleMenus(roleMenus);
-            if (!roleMenus.includes(roleCode)) {
+            const roleMenus = await roleService.getUserMenus(true);
+            let result = false;
+            for (const rc of roleMenus) {
+              const r = rc.includes(roleCode);
+              if (r) {
+                result = r;
+                break;
+              }
+            }
+            if (!result) {
               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;
           }
-          const result = await joinPoint.proceed(...joinPoint.args);
-          return result;
         }
         const result = await joinPoint.proceed(...joinPoint.args);
         return result;

+ 10 - 10
src/entity/system/admin.entity.ts

@@ -5,13 +5,13 @@ import { isString } from 'lodash';
   schemaOptions: { collection: 'admin' },
 })
 export class Admin extends BaseModel {
-  @prop({ required: true, index: true, zh: '账号' })
-  account: string;
-  @prop({ required: false, index: false, zh: '名称' })
+  @prop({ required: true, index: false, zh: '管理员名称' })
   nick_name: string;
+  @prop({ required: true, index: false, zh: '账号' })
+  account: string;
   // 手动删除set前的大括号,处理太麻烦了.就手动删除吧
   @prop({
-    required: false,
+    required: true,
     index: false,
     zh: '密码',
     select: false,
@@ -23,12 +23,12 @@ export class Admin extends BaseModel {
     },
   })
   password: object;
-  @prop({ required: false, index: false, zh: '是否是超级管理员', remark: '0:超级管理员;1普通用户', default: '1' })
+  @prop({ required: false, index: false, zh: '拥有角色', remark: '可以有多个角色扩展权限' })
+  role: Array<any>;
+  @prop({ required: false, index: false, zh: '所属部门', remark: '只能隶属1各部门' })
+  dept: string;
+  @prop({ required: false, index: false, zh: '是否是超级管理员', remark: '0:是;1否', default: '1' })
   is_super: string;
-  @prop({ required: false, index: false, zh: '角色' })
-  role: string;
-  @prop({ required: false, index: false, zh: 'openid' })
-  openid: string;
-  @prop({ required: false, index: false, zh: '是否启用', default: '0' })
+  @prop({ required: false, index: false, zh: '使用状态', remark: '0:正常;1冻结', default: '0' })
   is_use: string;
 }

+ 19 - 0
src/entity/system/dept.entity.ts

@@ -0,0 +1,19 @@
+import { modelOptions, prop } from '@typegoose/typegoose';
+import { BaseModel } from 'free-midway-component';
+@modelOptions({
+  schemaOptions: { collection: 'dept' },
+})
+export class Dept extends BaseModel {
+  @prop({'required':false,'index':false,'zh':'部门名称'})
+  name: string
+  @prop({'required':false,'index':false,'zh':'资源权限'})
+  resource: Array<any>
+  @prop({'required':false,'index':false,'zh':'上级部门id'})
+  parent_id: string
+  @prop({'required':false,'index':false,'zh':'使用状态','remark':'0使用;1禁用','default':'0'})
+  is_use: string
+  @prop({'required':false,'index':false,'zh':'是否是总部门','remark':'0:是;1否','default':'1'})
+  is_super: string
+  @prop({'required':false,'index':false,'zh':'排序'})
+  order_num: number
+}

+ 3 - 1
src/interface/login.interface.ts

@@ -31,12 +31,14 @@ export class LoginVO {
     this.openid = get(data, 'openid');
     this.role = get(data, 'role');
     this.is_super = get(data, 'is_super');
+    this.dept = get(data, 'dept');
   }
   _id: string;
   nick_name: string;
   openid: string;
-  role: string;
+  role: Array<any>;
   is_super: number;
   @ApiProperty({ description: '登录标识' })
   'login_code': string = undefined;
+  dept?: string;
 }

+ 32 - 28
src/interface/system/admin.interface.ts

@@ -1,6 +1,6 @@
 import { Rule, RuleType } from '@midwayjs/validate';
 import { ApiProperty } from '@midwayjs/swagger';
-import { SearchBase } from 'free-midway-component';
+import { FrameworkErrorEnum, SearchBase, ServiceError } from 'free-midway-component';
 import get = require('lodash/get');
 const dealVO = (cla, data) => {
   for (const key in cla) {
@@ -14,33 +14,33 @@ export class FVO_admin {
   }
   @ApiProperty({ description: '数据id' })
   _id: string = undefined;
+  @ApiProperty({ description: '管理员名称' })
+  'nick_name': string = undefined;
   @ApiProperty({ description: '账号' })
   'account': string = undefined;
-  @ApiProperty({ description: '名称' })
-  'nick_name': string = undefined;
   @ApiProperty({ description: '密码' })
   'password': string = undefined;
+  @ApiProperty({ description: '拥有角色' })
+  'role': Array<any> = undefined;
+  @ApiProperty({ description: '所属部门' })
+  'dept': string = undefined;
   @ApiProperty({ description: '是否是超级管理员' })
   'is_super': string = undefined;
-  @ApiProperty({ description: '角色' })
-  'role': string = undefined;
-  @ApiProperty({ description: 'openid' })
-  'openid': string = undefined;
-  @ApiProperty({ description: '是否启用' })
+  @ApiProperty({ description: '使用状态' })
   'is_use': string = undefined;
 }
 
+
 export class QDTO_admin extends SearchBase {
   constructor() {
     const like_prop = [];
-    const props = ['account'];
+    const props = [];
     const mapping = [];
     super({ like_prop, props, mapping });
   }
-  @ApiProperty({ description: '账号' })
-  'account': string = undefined;
 }
 
+
 export class QVO_admin extends FVO_admin {
   constructor(data: object) {
     super(data);
@@ -48,30 +48,32 @@ export class QVO_admin extends FVO_admin {
   }
 }
 
+
 export class CDTO_admin {
+  @ApiProperty({ description: '管理员名称' })
+@Rule(RuleType['string']().required().error(new ServiceError('缺少管理员名称',FrameworkErrorEnum.NEED_BODY)))
+  'nick_name': string = undefined;
   @ApiProperty({ description: '账号' })
-  @Rule(RuleType['string']().empty(''))
+@Rule(RuleType['string']().required().error(new ServiceError('缺少账号',FrameworkErrorEnum.NEED_BODY)))
   'account': string = undefined;
-  @ApiProperty({ description: '名称' })
-  @Rule(RuleType['string']().empty(''))
-  'nick_name': string = undefined;
   @ApiProperty({ description: '密码' })
-  @Rule(RuleType['string']().empty(''))
+@Rule(RuleType['string']().required().error(new ServiceError('缺少密码',FrameworkErrorEnum.NEED_BODY)))
   'password': string = undefined;
+  @ApiProperty({ description: '拥有角色' })
+@Rule(RuleType['array']().empty(''))
+  'role': Array<any> = undefined;
+  @ApiProperty({ description: '所属部门' })
+@Rule(RuleType['string']().empty(''))
+  'dept': string = undefined;
   @ApiProperty({ description: '是否是超级管理员' })
-  @Rule(RuleType['string']().empty(''))
+@Rule(RuleType['string']().empty(''))
   'is_super': string = undefined;
-  @ApiProperty({ description: '角色' })
-  @Rule(RuleType['string']().empty(''))
-  'role': string = undefined;
-  @ApiProperty({ description: 'openid' })
-  @Rule(RuleType['string']().empty(''))
-  'openid': string = undefined;
-  @ApiProperty({ description: '是否启用' })
-  @Rule(RuleType['string']().empty(''))
+  @ApiProperty({ description: '使用状态' })
+@Rule(RuleType['string']().empty(''))
   'is_use': string = undefined;
 }
 
+
 export class CVO_admin extends FVO_admin {
   constructor(data: object) {
     super(data);
@@ -79,12 +81,14 @@ export class CVO_admin extends FVO_admin {
   }
 }
 
+
 export class UDTO_admin extends CDTO_admin {
-  @ApiProperty({ description: '数据id' })
-  @Rule(RuleType['string']().empty(''))
-  _id: string = undefined;
+    @ApiProperty({ description: '数据id' })
+    @Rule(RuleType['string']().empty(''))
+    _id: string = undefined;
 }
 
+
 export class UVAO_admin extends FVO_admin {
   constructor(data: object) {
     super(data);

+ 92 - 0
src/interface/system/dept.interface.ts

@@ -0,0 +1,92 @@
+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_dept {
+  constructor(data: object) {
+    dealVO(this, data);
+  }
+  @ApiProperty({ description: '数据id' })
+  _id: string = undefined;
+  @ApiProperty({ description: '部门名称' })
+  'name': string = undefined;
+  @ApiProperty({ description: '资源权限' })
+  'resource': Array<any> = undefined;
+  @ApiProperty({ description: '上级部门id' })
+  'parent_id': string = undefined;
+  @ApiProperty({ description: '使用状态' })
+  'is_use': string = undefined;
+  @ApiProperty({ description: '是否是总部门' })
+  'is_super': string = undefined;
+  @ApiProperty({ description: '排序' })
+  'order_num': number = undefined;
+}
+
+
+export class QDTO_dept extends SearchBase {
+  constructor() {
+    const like_prop = [];
+    const props = [];
+    const mapping = [];
+    super({ like_prop, props, mapping });
+  }
+}
+
+
+export class QVO_dept extends FVO_dept {
+  constructor(data: object) {
+    super(data);
+    dealVO(this, data);
+  }
+}
+
+
+export class CDTO_dept {
+  @ApiProperty({ description: '部门名称' })
+@Rule(RuleType['string']().empty(''))
+  'name': string = undefined;
+  @ApiProperty({ description: '资源权限' })
+@Rule(RuleType['array']().empty(''))
+  'resource': Array<any> = undefined;
+  @ApiProperty({ description: '上级部门id' })
+@Rule(RuleType['string']().empty(''))
+  'parent_id': string = undefined;
+  @ApiProperty({ description: '使用状态' })
+@Rule(RuleType['string']().empty(''))
+  'is_use': string = undefined;
+  @ApiProperty({ description: '是否是总部门' })
+@Rule(RuleType['string']().empty(''))
+  'is_super': string = undefined;
+  @ApiProperty({ description: '排序' })
+@Rule(RuleType['number']().empty(''))
+  'order_num': number = undefined;
+}
+
+
+export class CVO_dept extends FVO_dept {
+  constructor(data: object) {
+    super(data);
+    dealVO(this, data);
+  }
+}
+
+
+export class UDTO_dept extends CDTO_dept {
+    @ApiProperty({ description: '数据id' })
+    @Rule(RuleType['string']().empty(''))
+    _id: string = undefined;
+}
+
+
+export class UVAO_dept extends FVO_dept {
+  constructor(data: object) {
+    super(data);
+    dealVO(this, data);
+  }
+}

+ 1 - 1
src/service/system/admin.service.ts

@@ -8,4 +8,4 @@ type modelType = ReturnModelType<typeof Admin>;
 export class AdminService extends BaseService<modelType> {
   @InjectEntityModel(Admin)
   model: modelType;
-}
+}

+ 61 - 0
src/service/system/dept.service.ts

@@ -0,0 +1,61 @@
+import { Provide } from '@midwayjs/decorator';
+import { InjectEntityModel } from '@midwayjs/typegoose';
+import { ReturnModelType } from '@typegoose/typegoose';
+import { BaseService } from 'free-midway-component';
+import { Dept } from '../../entity/system/dept.entity';
+type modelType = ReturnModelType<typeof Dept>;
+import { Types } from 'mongoose';
+import { get, isObject, orderBy } from 'lodash';
+const ObjectId = Types.ObjectId;
+@Provide()
+export class DeptService extends BaseService<modelType> {
+  @InjectEntityModel(Dept)
+  model: modelType;
+
+  async queryAll() {
+    const data = await this.model.find({}, { meta: 0, __v: 0 }).sort({ order_num: 1 }).lean();
+    let treeData = data.filter(f => !f.parent_id);
+    treeData = this.treeData(data, treeData);
+    return treeData;
+  }
+
+  async getNextLevel(id: string, query = { skip: 0, limit: 10 }) {
+    const data: any = await this.model
+      .find({ parent_id: id })
+      .skip(query.skip)
+      .limit(query.limit)
+      .populate({
+        path: 'parent_id',
+        select: 'name',
+        model: 'Dept',
+      })
+      .sort({ order_num: 1 })
+      .lean();
+    data.map(i => {
+      if (isObject(get(i, 'parent_id'))) {
+        i.parent_id_name = get(i, 'parent_id.name');
+        i.parent_id = get(i, 'parent_id._id');
+      }
+      return i;
+    });
+    const total = await this.model.count({ parent_id: id });
+    return { data, total };
+  }
+
+  treeData(allList, nowList) {
+    for (const nm of nowList) {
+      const { _id, parent_id } = nm;
+      // 查下下级其是否有目录
+      let children = allList.filter(f => new ObjectId(f.parent_id).equals(_id));
+      children = this.treeData(allList, children);
+      if (children.length > 0) nm.children = children;
+      // 换父级组件的名称
+      if (parent_id) {
+        const r = allList.find(f => new ObjectId(f._id).equals(parent_id));
+        if (r) nm.parent_name = r.name;
+      }
+    }
+    nowList = orderBy(nowList, ['order_num'], ['asc']);
+    return nowList;
+  }
+}

+ 79 - 17
src/service/system/role.service.ts

@@ -9,6 +9,8 @@ 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';
+import { Admin } from '../../entity/system/admin.entity';
+import { Dept } from '../../entity/system/dept.entity';
 type modelType = ReturnModelType<typeof Role>;
 @Provide()
 export class RoleService extends BaseService<modelType> {
@@ -17,41 +19,101 @@ export class RoleService extends BaseService<modelType> {
   @InjectEntityModel(Menus)
   menusModel: ReturnModelType<typeof Menus>;
 
+  @InjectEntityModel(Admin)
+  adminModel: ReturnModelType<typeof Admin>;
+
+  @InjectEntityModel(Dept)
+  deptModel: ReturnModelType<typeof Dept>;
+
   @Inject()
   menusService: MenusService;
+
   @Inject()
   ctx: Context;
   @Inject()
   i18n: I18nService;
   //是否是超级管理员
-  isSuperAdmin() {
+  async isSuperAdmin() {
     const user = this.ctx.user;
-    if (user.role === 'Admin' && user.is_super === '0') return true;
+    const admin = await this.adminModel.findById(user._id);
+    if (!admin) return false;
+    if (admin.is_super === '0') return true;
   }
 
   async getUserMenus(needCode = false) {
     const user = this.ctx.user;
-    // 这里需要改下. 平台的超级管理员有这些权限
-    if (this.isSuperAdmin()) {
+    // 平台的超级管理员有所有权限
+    if (await this.isSuperAdmin()) {
       const menus = await this.menusService.queryMenu({ is_use: '0' });
       return { menus };
     }
-    let roleCode;
-    for (const val of user.role) {
-      roleCode = [lowerFirst(val), upperFirst(val)];
+    // 其他用户需要把 部门 和 角色的权限叠加在一起
+    // 部门权限
+    const deptCodes = await this.getDeptCodes(get(user, 'dept'));
+
+    // 角色权限
+    const roleCodes = await this.getRoleCodes(get(user, 'role'));
+    let allCodes = [...deptCodes, ...roleCodes];
+    allCodes = uniq(allCodes);
+    // 只获取编码,直接返回
+    if (needCode) return allCodes;
+    // 根据编码获取菜单数据
+    const menuCodes = this.setMenuCodes(allCodes);
+    const menuList = await this.menusModel.find({ route_name: menuCodes }).lean();
+    let treeMenu = menuList.filter(f => !f.parent_id);
+    treeMenu = this.menusService.treeMenu(menuList, treeMenu);
+    return { menus: treeMenu, role_code: allCodes };
+  }
+
+  /**
+   * 整理出角色菜单的编码,主要是与route_name编码对应
+   * @param allCodes 本用户的角色+部门的完整权限编码
+   * @returns 菜单需要的编码
+   */
+  setMenuCodes(allCodes: Array<string>) {
+    const result = [];
+    for (const code of allCodes) {
+      const arr = code.split('.');
+      result.push(last(arr))
+    }
+    return uniq(result)
+  }
+
+  /**
+   * 根据部门id获取权限列表
+   * @param deptId 部门id
+   * @returns 权限列表
+   */
+  async getDeptCodes(deptId: string) {
+    const dept = await this.deptModel.findById(deptId).lean();
+    if (!dept) return [];
+    // 处理部门有的权限
+    const resource = get(dept, 'resource', []);
+    // const result = resource.map(i => {
+    //   const arr = i.split('.');
+    //   return last(arr);
+    // });
+    return resource;
+  }
+  /**
+   * 根据角色数组获取角色权限
+   * @param roleCode 角色数据
+   * @returns 权限列表
+   */
+  async getRoleCodes(roleCode: Array<string>) {
+    const roleCodes = [];
+    for (const rc of roleCode) {
+      roleCodes.push(lowerFirst(rc));
+      roleCodes.push(upperFirst(rc));
     }
     const role = await this.model.findOne({ code: roleCode, is_use: '0' }).lean();
-    if (!role) throw new ServiceError(this.i18n.translateError(FrameErrorEnum.ROLE_IS_DISABLED), FrameworkErrorEnum.SERVICE_FAULT);
+    if (!role) return [];
     const roleMenu = get(role, 'menu', []);
-    const menu = roleMenu.map(i => {
-      const arr = i.split('.');
-      return last(arr);
-    });
-    if (needCode) return roleMenu;
-    const menuList = await this.menusModel.find({ route_name: menu }).lean();
-    let treeMenu = menuList.filter(f => !f.parent_id);
-    treeMenu = this.menusService.treeMenu(menuList, treeMenu);
-    return { menus: treeMenu, role_code: roleMenu };
+    // const result = roleMenu.map(i => {
+    //   const arr = i.split('.');
+    //   return last(arr);
+    // });
+    return roleMenu;
   }
 
   /**