refactor: 系统权限模块重构,迁移至PostgreSQL并对齐新设计

- 切换数据库为PostgreSQL,更新依赖与配置
- 重构权限体系,使用sys_user/sys_role/sys_menu等新实体替代旧模型
- 移除旧的用户角色/权限/系统设置相关代码与实体
- 新增字典、菜单管理模块与基础CRUD接口
- 优化鉴权逻辑,基于菜单权限标识进行接口校验
- 前端同步更新API、路由与权限控制逻辑
- 删除冗余的v-permission指令与相关代码
This commit is contained in:
andyesfly committed 2026-08-19 14:11:34 +08:00
1 parent 98c22f6afb
commit 0a8103f33d
67 files changed
+3263 -1924

No files matched your search

+65 -60
View File
@@ -1,24 +1,24 @@
import { Provide, Inject } from "@midwayjs/core";
import { InjectRepository } from "@midwayjs/sequelize";
import Role from "../entity/role.entity";
import UserRole from "../entity/userRole.entity";
import RolePermission from "../entity/rolePermission.entity";
import Permission from "../entity/permission.entity";
import SysRole from "../entity/sysRole.entity";
import SysUserRole from "../entity/sysUserRole.entity";
import SysRoleMenu from "../entity/sysRoleMenu.entity";
import SysMenu from "../entity/sysMenu.entity";
import { Op } from "sequelize";
@Provide()
export class RoleService {
@InjectRepository(Role)
roleModel!: typeof Role;
@InjectRepository(SysRole)
roleModel!: typeof SysRole;
@InjectRepository(UserRole)
userRoleModel!: typeof UserRole;
@InjectRepository(SysUserRole)
userRoleModel!: typeof SysUserRole;
@InjectRepository(RolePermission)
rolePermissionModel!: typeof RolePermission;
@InjectRepository(SysRoleMenu)
roleMenuModel!: typeof SysRoleMenu;
@InjectRepository(Permission)
permissionModel!: typeof Permission;
@InjectRepository(SysMenu)
menuModel!: typeof SysMenu;
async list(query: {
page?: number;
@@ -32,20 +32,17 @@ export class RoleService {
const whereClause: any = {};
if (query.keyword) {
whereClause[Op.or] = [
{ name: { [Op.like]: `%${query.keyword}%` } },
{ code: { [Op.like]: `%${query.keyword}%` } },
{ roleCode: { [Op.like]: `%${query.keyword}%` } },
{ roleName: { [Op.like]: `%${query.keyword}%` } },
];
}
const { count, rows } = await this.roleModel.findAndCountAll({
where: whereClause,
attributes: ["id", "roleCode", "roleName", "description", "sortOrder"],
offset,
limit: pageSize,
order: [["sort_order", "ASC"], ["created_at", "DESC"]],
include: [{
model: this.rolePermissionModel,
include: [this.permissionModel],
}],
});
for (const role of rows) {
@@ -80,12 +77,7 @@ export class RoleService {
}
async detail(id: string): Promise<any> {
const role = await this.roleModel.findByPk(Number(id), {
include: [{
model: this.rolePermissionModel,
include: [this.permissionModel],
}],
});
const role = await this.roleModel.findByPk(Number(id));
if (!role) {
return {
@@ -108,10 +100,10 @@ export class RoleService {
}
async create(data: any): Promise<any> {
const { name, code, description, status = 1, sortOrder = 0 } = data;
const { roleCode, roleName, description, sortOrder = 0 } = data;
const existingRole = await this.roleModel.findOne({
where: { code },
where: { roleCode },
});
if (existingRole) {
@@ -123,10 +115,9 @@ export class RoleService {
}
const role = await this.roleModel.create({
name,
code,
roleCode,
roleName,
description,
status,
sort_order: sortOrder,
});
@@ -148,9 +139,9 @@ export class RoleService {
};
}
if (data.code && data.code !== role.code) {
if (data.roleCode && data.roleCode !== role.roleCode) {
const existingRole = await this.roleModel.findOne({
where: { code: data.code },
where: { roleCode: data.roleCode },
});
if (existingRole) {
@@ -163,9 +154,9 @@ export class RoleService {
}
const updateData: any = {};
if (data.name !== undefined) updateData.name = data.name;
if (data.roleCode !== undefined) updateData.roleCode = data.roleCode;
if (data.roleName !== undefined) updateData.roleName = data.roleName;
if (data.description !== undefined) updateData.description = data.description;
if (data.status !== undefined) updateData.status = data.status;
if (data.sortOrder !== undefined) updateData.sort_order = data.sortOrder;
await role.update(updateData);
@@ -200,7 +191,7 @@ export class RoleService {
};
}
await this.rolePermissionModel.destroy({
await this.roleMenuModel.destroy({
where: { roleId: Number(id) },
});
@@ -213,7 +204,7 @@ export class RoleService {
};
}
async getPermissions(roleId: number): Promise<any> {
async getMenus(roleId: number): Promise<any> {
const role = await this.roleModel.findByPk(roleId);
if (!role) {
@@ -224,28 +215,32 @@ export class RoleService {
};
}
const rolePermissions = await this.rolePermissionModel.findAll({
const roleMenus = await this.roleMenuModel.findAll({
where: { roleId },
});
const assignedPermissionIds = rolePermissions.map(rp => rp.permissionId);
const assignedMenuIds = roleMenus.map(rm => rm.menuId);
const allPermissions = await this.permissionModel.findAll({
const menus = await this.menuModel.findAll({
where: { menuType: { [Op.in]: [1, 2] } },
order: [["sort_order", "ASC"], ["id", "ASC"]],
});
const permissionTree = this.buildPermissionTree(
allPermissions.map(p => p.toJSON()),
assignedPermissionIds
const menuTree = this.buildMenuTree(
menus.map(m => m.toJSON()),
assignedMenuIds
);
return {
code: 200,
message: "获取角色权限成功",
data: permissionTree,
message: "获取角色菜单成功",
data: {
menuTree,
menuIds: assignedMenuIds,
},
};
}
async updatePermissions(roleId: number, permissionIds: number[]): Promise<any> {
async updateMenus(roleId: number, menuIds: number[]): Promise<any> {
const role = await this.roleModel.findByPk(roleId);
if (!role) {
@@ -256,47 +251,57 @@ export class RoleService {
};
}
await this.rolePermissionModel.destroy({
await this.roleMenuModel.destroy({
where: { roleId },
});
if (permissionIds && permissionIds.length > 0) {
const rolePermissions = permissionIds.map(permissionId => ({
if (menuIds && menuIds.length > 0) {
const roleMenus = menuIds.map(menuId => ({
roleId,
permissionId,
menuId,
}));
await this.rolePermissionModel.bulkCreate(rolePermissions);
await this.roleMenuModel.bulkCreate(roleMenus);
}
return {
code: 200,
message: "权限更新成功",
message: "菜单更新成功",
data: null,
};
}
private buildPermissionTree(permissions: any[], checkedIds: number[]): any[] {
const map = new Map<number, any>();
private buildMenuTree(menus: any[], checkedIds: number[]): any[] {
const nodeMap = new Map<number, any>();
const menuIdSet = new Set(menus.map(m => m.id));
const tree: any[] = [];
for (const perm of permissions) {
map.set(perm.id, {
...perm,
for (const menu of menus) {
nodeMap.set(menu.id, {
...menu,
children: [],
checked: checkedIds.includes(perm.id),
checked: checkedIds.includes(menu.id),
});
}
for (const perm of permissions) {
const node = map.get(perm.id)!;
if (perm.parent_id && map.has(perm.parent_id)) {
map.get(perm.parent_id)!.children.push(node);
for (const menu of menus) {
const node = nodeMap.get(menu.id)!;
const parent = menu.parentId ? nodeMap.get(menu.parentId) : undefined;
// 仅当父节点为一级节点时挂为其子节点,保证输出两级树;
// 父节点不在列表或父节点本身是二级节点时,提升为一级节点
if (parent && !menuIdSet.has(parent.parentId)) {
parent.children.push(node);
} else {
tree.push(node);
}
}
// 一级节点已在查询时按 sort_order 排序,此处对子节点排序
for (const node of tree) {
node.children.sort((a: any, b: any) => a.sortOrder - b.sortOrder);
}
return tree;
}
}