feat(M08-B): 补待结算候选预览

This commit is contained in:
Codex
2026-06-30 18:15:36 +08:00
parent 78fb6ed2d0
commit 67e7796652
11 changed files with 176 additions and 15 deletions
@@ -377,7 +377,9 @@ export class CleaningTaskRepository {
});
}
async settlementCandidates(input: CleaningActor & { page: number; pageSize: number }) {
async settlementCandidates(input: CleaningActor & {
page: number; pageSize: number; storeId?: string; cleanerUserId?: string;
}) {
this.assertCleaner(input.access, 'read');
const where = [
't.tenant_id = ?',
@@ -386,7 +388,23 @@ export class CleaningTaskRepository {
't.settled_at IS NULL',
storeScopeSql(input.access, 't.store_id')
];
return this.listByWhere(where, [input.tenantId], input.page, input.pageSize, 't.completed_at ASC, t.id ASC');
const params: Array<string | number> = [input.tenantId];
if (input.storeId) {
where.push('t.store_id = ?');
params.push(input.storeId);
}
if (input.cleanerUserId) {
where.push(`(t.cleaner_user_id = ? OR EXISTS (
SELECT 1 FROM qipai_cleaning_task_members candidate_member
WHERE candidate_member.tenant_id = t.tenant_id
AND candidate_member.task_id = t.id
AND candidate_member.user_id = ?
AND candidate_member.removed_at IS NULL
AND candidate_member.settled_at IS NULL
))`);
params.push(input.cleanerUserId, input.cleanerUserId);
}
return this.listByWhere(where, params, input.page, input.pageSize, 't.completed_at ASC, t.id ASC');
}
async listSettlements(input: CleaningActor & {
+1 -1
View File
@@ -186,7 +186,7 @@ export async function registerCleaningRoutes(
app.get('/admin-api/cleaning/settlement-candidates', async (request, reply) => {
const actor = await requireActor(request, reply, options, 'read');
if (!actor) return;
const query = listSchema.omit({ status: true }).safeParse(request.query);
const query = managerTaskListSchema.omit({ status: true }).safeParse(request.query);
if (!query.success) return invalid(reply, request.traceId);
return handle(reply, request.traceId, async () => ({
code: 0,
+3 -1
View File
@@ -416,11 +416,13 @@ assert.equal(calls.at(-1)[1].cleanerUserId, '33');
const settlement = await app.inject({
method: 'GET',
url: '/admin-api/cleaning/settlement-candidates?page=1&pageSize=10',
url: '/admin-api/cleaning/settlement-candidates?page=1&pageSize=10&storeId=11&cleanerUserId=31',
headers: { authorization: `Bearer ${token}` }
});
assert.equal(settlement.statusCode, 200);
assert.equal(calls.at(-1)[0], 'settlementCandidates');
assert.equal(calls.at(-1)[1].storeId, '11');
assert.equal(calls.at(-1)[1].cleanerUserId, '31');
const settlementList = await app.inject({
method: 'GET',