完善合同气瓶绑定约束与候选过滤
- 明确合同状态、气瓶归属、停用、报废和重复绑定失败原因 - 根据当前合同过滤可绑定气瓶,排除无效及重复候选项 - 从合同列表进入绑定页时锁定预填合同,防止切换上下文 - 切换通用新建页合同后清空旧气瓶并重新加载候选项 - 增加前后端回归检查并同步中文操作日志
This commit is contained in:
@@ -18,6 +18,7 @@
|
||||
"avatar-retry:check": "node scripts/check-avatar-upload-cache.mjs",
|
||||
"contract-attachment:check": "node scripts/check-contract-attachment-control.mjs",
|
||||
"contract-product-entry:check": "node scripts/check-contract-product-entry.mjs",
|
||||
"contract-product-filter:check": "node scripts/check-contract-product-filter.mjs",
|
||||
"staff-organization:check": "node scripts/check-staff-organization-linkage.mjs",
|
||||
"staff-relations:check": "node scripts/check-staff-relation-policy.mjs",
|
||||
"user-address-display:check": "node scripts/check-user-address-relation-display.mjs",
|
||||
|
||||
@@ -13,6 +13,10 @@ const detailSource = readFileSync(
|
||||
new URL('../src/views/resource/ResourceRecordPage.vue', import.meta.url),
|
||||
'utf8',
|
||||
);
|
||||
const resourcesSource = readFileSync(
|
||||
new URL('../src/api/resources.ts', import.meta.url),
|
||||
'utf8',
|
||||
);
|
||||
|
||||
assert.match(listSource, /definition\.name === 'gasorder_contract' && Number\(record\.contract_status\) === 0/, '绑定入口必须仅展示在草稿合同列表行');
|
||||
assert.match(listSource, />\s*绑定气瓶\s*</, '草稿合同操作列必须展示“绑定气瓶”按钮');
|
||||
@@ -21,5 +25,7 @@ assert.match(listSource, /relation_key: 'gasorder_contract_identity'/, '绑定
|
||||
assert.match(listSource, /owner_identity: String\(row\.identity \?\? ''\)/, '绑定入口必须预填所选合同唯一标识');
|
||||
assert.match(listSource, /return_to: route\.fullPath/, '绑定完成后必须支持返回合同列表');
|
||||
assert.doesNotMatch(detailSource, />\s*绑定气瓶\s*</, '合同详情页不应继续展示绑定按钮');
|
||||
assert.match(detailSource, /definition\.value\.name === 'gasorder_contract_product'[\s\S]*field\.key === 'gasorder_contract_identity'[\s\S]*route\.query\.relation_key === 'gasorder_contract_identity'[\s\S]*Boolean\(route\.query\.owner_identity\)/, '从合同列表进入时必须锁定预填合同');
|
||||
assert.match(resourcesSource, /readonlyRelationText: true, displayRelationLabel: true/, '锁定合同必须以可读名称展示');
|
||||
|
||||
console.log('合同气瓶绑定入口检查通过:仅草稿合同列表行可见,已启用合同和详情页均隐藏。');
|
||||
console.log('合同气瓶绑定入口检查通过:仅草稿合同列表行可见,进入后锁定所选合同。');
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* 功能:检查合同气瓶表单按当前合同加载可绑定气瓶。
|
||||
* 版本:v1.0.0
|
||||
*/
|
||||
import assert from 'node:assert/strict';
|
||||
import { readFileSync } from 'node:fs';
|
||||
|
||||
const resources = readFileSync(new URL('../src/api/resources.ts', import.meta.url), 'utf8');
|
||||
const linkage = readFileSync(new URL('../src/views/resource/use-resource-relation-linkage.ts', import.meta.url), 'utf8');
|
||||
|
||||
assert.match(resources, /filterKey: 'contract_identity', filterOnly: true/, '气瓶字段必须按当前合同筛选');
|
||||
assert.match(resources, /请先选择合同,再选择该合同用户可绑定的气瓶/, '气瓶字段必须解释筛选范围');
|
||||
assert.match(linkage, /if \(linkage\.filterOnly\) return ''/, '纯筛选联动不得执行父标识校验');
|
||||
|
||||
console.log('合同气瓶候选过滤检查通过:气瓶下拉按当前合同加载可绑定项。');
|
||||
@@ -31,6 +31,8 @@ export type ResourceRelationLinkage = {
|
||||
optionParentKey: string;
|
||||
filterKey: string;
|
||||
backfillParent?: boolean;
|
||||
/** 仅使用父字段筛选候选项,不校验候选项中的父标识。 */
|
||||
filterOnly?: boolean;
|
||||
};
|
||||
|
||||
export type ResourceField = {
|
||||
@@ -468,7 +470,15 @@ export const resources: ResourceUiDefinition[] = [
|
||||
{ name: '续签合同', resource: '/gasorder_contract/:identity/renew', fields: [f('effective_at', { required: true }), f('expired_at'), ...reason], visibleFor: { field: 'contract_status', values: [11, 12] } },
|
||||
{ name: '终止合同', resource: '/gasorder_contract/:identity/terminate', danger: true, fields: reason, visibleFor: { field: 'contract_status', values: [11] } },
|
||||
], { canCreate: true, canEdit: true }),
|
||||
define('gasorder_contract_product', '合同气瓶', 'append_only', [relation('gasorder_contract_identity', '/gasorder_contract', true), relation('product_info_identity', '/product_info', true), f('unit_price')], 'list', [
|
||||
define('gasorder_contract_product', '合同气瓶', 'append_only', [relation('gasorder_contract_identity', '/gasorder_contract', true, {
|
||||
readonlyRelationText: true, displayRelationLabel: true,
|
||||
}), relation('product_info_identity', '/product_info', true, {
|
||||
placeholder: '请先选择合同,再选择该合同用户可绑定的气瓶',
|
||||
relationLinkage: {
|
||||
parentKey: 'gasorder_contract_identity', optionParentKey: '',
|
||||
filterKey: 'contract_identity', filterOnly: true,
|
||||
},
|
||||
}), f('unit_price')], 'list', [
|
||||
{ name: '解绑气瓶', resource: '/gasorder_contract_product/:identity/unbind', danger: true, fields: reason },
|
||||
]),
|
||||
define('gasorder_contract_revision', '合同修订记录', 'readonly', []),
|
||||
|
||||
@@ -301,7 +301,11 @@ const readonlyKeys = computed(() =>
|
||||
.filter(
|
||||
(field) =>
|
||||
field.readonlyOnCreate ||
|
||||
(field.staffRelation?.lockPrefilled && Boolean(form[field.key])),
|
||||
(field.staffRelation?.lockPrefilled && Boolean(form[field.key])) ||
|
||||
(definition.value.name === 'gasorder_contract_product' &&
|
||||
field.key === 'gasorder_contract_identity' &&
|
||||
route.query.relation_key === 'gasorder_contract_identity' &&
|
||||
Boolean(route.query.owner_identity)),
|
||||
)
|
||||
.map((field) => field.key)
|
||||
: mode.value === 'edit'
|
||||
|
||||
@@ -162,7 +162,11 @@ export function useResourceRelationLinkage(
|
||||
return;
|
||||
const linkage = active.childField.relationLinkage;
|
||||
const childIdentity = relationIdentity(form[active.childField.key]);
|
||||
if (childIdentity) {
|
||||
if (linkage.filterOnly && childIdentity) {
|
||||
form[active.childField.key] = '';
|
||||
Message.info('合同已变更,请重新选择该合同可绑定的气瓶');
|
||||
}
|
||||
if (childIdentity && !linkage.filterOnly) {
|
||||
const option =
|
||||
findOption(active.childField.relation, childIdentity) ??
|
||||
(await relations.ensure(active.childField.relation, childIdentity));
|
||||
@@ -187,6 +191,7 @@ export function useResourceRelationLinkage(
|
||||
return;
|
||||
const linkage = active.childField.relationLinkage;
|
||||
if (!childIdentity) return;
|
||||
if (linkage.filterOnly) return;
|
||||
const option =
|
||||
findOption(active.childField.relation, childIdentity) ??
|
||||
(await relations.ensure(active.childField.relation, childIdentity));
|
||||
@@ -249,6 +254,7 @@ export function useResourceRelationLinkage(
|
||||
if (!active?.childField.relationLinkage || !active.childField.relation)
|
||||
return '';
|
||||
const linkage = active.childField.relationLinkage;
|
||||
if (linkage.filterOnly) return '';
|
||||
const parentIdentity = relationIdentity(form[linkage.parentKey]);
|
||||
const childIdentity = relationIdentity(form[active.childField.key]);
|
||||
const option = findOption(active.childField.relation, childIdentity);
|
||||
|
||||
Reference in New Issue
Block a user