feat(M09-B): 完成清洁规则与照片验收闭环
This commit is contained in:
@@ -77,6 +77,25 @@ const app = await buildApp({
|
||||
},
|
||||
async assertCanUploadPhoto(input) {
|
||||
calls.push(['assertCanUploadPhoto', input]);
|
||||
return { storeId: '11', maxPhotoCount: 3 };
|
||||
},
|
||||
async recordPhotoUpload(input) {
|
||||
calls.push(['recordPhotoUpload', input]);
|
||||
return { id: '701', ...input.image };
|
||||
},
|
||||
async listTemplates(input) {
|
||||
calls.push(['listTemplates', input]);
|
||||
return [{
|
||||
id: '801', scopeKey: 'STORE:11', scopeType: 'STORE', storeId: '11', roomId: null,
|
||||
name: '门店清洁', requirement: '桌面与地面', photoRequired: true,
|
||||
minPhotoCount: 2, maxPhotoCount: 3, exemptPolicy: 'BEFORE_START',
|
||||
version: 2, status: 'ACTIVE', appliesToExistingTasks: false
|
||||
}];
|
||||
},
|
||||
async upsertTemplate(input) {
|
||||
calls.push(['upsertTemplate', input]);
|
||||
return { id: '801', scopeKey: `STORE:${input.scopeId}`, ...input,
|
||||
storeId: input.scopeId, roomId: null, version: 3, appliesToExistingTasks: false };
|
||||
},
|
||||
async submit(input) {
|
||||
calls.push(['submit', input]);
|
||||
@@ -116,6 +135,15 @@ const app = await buildApp({
|
||||
createdAt: new Date()
|
||||
}];
|
||||
},
|
||||
async listSubmissions(input) {
|
||||
calls.push(['listSubmissions', input]);
|
||||
return [{
|
||||
id: '9101', taskId: input.taskId, revision: 2, status: 'REJECTED',
|
||||
photoUrls: ['https://api.txyundm.cn/uploads/old.webp'], note: 'first',
|
||||
rejectReason: 'photo is unclear', submittedBy: '31', reviewedBy: '31',
|
||||
submittedAt: new Date(), reviewedAt: new Date()
|
||||
}];
|
||||
},
|
||||
async addMember(input) {
|
||||
calls.push(['addMember', input]);
|
||||
return [member('LEAD', '31', 500), member('ASSIST', input.cleanerUserId, input.rewardCents)];
|
||||
@@ -171,6 +199,14 @@ const app = await buildApp({
|
||||
calls.push(['reclaimTimeouts', input]);
|
||||
return { reclaimed: 2, taskIds: ['101', '102'] };
|
||||
},
|
||||
async claimExpiredPhotoUploads(input) {
|
||||
calls.push(['claimExpiredPhotoUploads', input]);
|
||||
return [{ id: '701', storagePath: 'tenants/7/stores/11/orphan.webp' }];
|
||||
},
|
||||
async markPhotoUploadsDeleted(input) {
|
||||
calls.push(['markPhotoUploadsDeleted', input]);
|
||||
return { deleted: input.photoIds.length };
|
||||
},
|
||||
async stats(input) {
|
||||
calls.push(['stats', input]);
|
||||
return {
|
||||
@@ -281,19 +317,44 @@ const app = await buildApp({
|
||||
async storeImage(input) {
|
||||
calls.push(['storeImage', input]);
|
||||
return {
|
||||
storagePath: 'tenants/7/shared/cleaning.webp',
|
||||
publicUrl: 'https://api.txyundm.cn/uploads/tenants/7/shared/cleaning.webp',
|
||||
storagePath: 'tenants/7/stores/11/cleaning.webp',
|
||||
publicUrl: 'https://api.txyundm.cn/uploads/tenants/7/stores/11/cleaning.webp',
|
||||
mimeType: 'image/webp',
|
||||
byteSize: input.body.length,
|
||||
width: 640,
|
||||
height: 480,
|
||||
checksumSha256: 'abc'
|
||||
};
|
||||
},
|
||||
async deleteImage(storagePath) {
|
||||
calls.push(['deleteImage', storagePath]);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const templates = await app.inject({
|
||||
method: 'GET',
|
||||
url: '/admin-api/cleaning/templates',
|
||||
headers: { authorization: `Bearer ${token}` }
|
||||
});
|
||||
assert.equal(templates.statusCode, 200);
|
||||
assert.equal(templates.json().data[0].scopeKey, 'STORE:11');
|
||||
|
||||
const updatedTemplate = await app.inject({
|
||||
method: 'PUT',
|
||||
url: '/admin-api/cleaning/templates',
|
||||
headers: { authorization: `Bearer ${token}` },
|
||||
payload: {
|
||||
scopeType: 'STORE', scopeId: '11', name: '门店清洁', requirement: '桌面与地面',
|
||||
photoRequired: true, minPhotoCount: 2, maxPhotoCount: 3,
|
||||
exemptPolicy: 'BEFORE_START', status: 'ACTIVE'
|
||||
}
|
||||
});
|
||||
assert.equal(updatedTemplate.statusCode, 200);
|
||||
assert.equal(updatedTemplate.json().data.appliesToExistingTasks, false);
|
||||
assert.equal(calls.at(-1)[0], 'upsertTemplate');
|
||||
|
||||
const hall = await app.inject({
|
||||
method: 'GET',
|
||||
url: '/app-api/cleaning/tasks/hall?page=1&pageSize=10',
|
||||
@@ -396,9 +457,11 @@ const photo = await app.inject({
|
||||
payload: Buffer.from('fake-image')
|
||||
});
|
||||
assert.equal(photo.statusCode, 201);
|
||||
assert.equal(photo.json().data.publicUrl, 'https://api.txyundm.cn/uploads/tenants/7/shared/cleaning.webp');
|
||||
assert.equal(calls.at(-2)[0], 'assertCanUploadPhoto');
|
||||
assert.equal(calls.at(-1)[0], 'storeImage');
|
||||
assert.equal(photo.json().data.publicUrl, 'https://api.txyundm.cn/uploads/tenants/7/stores/11/cleaning.webp');
|
||||
assert.equal(calls.at(-3)[0], 'assertCanUploadPhoto');
|
||||
assert.equal(calls.at(-2)[0], 'storeImage');
|
||||
assert.equal(calls.at(-2)[1].storeId, '11');
|
||||
assert.equal(calls.at(-1)[0], 'recordPhotoUpload');
|
||||
|
||||
const submit = await app.inject({
|
||||
method: 'POST',
|
||||
@@ -498,6 +561,16 @@ assert.equal(calls.at(-1)[0], 'listEvents');
|
||||
assert.equal(calls.at(-1)[1].taskId, '101');
|
||||
assert.equal(events.json().data[0].action, 'SUBMIT');
|
||||
|
||||
const submissions = await app.inject({
|
||||
method: 'GET',
|
||||
url: '/admin-api/cleaning/tasks/101/submissions',
|
||||
headers: { authorization: `Bearer ${token}` }
|
||||
});
|
||||
assert.equal(submissions.statusCode, 200);
|
||||
assert.equal(calls.at(-1)[0], 'listSubmissions');
|
||||
assert.equal(submissions.json().data[0].revision, 2);
|
||||
assert.equal(submissions.json().data[0].photoUrls[0], 'https://api.txyundm.cn/uploads/old.webp');
|
||||
|
||||
const addedMember = await app.inject({
|
||||
method: 'POST',
|
||||
url: '/admin-api/cleaning/tasks/101/members',
|
||||
@@ -664,6 +737,19 @@ assert.equal(reclaimed.statusCode, 200);
|
||||
assert.equal(calls.at(-1)[0], 'reclaimTimeouts');
|
||||
assert.equal(calls.at(-1)[1].olderThanMinutes, 30);
|
||||
|
||||
const cleanedPhotos = await app.inject({
|
||||
method: 'POST',
|
||||
url: '/admin-api/cleaning/photos/cleanup',
|
||||
headers: { authorization: `Bearer ${token}` },
|
||||
payload: { limit: 10 }
|
||||
});
|
||||
assert.equal(cleanedPhotos.statusCode, 200);
|
||||
assert.deepEqual(cleanedPhotos.json().data, { claimed: 1, deleted: 1, failedIds: [] });
|
||||
assert.equal(calls.at(-3)[0], 'claimExpiredPhotoUploads');
|
||||
assert.equal(calls.at(-2)[0], 'deleteImage');
|
||||
assert.equal(calls.at(-1)[0], 'markPhotoUploadsDeleted');
|
||||
assert.deepEqual(calls.at(-1)[1].photoIds, ['701']);
|
||||
|
||||
const stats = await app.inject({
|
||||
method: 'GET',
|
||||
url: '/app-api/cleaning/stats',
|
||||
|
||||
Reference in New Issue
Block a user