diff --git a/src/tasks/task.service.ts b/src/tasks/task.service.ts index d5de0ec..010a12e 100644 --- a/src/tasks/task.service.ts +++ b/src/tasks/task.service.ts @@ -84,7 +84,7 @@ export class TaskService { const page = query.page ?? 1; const pageSize = query.pageSize ?? 20; const skip = (page - 1) * pageSize; - const where = this.buildTaskRecordWhere(query, hospitalId); + const where = this.buildTaskRecordWhere(actor, query, hospitalId); const [total, items] = await Promise.all([ this.prisma.taskItem.count({ where }), @@ -608,16 +608,23 @@ export class TaskService { * 构造调压记录查询条件。 */ private buildTaskRecordWhere( + actor: ActorContext, query: TaskRecordQueryDto, hospitalId?: number, ): Prisma.TaskItemWhereInput { const keyword = query.keyword?.trim(); + const patientScope = this.buildTaskPatientScope(actor); const where: Prisma.TaskItemWhereInput = { task: { hospitalId, status: query.status, }, + device: patientScope + ? { + patient: patientScope, + } + : undefined, }; if (!keyword) { @@ -676,6 +683,42 @@ export class TaskService { return where; } + /** + * 按角色构造任务列表中的患者可见范围,保持与患者列表一致。 + */ + private buildTaskPatientScope(actor: ActorContext): Prisma.PatientWhereInput | null { + switch (actor.role) { + case Role.SYSTEM_ADMIN: + case Role.HOSPITAL_ADMIN: + case Role.ENGINEER: + return null; + case Role.DOCTOR: + return { + doctorId: actor.id, + }; + case Role.LEADER: + if (!actor.groupId) { + throw new BadRequestException(MESSAGES.PATIENT.GROUP_REQUIRED); + } + return { + doctor: { + groupId: actor.groupId, + }, + }; + case Role.DIRECTOR: + if (!actor.departmentId) { + throw new BadRequestException(MESSAGES.PATIENT.DEPARTMENT_REQUIRED); + } + return { + doctor: { + departmentId: actor.departmentId, + }, + }; + default: + throw new ForbiddenException(MESSAGES.TASK.ACTOR_ROLE_FORBIDDEN); + } + } + /** * 调压目标挡位标准化。 */ diff --git a/test/e2e/specs/tasks.e2e-spec.ts b/test/e2e/specs/tasks.e2e-spec.ts index 08aba70..9f9c9ce 100644 --- a/test/e2e/specs/tasks.e2e-spec.ts +++ b/test/e2e/specs/tasks.e2e-spec.ts @@ -26,6 +26,7 @@ describe('BTasksController (e2e)', () => { let ctx: E2EContext; let samplePngBuffer: Buffer; let doctorBToken = ''; + let doctorA2Token = ''; beforeAll(async () => { ctx = await createE2EContext(); @@ -44,6 +45,11 @@ describe('BTasksController (e2e)', () => { Role.DOCTOR, ctx.fixtures.hospitalBId, ); + doctorA2Token = await loginByUser( + ctx.fixtures.users.doctorA2Id, + Role.DOCTOR, + ctx.fixtures.hospitalAId, + ); }); afterAll(async () => { @@ -293,21 +299,53 @@ describe('BTasksController (e2e)', () => { ); }); - it('成功:DOCTOR 仅可查看本院调压记录', async () => { + it('成功:DOCTOR 仅可查看本人患者调压记录', async () => { + const keywordPrefix = uniqueSeedValue('scope-doctor'); + const [selfDevice] = await createAdjustableDevices({ + actorToken: ctx.tokens[Role.DOCTOR], + doctorId: ctx.fixtures.users.doctorAId, + patientName: `${keywordPrefix}-self`, + }); + const [peerDevice] = await createAdjustableDevices({ + actorToken: doctorA2Token, + doctorId: ctx.fixtures.users.doctorA2Id, + patientName: `${keywordPrefix}-peer`, + }); + + await publishPendingTask( + selfDevice.id, + '1.5', + ctx.tokens[Role.SYSTEM_ADMIN], + ); + await publishPendingTask( + peerDevice.id, + '1.5', + ctx.tokens[Role.SYSTEM_ADMIN], + ); + const response = await request(ctx.app.getHttpServer()) .get('/b/tasks') .set('Authorization', `Bearer ${ctx.tokens[Role.DOCTOR]}`) - .query({ page: 1, pageSize: 20 }); + .query({ page: 1, pageSize: 50, keyword: keywordPrefix }); expectSuccessEnvelope(response, 200); expect(Array.isArray(response.body.data.list)).toBe(true); expect(response.body.data.total).toBeGreaterThan(0); expect( response.body.data.list.every( - (item: { hospital?: { id?: number } }) => - item.hospital?.id === ctx.fixtures.hospitalAId, + (item: { + hospital?: { id?: number }; + patient?: { name?: string }; + }) => + item.hospital?.id === ctx.fixtures.hospitalAId && + item.patient?.name?.includes(`${keywordPrefix}-self`), ), ).toBe(true); + expect( + response.body.data.list.some((item: { patient?: { name?: string } }) => + item.patient?.name?.includes(`${keywordPrefix}-peer`), + ), + ).toBe(false); }); it('失败:hospitalId 非法返回 400', async () => { diff --git a/tyt-admin/src/views/patients/Patients.vue b/tyt-admin/src/views/patients/Patients.vue index ffb4c25..dbdfebb 100644 --- a/tyt-admin/src/views/patients/Patients.vue +++ b/tyt-admin/src/views/patients/Patients.vue @@ -78,7 +78,7 @@ - + @@ -421,7 +421,7 @@ {{ detailPatient.creator?.name || '-' }} - + {{ detailPatient.hospital?.name || '-' }} @@ -716,7 +716,7 @@ {{ row.surgery?.surgeryName || '-' }} - + @@ -791,6 +791,9 @@ const doctorTreeProps = { }; const isSystemAdmin = computed(() => userStore.role === 'SYSTEM_ADMIN'); +const canViewHospitalInfo = computed(() => + ['SYSTEM_ADMIN', 'HOSPITAL_ADMIN'].includes(userStore.role), +); const canPublishAdjustTask = computed(() => ['SYSTEM_ADMIN', 'HOSPITAL_ADMIN', 'DOCTOR', 'DIRECTOR', 'LEADER'].includes( userStore.role, diff --git a/tyt-admin/src/views/tasks/Tasks.vue b/tyt-admin/src/views/tasks/Tasks.vue index 15f3ae2..629acc2 100644 --- a/tyt-admin/src/views/tasks/Tasks.vue +++ b/tyt-admin/src/views/tasks/Tasks.vue @@ -193,13 +193,7 @@ - - + - +