feat: 支持企业级管理模式,项目管理,细分权限

This commit is contained in:
xiaojunnuo
2026-02-10 01:57:11 +08:00
parent d1a8dd7817
commit 37340838b6
35 changed files with 559 additions and 135 deletions
@@ -4,6 +4,7 @@ CREATE TABLE "cd_project"
"id" integer PRIMARY KEY AUTOINCREMENT NOT NULL,
"user_id" integer NOT NULL,
"name" varchar(512) NOT NULL,
"admin_id" integer NOT NULL,
"disabled" boolean NOT NULL DEFAULT (false),
"create_time" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP),
"update_time" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP)
@@ -11,6 +12,7 @@ CREATE TABLE "cd_project"
CREATE INDEX "index_project_user_id" ON "cd_project" ("user_id");
CREATE INDEX "index_project_admin_id" ON "cd_project" ("admin_id");
INSERT INTO cd_project (id, user_id, "name", "disabled") VALUES (1, 1, 'default', false);
@@ -38,7 +38,11 @@ export class SysProjectController extends CrudController<ProjectEntity> {
};
merge(bean, def);
bean.userId = this.getUserId();
return super.add(bean);
return super.add({
...bean,
userId:0,
adminId: bean.userId,
});
}
@Post("/update", { summary: "sys:settings:edit" })
@@ -3,6 +3,7 @@ import { ALL, Body, Controller, Inject, Post, Provide, Query } from "@midwayjs/c
import { ProjectMemberEntity } from "../../../modules/sys/enterprise/entity/project-member.js";
import { ProjectMemberService } from "../../../modules/sys/enterprise/service/project-member-service.js";
import { merge } from "lodash-es";
import { ProjectService } from "../../../modules/sys/enterprise/service/project-service.js";
/**
*/
@@ -15,6 +16,9 @@ export class SysProjectMemberController extends CrudController<ProjectMemberEnti
@Inject()
sysSettingsService: SysSettingsService;
@Inject()
projectService: ProjectService;
getService<T>() {
return this.service;
}
@@ -37,29 +41,71 @@ export class SysProjectMemberController extends CrudController<ProjectMemberEnti
disabled: false,
};
merge(bean, def);
bean.userId = this.getUserId();
await this.projectService.checkAdminPermission({
userId: this.getUserId(),
projectId: bean.projectId,
});
return super.add(bean);
}
@Post("/update", { summary: "sys:settings:edit" })
async update(@Body(ALL) bean: any) {
bean.userId = this.getUserId();
return super.update(bean);
if (!bean.id) {
throw new Error("id is required");
}
const projectId = await this.service.getProjectId(bean.id)
await this.projectService.checkAdminPermission({
userId: this.getUserId(),
projectId: projectId,
});
return super.update({
id: bean.id,
permission: bean.permission,
});
}
@Post("/info", { summary: "sys:settings:view" })
async info(@Query("id") id: number) {
if (!id) {
throw new Error("id is required");
}
const projectId = await this.service.getProjectId(id)
await this.projectService.checkReadPermission({
userId: this.getUserId(),
projectId:projectId,
});
return super.info(id);
}
@Post("/delete", { summary: "sys:settings:edit" })
async delete(@Query("id") id: number) {
if (!id) {
throw new Error("id is required");
}
const projectId = await this.service.getProjectId(id)
await this.projectService.checkAdminPermission({
userId: this.getUserId(),
projectId:projectId,
});
return super.delete(id);
}
@Post("/deleteByIds", { summary: "sys:settings:edit" })
async deleteByIds(@Body("ids") ids: number[]) {
const res = await this.service.delete(ids);
return this.ok(res);
for (const id of ids) {
if (!id) {
throw new Error("id is required");
}
const projectId = await this.service.getProjectId(id)
await this.projectService.checkAdminPermission({
userId: this.getUserId(),
projectId:projectId,
});
await this.service.delete(id as any);
}
return this.ok({});
}
}
@@ -20,7 +20,7 @@ export class UserProjectController extends BaseController {
@Post('/list', { summary: Constants.per.authOnly })
async list(@Body(ALL) body: any) {
const userId= this.getUserId();
const res = await this.service.getByUserId(userId);
const res = await this.service.getUserProjects(userId);
return this.ok(res);
}
@@ -10,6 +10,9 @@ export class ProjectEntity {
@Column({ name: 'user_id', comment: 'UserId' })
userId: number;
@Column({ name: 'admin_id', comment: '管理员Id' })
adminId: number;
@Column({ name: 'name', comment: '项目名称' })
name: string;
@@ -46,4 +46,26 @@ export class ProjectMemberService extends BaseService<ProjectMemberEntity> {
});
}
async getMember(projectId: number,userId: number) {
return await this.repository.findOne({
where: {
userId,
projectId,
},
});
}
async getProjectId(id: number) {
const member = await this.repository.findOne({
select: ['projectId'],
where: {
id: id,
},
});
if (!member) {
throw new Error('项目成员记录不存在');
}
return member.projectId;
}
}
@@ -1,7 +1,7 @@
import {Inject, Provide, Scope, ScopeEnum} from '@midwayjs/core';
import {BaseService, SysSettingsService} from '@certd/lib-server';
import {InjectEntityModel} from '@midwayjs/typeorm';
import {In, Repository} from 'typeorm';
import { BaseService, SysSettingsService } from '@certd/lib-server';
import { Inject, Provide, Scope, ScopeEnum } from '@midwayjs/core';
import { InjectEntityModel } from '@midwayjs/typeorm';
import { Repository } from 'typeorm';
import { ProjectEntity } from '../entity/project.js';
import { ProjectMemberService } from './project-member-service.js';
@@ -30,45 +30,34 @@ export class ProjectService extends BaseService<ProjectEntity> {
const exist = await this.repository.findOne({
where: {
name,
userId:0,
userId: 0,
},
});
if (exist) {
throw new Error('项目名称已存在');
}
bean.userId = 0
bean.disabled = false
return await super.add(bean)
}
async setDisabled(id: number, disabled: boolean) {
const project = await this.repository.findOne({
where: {
id,
userId:0,
},
});
if (!project) {
throw new Error('项目不存在');
}
await this.repository.update({
id,
userId:0,
}, {
disabled,
});
project.disabled = disabled;
await this.repository.save(project);
}
async getByUserId(userId: number) {
async getUserProjects(userId: number) {
const memberList = await this.projectMemberService.getByUserId(userId);
const projectIds = memberList.map(item => item.projectId);
const projectList = await this.repository.find({
where: {
id: In(projectIds),
},
});
const projectList = await this.repository.createQueryBuilder('project')
.where(' project.disabled = false')
.where(' project.userId = :userId', { userId:0 })
.where(' project.id IN (:...projectIds) or project.adminId = :userId', { projectIds, userId })
.getMany();
const memberPermissionMap = memberList.reduce((prev, cur) => {
prev[cur.projectId] = cur.permission;
@@ -76,9 +65,81 @@ export class ProjectService extends BaseService<ProjectEntity> {
}, {} as Record<number, string>);
projectList.forEach(item => {
item.permission = memberPermissionMap[item.id] || 'read';
if (item.adminId === userId) {
item.permission = 'admin';
}else{
item.permission = memberPermissionMap[item.id] || 'read';
}
})
return projectList
}
async checkAdminPermission({userId, projectId}: {userId: number, projectId: number}) {
return await this.checkPermission({
userId,
projectId,
permission: 'admin',
})
}
async checkWritePermission({userId, projectId}: {userId: number, projectId: number}) {
return await this.checkPermission({
userId,
projectId,
permission: 'write',
})
}
async checkReadPermission({userId, projectId}: {userId: number, projectId: number}) {
return await this.checkPermission({
userId,
projectId,
permission: 'read',
})
}
async checkPermission({userId, projectId, permission}: {userId: number, projectId: number, permission: string}) {
if (permission !== 'admin' && permission !== 'write' && permission !== 'read') {
throw new Error('权限类型错误');
}
if (!userId ){
throw new Error('用户ID不能为空');
}
if (!projectId ){
throw new Error('项目ID不能为空');
}
const project = await this.findOne({
select: ['id', 'userId', 'adminId', 'disabled'],
where: {
id: projectId,
},
});
if (!project) {
throw new Error('项目不存在');
}
if (project.adminId === userId) {
//创建者拥有管理权限
return true
}
if (project.disabled) {
throw new Error('项目已禁用');
}
const member = await this.projectMemberService.getMember(projectId,userId);
if (!member) {
throw new Error('项目成员不存在');
}
if (permission === 'read') {
return true
}
if (permission === 'write') {
if (member.permission === 'admin' || member.permission === 'write') {
return true
}else{
throw new Error('权限不足');
}
}
if (member.permission !== permission) {
throw new Error('权限不足');
}
return true
}
}