feat(M08-B): 增加保洁多人协作策略
This commit is contained in:
@@ -25,6 +25,18 @@ const assignSchema = z.object({
|
||||
cleanerUserId: z.string().regex(/^[1-9]\d{0,19}$/),
|
||||
note: z.string().trim().max(512).optional()
|
||||
}).strict();
|
||||
const memberParamsSchema = z.object({
|
||||
taskId: z.string().regex(/^[1-9]\d{0,19}$/),
|
||||
cleanerUserId: z.string().regex(/^[1-9]\d{0,19}$/)
|
||||
});
|
||||
const memberSchema = z.object({
|
||||
cleanerUserId: z.string().regex(/^[1-9]\d{0,19}$/),
|
||||
rewardCents: z.coerce.number().int().min(0).max(1000000),
|
||||
note: z.string().trim().max(512).optional()
|
||||
}).strict();
|
||||
const memberRemoveSchema = z.object({
|
||||
note: z.string().trim().max(512).optional()
|
||||
}).strict();
|
||||
const completeSchema = z.object({ note: z.string().trim().max(512).optional() }).strict();
|
||||
const rejectSchema = z.object({ reason: z.string().trim().min(1).max(512) }).strict();
|
||||
const settlementStatusSchema = z.enum(['DRAFT', 'CONFIRMED', 'PAID', 'CANCELLED']);
|
||||
@@ -50,7 +62,7 @@ const reclaimSchema = z.object({
|
||||
export interface CleaningRouteOptions {
|
||||
repository: Pick<CleaningTaskRepository,
|
||||
'listHall' | 'listMine' | 'listManage' | 'claim' | 'start' | 'rework' | 'submit'
|
||||
| 'assign' | 'complete' | 'reject' | 'settlementCandidates'
|
||||
| 'assign' | 'complete' | 'reject' | 'listMembers' | 'addMember' | 'removeMember' | 'settlementCandidates'
|
||||
| 'listSettlements' | 'generateSettlement' | 'confirmSettlement' | 'reclaimTimeouts'
|
||||
| 'assertCanUploadPhoto' | 'stats'>;
|
||||
mediaStorage?: MediaStorage;
|
||||
@@ -171,6 +183,55 @@ export async function registerCleaningRoutes(
|
||||
}));
|
||||
});
|
||||
|
||||
app.get('/admin-api/cleaning/tasks/:taskId/members', async (request, reply) => {
|
||||
const actor = await requireActor(request, reply, options, 'read');
|
||||
if (!actor) return;
|
||||
const params = paramsSchema.safeParse(request.params);
|
||||
if (!params.success) return invalid(reply, request.traceId);
|
||||
return handle(reply, request.traceId, async () => ({
|
||||
code: 0,
|
||||
data: await options.repository.listMembers({ ...actor, taskId: params.data.taskId }),
|
||||
traceId: request.traceId
|
||||
}));
|
||||
});
|
||||
|
||||
app.post('/admin-api/cleaning/tasks/:taskId/members', async (request, reply) => {
|
||||
const actor = await requireActor(request, reply, options, 'write');
|
||||
if (!actor) return;
|
||||
const params = paramsSchema.safeParse(request.params);
|
||||
const body = memberSchema.safeParse(request.body ?? {});
|
||||
if (!params.success || !body.success) return invalid(reply, request.traceId);
|
||||
return handle(reply, request.traceId, async () => ({
|
||||
code: 0,
|
||||
data: await options.repository.addMember({
|
||||
...actor,
|
||||
taskId: params.data.taskId,
|
||||
cleanerUserId: body.data.cleanerUserId,
|
||||
rewardCents: body.data.rewardCents,
|
||||
note: body.data.note
|
||||
}),
|
||||
traceId: request.traceId
|
||||
}));
|
||||
});
|
||||
|
||||
app.post('/admin-api/cleaning/tasks/:taskId/members/:cleanerUserId/remove', async (request, reply) => {
|
||||
const actor = await requireActor(request, reply, options, 'write');
|
||||
if (!actor) return;
|
||||
const params = memberParamsSchema.safeParse(request.params);
|
||||
const body = memberRemoveSchema.safeParse(request.body ?? {});
|
||||
if (!params.success || !body.success) return invalid(reply, request.traceId);
|
||||
return handle(reply, request.traceId, async () => ({
|
||||
code: 0,
|
||||
data: await options.repository.removeMember({
|
||||
...actor,
|
||||
taskId: params.data.taskId,
|
||||
cleanerUserId: params.data.cleanerUserId,
|
||||
note: body.data.note
|
||||
}),
|
||||
traceId: request.traceId
|
||||
}));
|
||||
});
|
||||
|
||||
app.post('/app-api/cleaning/tasks/:taskId/start', async (request, reply) => {
|
||||
const actor = await requireActor(request, reply, options, 'write');
|
||||
if (!actor) return;
|
||||
|
||||
Reference in New Issue
Block a user