diff --git a/src/order/dto.ts b/src/order/dto.ts index c91a77e..0578af3 100644 --- a/src/order/dto.ts +++ b/src/order/dto.ts @@ -120,3 +120,15 @@ export class BatchRecommendQuery { @IsDateString() timeSlotEnd?: string; } + +/** 按日列表查询:排班派单日视图加载当日工单。 */ +export class ListOrderQuery { + @ApiProperty({ description: '服务日期(YYYY-MM-DD)' }) + @IsDateString() + serviceDate!: string; + + @ApiPropertyOptional({ description: '护理员 staff.id(可选过滤)' }) + @IsOptional() + @IsString() + assigneeId?: string; +} diff --git a/src/order/order.controller.ts b/src/order/order.controller.ts index 59fe8b4..8c2bc54 100644 --- a/src/order/order.controller.ts +++ b/src/order/order.controller.ts @@ -6,6 +6,7 @@ import { BatchRecommendQuery, CancelOrderDto, GenerateOrderDto, + ListOrderQuery, ReassignOrderDto, TodayOrderQuery, } from './dto.js'; @@ -29,7 +30,13 @@ export class OrderController { return this.service.assign(dto); } - // 注意:静态路径 batch-recommend/today 必须先于 :id 声明,否则 :id 会吞掉它们。 + // 注意:静态路径 batch-recommend/today 与列表根路径必须先于 :id 声明,否则 :id 会吞掉它们。 + @Get() + @RequirePermissions(Permissions.order.detail) + list(@Query() q: ListOrderQuery) { + return this.service.list(q); + } + @Get('batch-recommend') @RequirePermissions(Permissions.order.assign) batchRecommend(@Query() q: BatchRecommendQuery) { diff --git a/src/order/order.service.spec.ts b/src/order/order.service.spec.ts index 8623332..64135e2 100644 --- a/src/order/order.service.spec.ts +++ b/src/order/order.service.spec.ts @@ -330,3 +330,32 @@ describe('OrderService.cancel', () => { }); }); }); + +describe('OrderService.list', () => { + it('按 serviceDate 过滤(可选 assigneeId)', async () => { + const orderFindMany = vi.fn().mockResolvedValue([{ id: 'o1' }]); + const { service } = makeService({ orderFindMany }); + + const res = await runWithRequestContext(ctx, () => + service.list({ serviceDate: '2026-10-14', assigneeId: 's1' }), + ); + + expect(res).toHaveLength(1); + expect(orderFindMany).toHaveBeenCalledWith({ + where: { serviceDate: new Date('2026-10-14T00:00:00Z'), assigneeId: 's1' }, + orderBy: { timeSlotStart: 'asc' }, + }); + }); + + it('未传 assigneeId 时不加该过滤条件', async () => { + const orderFindMany = vi.fn().mockResolvedValue([]); + const { service } = makeService({ orderFindMany }); + + await runWithRequestContext(ctx, () => service.list({ serviceDate: '2026-10-14' })); + + expect(orderFindMany).toHaveBeenCalledWith({ + where: { serviceDate: new Date('2026-10-14T00:00:00Z') }, + orderBy: { timeSlotStart: 'asc' }, + }); + }); +}); diff --git a/src/order/order.service.ts b/src/order/order.service.ts index 58d08e3..5bcf501 100644 --- a/src/order/order.service.ts +++ b/src/order/order.service.ts @@ -9,6 +9,7 @@ import { BatchRecommendQuery, CancelOrderDto, GenerateOrderDto, + ListOrderQuery, ReassignOrderDto, TodayOrderQuery, } from './dto.js'; @@ -187,6 +188,13 @@ export class OrderService { return this.requireOrder(id); } + /** 按日列表(排班派单日视图):租户当日工单,可选按护理员过滤。 */ + list(q: ListOrderQuery) { + const where: Record = { serviceDate: toDateOnly(q.serviceDate)! }; + if (q.assigneeId) where.assigneeId = q.assigneeId; + return this.prisma.client.order.findMany({ where, orderBy: { timeSlotStart: 'asc' } }); + } + /** 当前登录护理员本人的当日工单(按 assignee_id + service_date)。 */ async today(q: TodayOrderQuery) { const ctx = getRequestContext();