93 lines
5.6 KiB
JavaScript
93 lines
5.6 KiB
JavaScript
/**
|
||
* 功能描述:校验配送点资源的独立详情、新建、编辑页面与后端契约保持一致。
|
||
* 版本:v1.0.0。
|
||
*/
|
||
import fs from 'node:fs';
|
||
import path from 'node:path';
|
||
import { fileURLToPath } from 'node:url';
|
||
|
||
const projectRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
||
const contract = JSON.parse(fs.readFileSync(
|
||
path.join(projectRoot, 'src/contracts/delivery-resources.json'),
|
||
'utf8',
|
||
));
|
||
const read = (relativePath) => fs.readFileSync(path.join(projectRoot, relativePath), 'utf8');
|
||
const routeKeys = new Set(contract.routes.map((route) => `${route.method} ${route.path}`));
|
||
const listResources = contract.resources.filter(
|
||
(resource) => resource.pageKind === 'list' && resource.name !== 'delivery_profile',
|
||
);
|
||
const creatable = new Set([
|
||
'staff_account', 'staff_credential', 'user_account', 'user_address',
|
||
'gasorder_contract', 'gasorder_contract_product', 'gasorder_basic',
|
||
'wallet_recharge', 'wallet_apply_cash',
|
||
]);
|
||
const editable = new Set([
|
||
'staff_account', 'staff_credential', 'user_account', 'user_address', 'gasorder_contract',
|
||
]);
|
||
const resourcesByName = new Map(contract.resources.map((resource) => [resource.name, resource]));
|
||
|
||
/** 在条件不成立时中止检查,并给出可直接定位的原因。 */
|
||
function assert(condition, message) {
|
||
if (!condition) throw new Error(message);
|
||
}
|
||
|
||
for (const resource of listResources) {
|
||
assert(
|
||
routeKeys.has(`GET ${resource.path}/:identity`),
|
||
`${resource.name} 缺少详情接口`,
|
||
);
|
||
if (creatable.has(resource.name)) {
|
||
assert(routeKeys.has(`POST ${resource.path}`), `${resource.name} 缺少新建接口`);
|
||
}
|
||
if (editable.has(resource.name)) {
|
||
assert(routeKeys.has(`PUT ${resource.path}/:identity`), `${resource.name} 缺少编辑接口`);
|
||
}
|
||
}
|
||
|
||
assert(listResources.length === 17, `详情页面资源应为 17 个,当前为 ${listResources.length}`);
|
||
assert(creatable.size === 9, `新建页面资源应为 9 个,当前为 ${creatable.size}`);
|
||
assert(editable.size === 5, `编辑页面资源应为 5 个,当前为 ${editable.size}`);
|
||
|
||
const builder = read('src/router/routes/modules/resource-route-builder.ts');
|
||
const platform = read('src/router/routes/modules/platform.ts');
|
||
const resourcePage = read('src/views/shared/ResourcePage.vue');
|
||
const definitions = read('src/api/resources.ts');
|
||
assert(builder.includes("recordRoute('detail', ':identity'"), '路由生成器未创建详情页');
|
||
assert(builder.includes("recordRoute('create', 'new'"), '路由生成器未创建新建页');
|
||
assert(builder.includes("recordRoute('edit', ':identity/edit'"), '路由生成器未创建编辑页');
|
||
assert(platform.includes("createChild('add'"), '工作人员正式新建路由必须保留 /staff/add');
|
||
assert(platform.includes("createChild('create'"), '配送订单正式新建路由必须保留 /gasorder/create');
|
||
assert(resourcePage.includes('ResourceListPage'), '标准资源列表尚未切换到独立页面导航');
|
||
assert(!resourcePage.includes('CrudListPage'), '活动列表仍依赖抽屉式 CrudListPage');
|
||
assert(definitions.includes("define('payment_order'"), '支付资源必须使用后端名称 payment_order');
|
||
assert(definitions.includes("define('payment_refund'"), '退款资源必须使用后端名称 payment_refund');
|
||
assert(routeKeys.has('GET /staff_account/:identity/avatar'), '配送人员缺少受保护头像读取接口');
|
||
assert(routeKeys.has('GET /user_account/:identity/avatar'), '用户账户缺少受保护头像读取接口');
|
||
const recordPage = read('src/views/resource/ResourceRecordPage.vue');
|
||
assert(recordPage.includes('ResourceAccountSummary'), '账户资源页尚未接入 5173 头像摘要卡片');
|
||
assert(recordPage.includes("field.key !== 'avatar'"), '头像字段仍可能显示为普通文本框');
|
||
const listPage = read('src/views/shared/ResourceListPage.vue');
|
||
assert(!listPage.includes('title="ID"'), '标准列表仍暴露数据库自增 ID');
|
||
assert(listPage.includes('ProtectedAvatarThumbnail'), '账户列表尚未接入受控头像缩略图');
|
||
assert(listPage.includes('avatarLoader.reset()'), '列表刷新未清理头像缓存和请求');
|
||
const avatarLoader = read('src/views/shared/protected-list-avatar-loader.ts');
|
||
assert(avatarLoader.includes('MAX_CONCURRENT_REQUESTS = 6'), '头像请求并发上限未与 5173 对齐');
|
||
assert(avatarLoader.includes("new Set(['staff_account', 'user_account'])"), '头像列表资源白名单不正确');
|
||
assert(
|
||
resourcesByName.get('staff_credential').searchFields.map((field) => field.key).join(',') ===
|
||
'credential_type,credential_no',
|
||
'人员资质搜索契约必须包含资质类型和资质编号',
|
||
);
|
||
for (const name of ['delivery_profile', 'user_address', 'wallet_bank']) {
|
||
assert(!(resourcesByName.get(name).searchFields?.length), `${name} 不应显示无效搜索`);
|
||
}
|
||
assert(listPage.includes('v-if="searchEnabled"'), '列表搜索区域未按后端契约控制显示');
|
||
assert(listPage.includes('label="模糊搜索"'), '列表搜索标签未明确说明模糊匹配');
|
||
assert(!listPage.includes('label="关键字"'), '列表仍使用含义不清的关键字标签');
|
||
assert(!listPage.includes('placeholder="关键字段模糊搜索"'), '列表仍使用无意义的通用搜索提示');
|
||
assert(listPage.includes('ensureCredentialContext'), '人员资质列表缺少服务端人员上下文校验');
|
||
assert(listPage.includes("field.key === 'staff_account_identity'"), '人员范围资质列表未隐藏重复人员列');
|
||
assert(recordPage.includes('已锁定,不可更换'), '人员资质独立页未锁定所属配送人员');
|
||
|
||
console.log(`独立资源页面契约通过:详情 ${listResources.length},新建 ${creatable.size},编辑 ${editable.size}`);
|