feat(c2): 工单按日列表接口(排班日视图 R11)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
liuyun 2026-10-14 23:06:03 +08:00
parent 9c4fd6f4ca
commit 00c8fa4d4c
4 changed files with 57 additions and 1 deletions

View File

@ -120,3 +120,15 @@ export class BatchRecommendQuery {
@IsDateString() @IsDateString()
timeSlotEnd?: string; timeSlotEnd?: string;
} }
/** 按日列表查询:排班派单日视图加载当日工单。 */
export class ListOrderQuery {
@ApiProperty({ description: '服务日期(YYYY-MM-DD)' })
@IsDateString()
serviceDate!: string;
@ApiPropertyOptional({ description: '护理员 staff.id(可选过滤)' })
@IsOptional()
@IsString()
assigneeId?: string;
}

View File

@ -6,6 +6,7 @@ import {
BatchRecommendQuery, BatchRecommendQuery,
CancelOrderDto, CancelOrderDto,
GenerateOrderDto, GenerateOrderDto,
ListOrderQuery,
ReassignOrderDto, ReassignOrderDto,
TodayOrderQuery, TodayOrderQuery,
} from './dto.js'; } from './dto.js';
@ -29,7 +30,13 @@ export class OrderController {
return this.service.assign(dto); 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') @Get('batch-recommend')
@RequirePermissions(Permissions.order.assign) @RequirePermissions(Permissions.order.assign)
batchRecommend(@Query() q: BatchRecommendQuery) { batchRecommend(@Query() q: BatchRecommendQuery) {

View File

@ -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' },
});
});
});

View File

@ -9,6 +9,7 @@ import {
BatchRecommendQuery, BatchRecommendQuery,
CancelOrderDto, CancelOrderDto,
GenerateOrderDto, GenerateOrderDto,
ListOrderQuery,
ReassignOrderDto, ReassignOrderDto,
TodayOrderQuery, TodayOrderQuery,
} from './dto.js'; } from './dto.js';
@ -187,6 +188,13 @@ export class OrderService {
return this.requireOrder(id); return this.requireOrder(id);
} }
/** 按日列表(排班派单日视图):租户当日工单,可选按护理员过滤。 */
list(q: ListOrderQuery) {
const where: Record<string, any> = { 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)。 */ /** 当前登录护理员本人的当日工单(按 assignee_id + service_date)。 */
async today(q: TodayOrderQuery) { async today(q: TodayOrderQuery) {
const ctx = getRequestContext(); const ctx = getRequestContext();