feat(M08-B): 增加保洁多人协作策略
This commit is contained in:
@@ -94,6 +94,18 @@ const app = await buildApp({
|
||||
calls.push(['reject', input]);
|
||||
return { ...task('REJECTED'), rejectReason: input.reason };
|
||||
},
|
||||
async listMembers(input) {
|
||||
calls.push(['listMembers', input]);
|
||||
return [member('LEAD', '31', 500), member('ASSIST', '33', 100)];
|
||||
},
|
||||
async addMember(input) {
|
||||
calls.push(['addMember', input]);
|
||||
return [member('LEAD', '31', 500), member('ASSIST', input.cleanerUserId, input.rewardCents)];
|
||||
},
|
||||
async removeMember(input) {
|
||||
calls.push(['removeMember', input]);
|
||||
return [member('LEAD', '31', 600)];
|
||||
},
|
||||
async settlementCandidates(input) {
|
||||
calls.push(['settlementCandidates', input]);
|
||||
return { items: [task('COMPLETED')], total: 1, page: input.page, pageSize: input.pageSize };
|
||||
@@ -243,6 +255,36 @@ assert.equal(reject.statusCode, 200);
|
||||
assert.equal(calls.at(-1)[0], 'reject');
|
||||
assert.equal(calls.at(-1)[1].reason, 'photo is unclear');
|
||||
|
||||
const members = await app.inject({
|
||||
method: 'GET',
|
||||
url: '/admin-api/cleaning/tasks/101/members',
|
||||
headers: { authorization: `Bearer ${token}` }
|
||||
});
|
||||
assert.equal(members.statusCode, 200);
|
||||
assert.equal(calls.at(-1)[0], 'listMembers');
|
||||
assert.equal(members.json().data.length, 2);
|
||||
|
||||
const addedMember = await app.inject({
|
||||
method: 'POST',
|
||||
url: '/admin-api/cleaning/tasks/101/members',
|
||||
headers: { authorization: `Bearer ${token}` },
|
||||
payload: { cleanerUserId: '33', rewardCents: 100, note: 'support' }
|
||||
});
|
||||
assert.equal(addedMember.statusCode, 200);
|
||||
assert.equal(calls.at(-1)[0], 'addMember');
|
||||
assert.equal(calls.at(-1)[1].cleanerUserId, '33');
|
||||
assert.equal(calls.at(-1)[1].rewardCents, 100);
|
||||
|
||||
const removedMember = await app.inject({
|
||||
method: 'POST',
|
||||
url: '/admin-api/cleaning/tasks/101/members/33/remove',
|
||||
headers: { authorization: `Bearer ${token}` },
|
||||
payload: { note: 'done' }
|
||||
});
|
||||
assert.equal(removedMember.statusCode, 200);
|
||||
assert.equal(calls.at(-1)[0], 'removeMember');
|
||||
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',
|
||||
@@ -346,3 +388,17 @@ function settlementResponse(status) {
|
||||
note: ''
|
||||
};
|
||||
}
|
||||
|
||||
function member(memberRole, userId, rewardCents) {
|
||||
return {
|
||||
id: `${userId}01`,
|
||||
taskId: '101',
|
||||
userId,
|
||||
nickname: `Cleaner ${userId}`,
|
||||
memberRole,
|
||||
rewardCents,
|
||||
joinedAt: new Date(),
|
||||
removedAt: null,
|
||||
settledAt: null
|
||||
};
|
||||
}
|
||||
|
||||
@@ -87,6 +87,9 @@ const cleaningVerifySql = read('database/migrations/2026062525_m08b_cleaner_task
|
||||
const cleaningSettlementUpSql = read('database/migrations/2026062626_m08b_cleaning_settlements.up.sql');
|
||||
const cleaningSettlementDownSql = read('database/migrations/2026062626_m08b_cleaning_settlements.down.sql');
|
||||
const cleaningSettlementVerifySql = read('database/migrations/2026062626_m08b_cleaning_settlements.verify.sql');
|
||||
const cleaningCollaborationUpSql = read('database/migrations/2026062627_m08b_cleaning_collaboration.up.sql');
|
||||
const cleaningCollaborationDownSql = read('database/migrations/2026062627_m08b_cleaning_collaboration.down.sql');
|
||||
const cleaningCollaborationVerifySql = read('database/migrations/2026062627_m08b_cleaning_collaboration.verify.sql');
|
||||
|
||||
const coreTables = [
|
||||
'qipai_schema_migrations',
|
||||
@@ -412,4 +415,15 @@ assert.match(cleaningSettlementUpSql, /uq_qipai_cleaning_settlement_item_task/);
|
||||
assert.match(cleaningSettlementUpSql, /cleaning\.settlement\.read/);
|
||||
assert.match(cleaningSettlementUpSql, /cleaning\.settlement\.write/);
|
||||
|
||||
assert.match(cleaningCollaborationUpSql, /CREATE TABLE IF NOT EXISTS qipai_cleaning_task_members/);
|
||||
assert.match(cleaningCollaborationUpSql, /member_role VARCHAR\(16\) NOT NULL DEFAULT 'ASSIST'/);
|
||||
assert.match(cleaningCollaborationUpSql, /settled_at DATETIME\(3\) NULL/);
|
||||
assert.match(cleaningCollaborationUpSql, /DROP INDEX uq_qipai_cleaning_settlement_item_task/);
|
||||
assert.match(cleaningCollaborationUpSql, /cleaner_user_id BIGINT UNSIGNED NOT NULL/);
|
||||
assert.match(cleaningCollaborationUpSql, /uq_qipai_cleaning_settlement_item_task_user/);
|
||||
assert.match(cleaningCollaborationDownSql, /DROP TABLE IF EXISTS qipai_cleaning_task_members/);
|
||||
assert.match(cleaningCollaborationDownSql, /ADD UNIQUE KEY uq_qipai_cleaning_settlement_item_task/);
|
||||
assert.match(cleaningCollaborationVerifySql, /'qipai_cleaning_task_members'/);
|
||||
assert.match(cleaningCollaborationVerifySql, /'cleaner_user_id'/);
|
||||
|
||||
console.log('PASS: M01-B through M08-B migration contracts are present.');
|
||||
|
||||
@@ -36,7 +36,8 @@ assert.match(plan.file, /2026062421_m07a_wallet_ledger\.up\.sql/);
|
||||
assert.match(plan.file, /2026062422_m07b_recharge_plans\.up\.sql/);
|
||||
assert.match(plan.file, /2026062524_m08a_recharge_wechat\.up\.sql/);
|
||||
assert.match(plan.file, /2026062525_m08b_cleaner_tasks\.up\.sql/);
|
||||
assert.match(plan.file, /2026062626_m08b_cleaning_settlements\.up\.sql$/);
|
||||
assert.match(plan.file, /2026062626_m08b_cleaning_settlements\.up\.sql/);
|
||||
assert.match(plan.file, /2026062627_m08b_cleaning_collaboration\.up\.sql$/);
|
||||
assert.match(plan.checksum, /^[a-f0-9]{64}$/);
|
||||
assert.ok(plan.statements.length >= 11);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user