import assert from 'node:assert/strict'; import { readFileSync } from 'node:fs'; import { join } from 'node:path'; const root = new URL('..', import.meta.url).pathname.replace(/^\/([A-Za-z]:)/, '$1'); const read = (path) => readFileSync(join(root, path), 'utf8'); const packageJson = JSON.parse(read('admin/package.json')); assert.equal(packageJson.dependencies.vue.startsWith('^3.'), true); assert.ok(packageJson.dependencies['element-plus']); assert.ok(packageJson.dependencies['@lucide/vue']); const envExample = read('admin/.env.example'); assert.match(envExample, /https:\/\/api\.txyundm\.cn\/admin-api/); assert.doesNotMatch(envExample, /localhost|127\.0\.0\.1|http:\/\//); const vite = read('admin/vite.config.ts'); assert.match(vite, /base: '\/admin\/'/); assert.match(vite, /'\/admin-api'/); const app = read('admin/src/App.vue'); for (const pattern of [ 'CleaningTasksPanel', 'CleaningSettlementsPanel', 'qipai.admin.token', 'loadTasks', 'loadSettlements', 'handleSyncTransfer' ]) { assert.match(app, new RegExp(pattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'))); } const api = read('admin/src/api.ts'); for (const route of [ '/cleaning/tasks?', '/assign', '/complete', '/reject', '/cleaning/reclaim-timeouts', '/cleaning/settlements?', '/cleaning/settlements', '/wechat-transfer', '/wechat-transfer/sync', '/payout-failure' ]) { assert.match(api, new RegExp(route.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'))); } const tasks = read('admin/src/components/CleaningTasksPanel.vue'); for (const pattern of ['指派', '验收', '驳回', '回收', 'photoUrls']) { assert.match(tasks, new RegExp(pattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'))); } const settlements = read('admin/src/components/CleaningSettlementsPanel.vue'); for (const pattern of ['生成', '确认', '转账', '同步', '失败', 'MOCK']) { assert.match(settlements, new RegExp(pattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'))); } const styles = read('admin/src/styles.css'); assert.match(styles, /@media \(max-width: 980px\)/); assert.match(styles, /@media \(max-width: 560px\)/); console.log('PASS: M08-B admin cleaning workspace uses fixed admin API and covers task, settlement and transfer controls.');