feat(M09-B): 完成清洁规则与照片验收闭环
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import { existsSync, readFileSync } from 'node:fs';
|
||||
import { join } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
const root = fileURLToPath(new URL('..', import.meta.url));
|
||||
const read = (path) => readFileSync(join(root, path), 'utf8');
|
||||
|
||||
for (const suffix of ['up', 'verify', 'down']) {
|
||||
assert.ok(
|
||||
existsSync(join(root, `database/migrations/2026081005_m09b_cleaning_rules.${suffix}.sql`)),
|
||||
`M09-B ${suffix} migration is missing`
|
||||
);
|
||||
}
|
||||
|
||||
const migration = read('database/migrations/2026081005_m09b_cleaning_rules.up.sql');
|
||||
for (const pattern of [
|
||||
'qipai_cleaning_templates',
|
||||
'cleaning_template_version',
|
||||
'photo_required',
|
||||
'min_photo_count',
|
||||
'max_photo_count',
|
||||
'exempt_policy',
|
||||
'rework_count',
|
||||
'qipai_cleaning_task_photos',
|
||||
'retention_until',
|
||||
'attached_revision',
|
||||
'qipai_cleaning_task_submissions',
|
||||
'uq_qipai_cleaning_submission_revision'
|
||||
]) assert.ok(migration.includes(pattern), `migration is missing ${pattern}`);
|
||||
|
||||
const repository = read('backend/src/cleaning/cleaning-task-repository.ts');
|
||||
for (const pattern of [
|
||||
'listTemplates',
|
||||
'upsertTemplate',
|
||||
"'appliesToExistingTasks', FALSE",
|
||||
'listSubmissions',
|
||||
'CLEANING_PHOTO_OWNERSHIP_INVALID',
|
||||
"status = 'ATTACHED'",
|
||||
'attached_revision = ?',
|
||||
'claimExpiredPhotoUploads',
|
||||
'markPhotoUploadsDeleted',
|
||||
'CLEANING_EXEMPT_POLICY_DENIED',
|
||||
"ORDER BY FIELD(scope_type, 'ROOM', 'STORE', 'TENANT')"
|
||||
]) assert.ok(repository.includes(pattern), `repository is missing ${pattern}`);
|
||||
|
||||
const routes = read('backend/src/routes/cleaning.ts');
|
||||
for (const pattern of [
|
||||
'/admin-api/cleaning/templates',
|
||||
'/admin-api/cleaning/tasks/:taskId/submissions',
|
||||
'/admin-api/cleaning/photos/cleanup',
|
||||
'tenantId: actor.tenantId',
|
||||
'storeId: context.storeId',
|
||||
'deleteImage(image.storagePath)'
|
||||
]) assert.ok(routes.includes(pattern), `cleaning routes are missing ${pattern}`);
|
||||
|
||||
const media = read('backend/src/content/media-storage.ts');
|
||||
for (const pattern of [
|
||||
'declaredFormat',
|
||||
'declaredExtension',
|
||||
'metadata.format',
|
||||
'.webp({ quality: 82 })',
|
||||
'deleteImage'
|
||||
]) assert.ok(media.includes(pattern), `media storage is missing ${pattern}`);
|
||||
|
||||
const automation = read('backend/src/devices/order-device-automation-service.ts');
|
||||
for (const pattern of [
|
||||
'ROOM_HAS_ACTIVE_ORDER',
|
||||
"status IN ('PAID', 'RESERVED', 'IN_PROGRESS')",
|
||||
'room_id = ? AND id <> ?'
|
||||
]) assert.ok(automation.includes(pattern), `device automation is missing ${pattern}`);
|
||||
|
||||
const miniapp = read('miniapp/pages/cleaner/tasks.js')
|
||||
+ read('miniapp/pages/cleaner/tasks.wxml');
|
||||
for (const pattern of [
|
||||
'minPhotoCount', 'maxPhotoCount', "task.status === 'STARTED'", 'photoRequired'
|
||||
]) assert.ok(miniapp.includes(pattern), `cleaner miniapp is missing ${pattern}`);
|
||||
|
||||
const admin = read('admin/src/components/CleaningRulesPanel.vue')
|
||||
+ read('admin/src/components/CleaningTasksPanel.vue')
|
||||
+ read('admin/src/api.ts');
|
||||
for (const pattern of [
|
||||
'配置变更不会静默改写在途任务',
|
||||
'listCleaningTemplates',
|
||||
'upsertCleaningTemplate',
|
||||
'listCleaningTaskSubmissions',
|
||||
'验收照片版本',
|
||||
'submission.revision'
|
||||
]) assert.ok(admin.includes(pattern), `admin cleaning workflow is missing ${pattern}`);
|
||||
|
||||
const liveTest = read('backend/tests/mysql-migration-roundtrip.test.mjs');
|
||||
for (const pattern of [
|
||||
'cleaning template snapshot remains stable after config version change',
|
||||
'rejected and accepted cleaning photo revisions remain distinguishable',
|
||||
'expired unattached cleaning photo retention cleanup',
|
||||
'task-level cleaning exemption policy denial'
|
||||
]) assert.ok(liveTest.includes(pattern), `live MySQL test is missing ${pattern}`);
|
||||
|
||||
console.log('PASS: M09-B cleaning templates, photo security, versioned review and safe device shutdown gates are present.');
|
||||
@@ -32,6 +32,8 @@ node scripts/check-admin-m08-d-r1.mjs --source-only
|
||||
Assert-NativeSuccess "check-admin-m08-d-r1 source"
|
||||
node scripts/check-miniapp-m08-c.mjs
|
||||
Assert-NativeSuccess "check-miniapp-m08-c"
|
||||
node scripts/check-m09-b-cleaning-rules.mjs
|
||||
Assert-NativeSuccess "check-m09-b-cleaning-rules"
|
||||
|
||||
if (Test-Path "admin/package.json") {
|
||||
Push-Location admin
|
||||
|
||||
Reference in New Issue
Block a user