add
This commit is contained in:
parent
2ed15c9b6b
commit
eafd308db2
|
@ -1,21 +1,29 @@
|
|||
import { Injectable } from '@nestjs/common';
|
||||
import { TrpcService } from '@server/trpc/trpc.service';
|
||||
import { DepartmentService } from './department.service'; // assuming it's in the same directory
|
||||
import { DepartmentMethodSchema, Prisma, UpdateOrderSchema } from '@nice/common';
|
||||
import {
|
||||
DepartmentMethodSchema,
|
||||
Prisma,
|
||||
UpdateOrderSchema,
|
||||
} from '@nice/common';
|
||||
import { z, ZodType } from 'zod';
|
||||
import { DepartmentRowService } from './department.row.service';
|
||||
|
||||
const DepartmentCreateArgsSchema: ZodType<Prisma.DepartmentCreateArgs> = z.any()
|
||||
const DepartmentUpdateArgsSchema: ZodType<Prisma.DepartmentUpdateArgs> = z.any()
|
||||
const DepartmentFindFirstArgsSchema: ZodType<Prisma.DepartmentFindFirstArgs> = z.any()
|
||||
const DepartmentFindManyArgsSchema: ZodType<Prisma.DepartmentFindManyArgs> = z.any()
|
||||
const DepartmentCreateArgsSchema: ZodType<Prisma.DepartmentCreateArgs> =
|
||||
z.any();
|
||||
const DepartmentUpdateArgsSchema: ZodType<Prisma.DepartmentUpdateArgs> =
|
||||
z.any();
|
||||
const DepartmentFindFirstArgsSchema: ZodType<Prisma.DepartmentFindFirstArgs> =
|
||||
z.any();
|
||||
const DepartmentFindManyArgsSchema: ZodType<Prisma.DepartmentFindManyArgs> =
|
||||
z.any();
|
||||
@Injectable()
|
||||
export class DepartmentRouter {
|
||||
constructor(
|
||||
private readonly trpc: TrpcService,
|
||||
private readonly departmentService: DepartmentService, // 注入 DepartmentService
|
||||
private readonly departmentRowService: DepartmentRowService
|
||||
) { }
|
||||
private readonly departmentRowService: DepartmentRowService,
|
||||
) {}
|
||||
router = this.trpc.router({
|
||||
// 创建部门
|
||||
create: this.trpc.protectProcedure
|
||||
|
@ -36,9 +44,11 @@ export class DepartmentRouter {
|
|||
return this.departmentService.softDeleteByIds(input.ids);
|
||||
}),
|
||||
// 更新部门顺序
|
||||
updateOrder: this.trpc.protectProcedure.input(UpdateOrderSchema).mutation(async ({ input }) => {
|
||||
return this.departmentService.updateOrder(input)
|
||||
}),
|
||||
updateOrder: this.trpc.protectProcedure
|
||||
.input(UpdateOrderSchema)
|
||||
.mutation(async ({ input }) => {
|
||||
return this.departmentService.updateOrder(input);
|
||||
}),
|
||||
// 查询多个部门
|
||||
findMany: this.trpc.procedure
|
||||
.input(DepartmentFindManyArgsSchema) // 假设 StaffMethodSchema.findMany 是根据关键字查找员工的 Zod schema
|
||||
|
@ -53,13 +63,15 @@ export class DepartmentRouter {
|
|||
}),
|
||||
// 获取子部门的简单树结构
|
||||
getChildSimpleTree: this.trpc.procedure
|
||||
.input(DepartmentMethodSchema.getSimpleTree).query(async ({ input }) => {
|
||||
return await this.departmentService.getChildSimpleTree(input)
|
||||
.input(DepartmentMethodSchema.getSimpleTree)
|
||||
.query(async ({ input }) => {
|
||||
return await this.departmentService.getChildSimpleTree(input);
|
||||
}),
|
||||
// 获取父部门的简单树结构
|
||||
getParentSimpleTree: this.trpc.procedure
|
||||
.input(DepartmentMethodSchema.getSimpleTree).query(async ({ input }) => {
|
||||
return await this.departmentService.getParentSimpleTree(input)
|
||||
.input(DepartmentMethodSchema.getSimpleTree)
|
||||
.query(async ({ input }) => {
|
||||
return await this.departmentService.getParentSimpleTree(input);
|
||||
}),
|
||||
// 获取部门行数据
|
||||
getRows: this.trpc.protectProcedure
|
||||
|
|
|
@ -61,6 +61,18 @@ export class StaffRouter {
|
|||
.query(async ({ input }) => {
|
||||
return await this.staffService.findMany(input);
|
||||
}),
|
||||
findManyWithPagination: this.trpc.procedure
|
||||
.input(
|
||||
z.object({
|
||||
page: z.number().optional(),
|
||||
pageSize: z.number().optional(),
|
||||
where: StaffWhereInputSchema.optional(),
|
||||
select: StaffSelectSchema.optional(),
|
||||
}),
|
||||
) // Assuming StaffMethodSchema.findMany is the Zod schema for finding staffs by keyword
|
||||
.query(async ({ input }) => {
|
||||
return await this.staffService.findManyWithPagination(input);
|
||||
}),
|
||||
getRows: this.trpc.protectProcedure
|
||||
.input(StaffMethodSchema.getRows)
|
||||
.query(async ({ input, ctx }) => {
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
import { Injectable } from '@nestjs/common';
|
||||
import {
|
||||
db,
|
||||
ObjectType,
|
||||
StaffMethodSchema,
|
||||
UserProfile,
|
||||
RolePerms,
|
||||
ResPerm,
|
||||
Staff,
|
||||
RowModelRequest,
|
||||
db,
|
||||
ObjectType,
|
||||
StaffMethodSchema,
|
||||
UserProfile,
|
||||
RolePerms,
|
||||
ResPerm,
|
||||
Staff,
|
||||
RowModelRequest,
|
||||
} from '@nice/common';
|
||||
import { DepartmentService } from '../department/department.service';
|
||||
import { RowCacheService } from '../base/row-cache.service';
|
||||
|
@ -15,121 +15,116 @@ import { z } from 'zod';
|
|||
import { isFieldCondition } from '../base/sql-builder';
|
||||
@Injectable()
|
||||
export class StaffRowService extends RowCacheService {
|
||||
constructor(
|
||||
private readonly departmentService: DepartmentService,
|
||||
) {
|
||||
super(ObjectType.STAFF, false);
|
||||
constructor(private readonly departmentService: DepartmentService) {
|
||||
super(ObjectType.STAFF, false);
|
||||
}
|
||||
createUnGroupingRowSelect(request?: RowModelRequest): string[] {
|
||||
const result = super
|
||||
.createUnGroupingRowSelect(request)
|
||||
.concat([
|
||||
`${this.tableName}.id AS id`,
|
||||
`${this.tableName}.username AS username`,
|
||||
`${this.tableName}.showname AS showname`,
|
||||
`${this.tableName}.avatar AS avatar`,
|
||||
`${this.tableName}.officer_id AS officer_id`,
|
||||
`${this.tableName}.phone_number AS phone_number`,
|
||||
`${this.tableName}.order AS order`,
|
||||
`${this.tableName}.enabled AS enabled`,
|
||||
'dept.name AS dept_name',
|
||||
'domain.name AS domain_name',
|
||||
]);
|
||||
return result;
|
||||
}
|
||||
createJoinSql(request?: RowModelRequest): string[] {
|
||||
return [
|
||||
`LEFT JOIN department dept ON ${this.tableName}.dept_id = dept.id`,
|
||||
`LEFT JOIN department domain ON ${this.tableName}.domain_id = domain.id`,
|
||||
];
|
||||
}
|
||||
protected createGetRowsFilters(
|
||||
request: z.infer<typeof StaffMethodSchema.getRows>,
|
||||
staff: UserProfile,
|
||||
) {
|
||||
const condition = super.createGetRowsFilters(request);
|
||||
const { domainId, includeDeleted = false } = request;
|
||||
if (isFieldCondition(condition)) {
|
||||
return;
|
||||
}
|
||||
createUnGroupingRowSelect(request?: RowModelRequest): string[] {
|
||||
const result = super.createUnGroupingRowSelect(request).concat([
|
||||
`${this.tableName}.id AS id`,
|
||||
`${this.tableName}.username AS username`,
|
||||
`${this.tableName}.showname AS showname`,
|
||||
`${this.tableName}.avatar AS avatar`,
|
||||
`${this.tableName}.officer_id AS officer_id`,
|
||||
`${this.tableName}.phone_number AS phone_number`,
|
||||
`${this.tableName}.order AS order`,
|
||||
`${this.tableName}.enabled AS enabled`,
|
||||
'dept.name AS dept_name',
|
||||
'domain.name AS domain_name',
|
||||
]);
|
||||
return result
|
||||
if (domainId) {
|
||||
condition.AND.push({
|
||||
field: `${this.tableName}.domain_id`,
|
||||
value: domainId,
|
||||
op: 'equals',
|
||||
});
|
||||
} else {
|
||||
condition.AND.push({
|
||||
field: `${this.tableName}.domain_id`,
|
||||
op: 'blank',
|
||||
});
|
||||
}
|
||||
createJoinSql(request?: RowModelRequest): string[] {
|
||||
return [
|
||||
`LEFT JOIN department dept ON ${this.tableName}.dept_id = dept.id`,
|
||||
`LEFT JOIN department domain ON ${this.tableName}.domain_id = domain.id`,
|
||||
];
|
||||
if (!includeDeleted) {
|
||||
condition.AND.push({
|
||||
field: `${this.tableName}.deleted_at`,
|
||||
type: 'date',
|
||||
op: 'blank',
|
||||
});
|
||||
}
|
||||
protected createGetRowsFilters(
|
||||
request: z.infer<typeof StaffMethodSchema.getRows>,
|
||||
staff: UserProfile,
|
||||
) {
|
||||
const condition = super.createGetRowsFilters(request);
|
||||
const { domainId, includeDeleted = false } = request;
|
||||
if (isFieldCondition(condition)) {
|
||||
return;
|
||||
}
|
||||
if (domainId) {
|
||||
condition.AND.push({
|
||||
field: `${this.tableName}.domain_id`,
|
||||
value: domainId,
|
||||
op: 'equals',
|
||||
});
|
||||
} else {
|
||||
condition.AND.push({
|
||||
field: `${this.tableName}.domain_id`,
|
||||
op: 'blank',
|
||||
});
|
||||
}
|
||||
if (!includeDeleted) {
|
||||
condition.AND.push({
|
||||
field: `${this.tableName}.deleted_at`,
|
||||
type: 'date',
|
||||
op: 'blank',
|
||||
});
|
||||
}
|
||||
condition.OR = [];
|
||||
if (!staff.permissions.includes(RolePerms.MANAGE_ANY_STAFF)) {
|
||||
if (staff.permissions.includes(RolePerms.MANAGE_DOM_STAFF)) {
|
||||
condition.OR.push({
|
||||
field: 'dept.id',
|
||||
value: staff.domainId,
|
||||
op: 'equals',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return condition;
|
||||
}
|
||||
|
||||
async getPermissionContext(id: string, staff: UserProfile) {
|
||||
const data = await db.staff.findUnique({
|
||||
where: { id },
|
||||
select: {
|
||||
deptId: true,
|
||||
domainId: true,
|
||||
},
|
||||
condition.OR = [];
|
||||
if (!staff.permissions.includes(RolePerms.MANAGE_ANY_STAFF)) {
|
||||
if (staff.permissions.includes(RolePerms.MANAGE_DOM_STAFF)) {
|
||||
condition.OR.push({
|
||||
field: 'dept.id',
|
||||
value: staff.domainId,
|
||||
op: 'equals',
|
||||
});
|
||||
const deptId = data?.deptId;
|
||||
const isFromSameDept = staff.deptIds?.includes(deptId);
|
||||
const domainChildDeptIds = await this.departmentService.getDescendantIds(
|
||||
staff.domainId, true
|
||||
);
|
||||
const belongsToDomain = domainChildDeptIds.includes(
|
||||
deptId,
|
||||
);
|
||||
return { isFromSameDept, belongsToDomain };
|
||||
}
|
||||
protected async setResPermissions(
|
||||
data: Staff,
|
||||
staff: UserProfile,
|
||||
) {
|
||||
const permissions: ResPerm = {};
|
||||
const { isFromSameDept, belongsToDomain } = await this.getPermissionContext(
|
||||
data.id,
|
||||
staff,
|
||||
);
|
||||
const setManagePermissions = (permissions: ResPerm) => {
|
||||
Object.assign(permissions, {
|
||||
read: true,
|
||||
delete: true,
|
||||
edit: true,
|
||||
});
|
||||
};
|
||||
staff.permissions.forEach((permission) => {
|
||||
switch (permission) {
|
||||
case RolePerms.MANAGE_ANY_STAFF:
|
||||
setManagePermissions(permissions);
|
||||
break;
|
||||
case RolePerms.MANAGE_DOM_STAFF:
|
||||
if (belongsToDomain) {
|
||||
setManagePermissions(permissions);
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
return { ...data, perm: permissions };
|
||||
}
|
||||
}
|
||||
|
||||
return condition;
|
||||
}
|
||||
|
||||
async getPermissionContext(id: string, staff: UserProfile) {
|
||||
const data = await db.staff.findUnique({
|
||||
where: { id },
|
||||
select: {
|
||||
deptId: true,
|
||||
domainId: true,
|
||||
},
|
||||
});
|
||||
const deptId = data?.deptId;
|
||||
const isFromSameDept = staff.deptIds?.includes(deptId);
|
||||
const domainChildDeptIds = await this.departmentService.getDescendantIds(
|
||||
staff.domainId,
|
||||
true,
|
||||
);
|
||||
const belongsToDomain = domainChildDeptIds.includes(deptId);
|
||||
return { isFromSameDept, belongsToDomain };
|
||||
}
|
||||
protected async setResPermissions(data: Staff, staff: UserProfile) {
|
||||
const permissions: ResPerm = {};
|
||||
const { isFromSameDept, belongsToDomain } = await this.getPermissionContext(
|
||||
data.id,
|
||||
staff,
|
||||
);
|
||||
const setManagePermissions = (permissions: ResPerm) => {
|
||||
Object.assign(permissions, {
|
||||
read: true,
|
||||
delete: true,
|
||||
edit: true,
|
||||
});
|
||||
};
|
||||
staff.permissions.forEach((permission) => {
|
||||
switch (permission) {
|
||||
case RolePerms.MANAGE_ANY_STAFF:
|
||||
setManagePermissions(permissions);
|
||||
break;
|
||||
case RolePerms.MANAGE_DOM_STAFF:
|
||||
if (belongsToDomain) {
|
||||
setManagePermissions(permissions);
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
return { ...data, perm: permissions };
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,6 @@ import EventBus, { CrudOperation } from '@server/utils/event-bus';
|
|||
|
||||
@Injectable()
|
||||
export class StaffService extends BaseService<Prisma.StaffDelegate> {
|
||||
|
||||
constructor(private readonly departmentService: DepartmentService) {
|
||||
super(db, ObjectType.STAFF, true);
|
||||
}
|
||||
|
@ -25,7 +24,10 @@ export class StaffService extends BaseService<Prisma.StaffDelegate> {
|
|||
*/
|
||||
async findByDept(data: z.infer<typeof StaffMethodSchema.findByDept>) {
|
||||
const { deptId, domainId } = data;
|
||||
const childDepts = await this.departmentService.getDescendantIds(deptId, true);
|
||||
const childDepts = await this.departmentService.getDescendantIds(
|
||||
deptId,
|
||||
true,
|
||||
);
|
||||
const result = await db.staff.findMany({
|
||||
where: {
|
||||
deptId: { in: childDepts },
|
||||
|
@ -50,7 +52,9 @@ export class StaffService extends BaseService<Prisma.StaffDelegate> {
|
|||
await this.validateUniqueFields(data, where.id);
|
||||
const updateData = {
|
||||
...data,
|
||||
...(data.password && { password: await argon2.hash(data.password as string) })
|
||||
...(data.password && {
|
||||
password: await argon2.hash(data.password as string),
|
||||
}),
|
||||
};
|
||||
const result = await super.update({ ...args, data: updateData });
|
||||
this.emitDataChangedEvent(result, CrudOperation.UPDATED);
|
||||
|
@ -58,17 +62,26 @@ export class StaffService extends BaseService<Prisma.StaffDelegate> {
|
|||
}
|
||||
private async validateUniqueFields(data: any, excludeId?: string) {
|
||||
const uniqueFields = [
|
||||
{ field: 'officerId', errorMsg: (val: string) => `证件号为${val}的用户已存在` },
|
||||
{ field: 'phoneNumber', errorMsg: (val: string) => `手机号为${val}的用户已存在` },
|
||||
{ field: 'username', errorMsg: (val: string) => `帐号为${val}的用户已存在` }
|
||||
{
|
||||
field: 'officerId',
|
||||
errorMsg: (val: string) => `证件号为${val}的用户已存在`,
|
||||
},
|
||||
{
|
||||
field: 'phoneNumber',
|
||||
errorMsg: (val: string) => `手机号为${val}的用户已存在`,
|
||||
},
|
||||
{
|
||||
field: 'username',
|
||||
errorMsg: (val: string) => `帐号为${val}的用户已存在`,
|
||||
},
|
||||
];
|
||||
for (const { field, errorMsg } of uniqueFields) {
|
||||
if (data[field]) {
|
||||
const count = await db.staff.count({
|
||||
where: {
|
||||
[field]: data[field],
|
||||
...(excludeId && { id: { not: excludeId } })
|
||||
}
|
||||
...(excludeId && { id: { not: excludeId } }),
|
||||
},
|
||||
});
|
||||
if (count > 0) {
|
||||
throw new Error(errorMsg(data[field]));
|
||||
|
@ -77,9 +90,8 @@ export class StaffService extends BaseService<Prisma.StaffDelegate> {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
private emitDataChangedEvent(data: any, operation: CrudOperation) {
|
||||
EventBus.emit("dataChanged", {
|
||||
EventBus.emit('dataChanged', {
|
||||
type: this.objectType,
|
||||
operation,
|
||||
data,
|
||||
|
@ -87,12 +99,12 @@ export class StaffService extends BaseService<Prisma.StaffDelegate> {
|
|||
}
|
||||
|
||||
/**
|
||||
* 更新员工DomainId
|
||||
* @param data 包含domainId对象
|
||||
* @returns 更新后的员工记录
|
||||
*/
|
||||
* 更新员工DomainId
|
||||
* @param data 包含domainId对象
|
||||
* @returns 更新后的员工记录
|
||||
*/
|
||||
async updateUserDomain(data: { domainId?: string }, staff?: UserProfile) {
|
||||
let { domainId } = data;
|
||||
const { domainId } = data;
|
||||
if (staff.domainId !== domainId) {
|
||||
const result = await this.update({
|
||||
where: { id: staff.id },
|
||||
|
@ -107,7 +119,6 @@ export class StaffService extends BaseService<Prisma.StaffDelegate> {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// /**
|
||||
// * 根据关键词或ID集合查找员工
|
||||
// * @param data 包含关键词、域ID和ID集合的对象
|
||||
|
@ -176,5 +187,4 @@ export class StaffService extends BaseService<Prisma.StaffDelegate> {
|
|||
|
||||
// return combinedResults;
|
||||
// }
|
||||
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ export default function PostList({
|
|||
renderItem,
|
||||
}: PostListProps) {
|
||||
const [currentPage, setCurrentPage] = useState<number>(params?.page || 1);
|
||||
|
||||
const { data, isLoading }: PostPagnationProps =
|
||||
api.post.findManyWithPagination.useQuery({
|
||||
select: courseDetailSelect,
|
||||
|
|
Loading…
Reference in New Issue