Files
qipai/scripts/check-admin-m08-b.mjs
T
2026-07-07 09:45:15 +08:00

345 lines
8.4 KiB
JavaScript

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',
'CleaningStatisticsPanel',
'CleanersPanel',
'qipai.admin.token',
'loadTasks',
'loadSettlements',
'loadStatistics',
'loadCleaners',
'handleSyncTransfer',
'handleSyncTransferMany',
'handleCompleteMany',
'handleRejectMany',
'运营待处理',
'jumpToTaskStatus',
'jumpToSettlementStatus',
'draftSettlementTotal',
'operationalQueueTotal',
'exportOperationalQueue',
'cleaning-operational-queue',
'导出待处理',
'settlementFilters.payoutState',
'待确认结算',
'待发放金额',
'CleaningFieldHandoffPanel',
'联调'
]) {
assert.match(app, new RegExp(pattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')));
}
const api = read('admin/src/api.ts');
for (const route of [
'/cleaning/tasks?',
'/cleaning/statistics',
'storeId',
'cleanerUserId',
'/users?',
'/staff',
'/reset-sessions',
'/assign',
'/complete',
'/reject',
'/members',
'/cleaning/reclaim-timeouts',
'/cleaning/settlements?',
'/cleaning/settlements',
'payoutState',
'/wechat-transfer',
'/wechat-transfer/preflight',
'/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 [
'指派',
'验收',
'驳回',
'回收',
'成员',
'保洁任务详情',
'操作流水',
'协作分账',
'listCleaningTaskEvents',
'listCleaningTaskMembers',
'loadingEvents',
'loadingMembers',
'批量验收',
'批量驳回',
'selectedSubmittedTasks',
'complete-many',
'reject-many',
'photo-grid',
'timeline-grid',
'el-image',
'协作者管理',
'photoUrls',
'el-select',
'cleanerLabel',
'filterDraft',
'门店 ID',
'筛选',
'导出',
'exportTasks',
'exportTaskDetail',
'exportTaskEvents',
'exportTaskMembers',
'cleaning-tasks',
'cleaning-task-detail',
'cleaning-task-events',
'cleaning-task-members',
'导出详情',
'导出成员',
'downloadCsv',
'csvCell',
'photoUrls?.length'
]) {
assert.match(tasks, new RegExp(pattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')));
}
const settlements = read('admin/src/components/CleaningSettlementsPanel.vue');
for (const pattern of [
'详情',
'生成',
'确认',
'转账',
'同步',
'批量同步',
'selectedSyncableSettlements',
'sync-transfer-many',
'失败',
'结算单详情',
'微信确认参数',
'payoutPackageInfo',
'getCleaningSettlementDetail',
'微信转账预检',
'preflightWechatTransfer',
'凭据引用',
'授权状态',
'通知URL',
'平台证书',
'保洁员OpenID',
'credentialRefMasked',
'platformCertificateCount',
'configuredText',
'导出预检',
'exportPreflight',
'cleaning-transfer-preflight',
'transferPreflightTitle',
'transferCanSubmit',
'preflightLoading',
'listCleaningSettlementCandidates',
'candidateDialog',
'useCandidateFilters',
'exportSettlements',
'exportCandidates',
'exportSettlementDetail',
'cleaning-settlement-detail',
'downloadCsv',
'MOCK',
'el-select',
'cleanerLabel',
'filterDraft',
'payoutStateOptions',
'转账状态',
'WAIT_USER_CONFIRM',
'门店 ID',
'筛选'
]) {
assert.match(settlements, new RegExp(pattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')));
}
const statistics = read('admin/src/components/CleaningStatisticsPanel.vue');
for (const pattern of [
'今日',
'近7天',
'本月',
'任务状态',
'结算口径',
'每日趋势',
'trendWidth',
'paidSettlementCents',
'门店明细',
'成员分账',
'pendingSettlementCents',
'filterDraft.cleanerUserId',
'cleanerLabel',
'exportStatistics',
'cleaning-statistics',
'downloadCsv',
'csvCell',
'el-select'
]) {
assert.match(statistics, new RegExp(pattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')));
}
const cleaners = read('admin/src/components/CleanersPanel.vue');
for (const pattern of [
'新增保洁员',
'门店 ID,逗号分隔',
'已绑微信',
'待补资料',
'profileComplete',
'profileIssues',
'exportCleaners',
'exportCleanerProfileIssues',
'cleaning-cleaners',
'cleaning-cleaner-profile-issues',
'导出待补',
'downloadCsv',
'csvCell',
'会话',
'status-toggle',
'reset-sessions'
]) {
assert.match(cleaners, new RegExp(pattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')));
}
const handoff = read('admin/src/components/CleaningFieldHandoffPanel.vue');
for (const pattern of [
'现场联调进度',
'qipai.cleaning.field-handoff',
'qipai.cleaning.field-handoff.session',
'联调批次',
'现场/门店',
'验收人',
'收口结论',
'下一步',
'acceptor',
'closeoutVerdict',
'nextAction',
'createEmptySessionMeta',
'最后更新',
'证据记录',
'evidenceRecordedCount',
'待补证据',
'evidenceMissingItems',
'evidenceMissingCount',
'copyEvidenceSummary',
'待补证据清单已复制',
'现场交接报告已复制',
'copyHandoffReport',
'exportHandoffReport',
'exportCloseoutArchive',
'buildCloseoutArchive',
'serializeHandoffItem',
'buildHandoffReport',
'formatReportItem',
'statusText',
'cleaning-field-handoff-report',
'cleaning-field-closeout-archive',
'qipai.cleaning.field-handoff.closeout-archive.v1',
'归档包',
'evidenceRef',
'normalizeDraft',
'sessionMeta',
'updatedAt',
'persistSessionMeta',
'formatLocalMinute',
'快照',
'导入',
'exportSnapshot',
'importSnapshot',
'qipai.cleaning.field-handoff.snapshot.v1',
'cleaning-field-handoff-snapshot',
'categoryProgress',
'passPercent',
'handoff-category-progress',
'可进入现场验收收口',
'handoffReady',
'missingCloseoutFields',
'closeoutReady',
'copyVerdict',
'copyCloseoutGate',
'收口门禁已复制',
'归档门禁',
'现场记录可归档',
'收口资料待补齐',
'检查项状态',
'现场证据',
'联调结论已复制',
'商户凭据引用',
'小程序合法域名',
'小额真实转账',
'订单权限开门',
'控电和插座联动',
'BLOCKED',
'statusFilter',
'handoff-status-select',
'全部状态',
'ownerFilter',
'ownerOptions',
'handoff-owner-select',
'全部负责人',
'未分派',
'批量标记',
'bulkForm',
'deadline',
'期限',
'YYYY-MM-DD',
'applyBulkMark',
'应用到当前筛选',
'阻断摘要',
'blockedItems',
'riskItems',
'copyBlockedSummary',
'navigator.clipboard.writeText',
'exportChecklist',
'exportRiskRegister',
'cleaning-field-handoff',
'cleaning-field-risk-register',
'缺证据',
'localStorage',
'downloadCsv'
]) {
assert.match(handoff, new RegExp(pattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')));
}
const styles = read('admin/src/styles.css');
assert.match(styles, /\.cleaner-select/);
assert.match(styles, /\.option-row/);
assert.match(styles, /\.filter-select/);
assert.match(styles, /\.narrow-input/);
assert.match(styles, /\.action-board/);
assert.match(styles, /\.action-tile/);
assert.match(styles, /\.handoff-summary/);
assert.match(styles, /\.handoff-body/);
assert.match(styles, /\.handoff-session/);
assert.match(styles, /\.handoff-category-progress/);
assert.match(styles, /\.handoff-category-row/);
assert.match(styles, /\.handoff-verdict/);
assert.match(styles, /\.handoff-status-select/);
assert.match(styles, /\.handoff-bulk-form/);
assert.match(styles, /\.handoff-blockers/);
assert.match(styles, /\.hidden-file-input/);
assert.match(styles, /\.transfer-preflight-alert/);
assert.match(styles, /@media \(max-width: 980px\)/);
assert.match(styles, /@media \(max-width: 560px\)/);
console.log('PASS: M08-B admin cleaning workspace covers task, settlement, transfer and preflight controls.');