- 明确合同状态、气瓶归属、停用、报废和重复绑定失败原因 - 根据当前合同过滤可绑定气瓶,排除无效及重复候选项 - 从合同列表进入绑定页时锁定预填合同,防止切换上下文 - 切换通用新建页合同后清空旧气瓶并重新加载候选项 - 增加前后端回归检查并同步中文操作日志
281 lines
9.7 KiB
TypeScript
281 lines
9.7 KiB
TypeScript
/**
|
||
* 功能:协调资源表单中显式启用的父子关联下拉、搜索和保存前校验。
|
||
* 版本:v1.0.0
|
||
*/
|
||
import { Message } from '@arco-design/web-vue';
|
||
import type { ResourceField } from '@/api/resources';
|
||
import {
|
||
linkedRelationFilters,
|
||
linkedRelationValidationMessage,
|
||
optionParentIdentity,
|
||
relationIdentity,
|
||
shouldClearLinkedOption,
|
||
staffOrganizationFilters,
|
||
staffOrganizationValidationMessage,
|
||
} from './resource-relation-linkage-policy';
|
||
import type { ResourceRelations } from './use-resource-relations';
|
||
|
||
type ActiveLinkage = {
|
||
childField: ResourceField;
|
||
parentField?: ResourceField;
|
||
};
|
||
|
||
export function useResourceRelationLinkage(
|
||
form: Record<string, any>,
|
||
relations: ResourceRelations,
|
||
) {
|
||
let active: ActiveLinkage | undefined;
|
||
let organizationStaffField: ResourceField | undefined;
|
||
let initialized = false;
|
||
|
||
function findOption(resource: string, identity: string) {
|
||
return (relations.options[resource] ?? []).find(
|
||
(row) => relationIdentity(row.identity) === identity,
|
||
);
|
||
}
|
||
|
||
function configure(fields: ResourceField[]) {
|
||
const childField = fields.find((field) => field.relationLinkage);
|
||
organizationStaffField = fields.find(
|
||
(field) => field.staffRelation?.organizationScoped,
|
||
);
|
||
if (!childField?.relationLinkage) {
|
||
active = undefined;
|
||
return;
|
||
}
|
||
active = {
|
||
childField,
|
||
parentField: fields.find(
|
||
(field) => field.key === childField.relationLinkage?.parentKey,
|
||
),
|
||
};
|
||
}
|
||
|
||
function staffRequest() {
|
||
const staffIdentity = relationIdentity(
|
||
organizationStaffField ? form[organizationStaffField.key] : '',
|
||
);
|
||
return {
|
||
filters: staffOrganizationFilters(
|
||
relationIdentity(form.gas_basic_identity),
|
||
relationIdentity(form.delivery_basic_identity),
|
||
),
|
||
preserveIdentities: staffIdentity ? [staffIdentity] : [],
|
||
};
|
||
}
|
||
|
||
async function reloadStaffOptions() {
|
||
const field = organizationStaffField;
|
||
if (!field?.relation) return;
|
||
relations.cancelSearch(field.relation);
|
||
await relations.loadField(field, '', staffRequest());
|
||
}
|
||
|
||
/** 组织变化后清理不再匹配的服务人员,并刷新精确范围选项。 */
|
||
async function synchronizeStaff() {
|
||
const field = organizationStaffField;
|
||
if (!field?.relation) return;
|
||
const staffIdentity = relationIdentity(form[field.key]);
|
||
if (staffIdentity) {
|
||
const option =
|
||
findOption(field.relation, staffIdentity) ??
|
||
(await relations.ensure(field.relation, staffIdentity));
|
||
const warning = staffOrganizationValidationMessage(
|
||
relationIdentity(form.gas_basic_identity),
|
||
relationIdentity(form.delivery_basic_identity),
|
||
staffIdentity,
|
||
option,
|
||
);
|
||
if (warning && relationIdentity(form[field.key]) === staffIdentity) {
|
||
form[field.key] = '';
|
||
Message.info(`${warning},已清空原服务人员`);
|
||
}
|
||
}
|
||
await reloadStaffOptions();
|
||
}
|
||
|
||
function childRequest() {
|
||
if (!active?.childField.relationLinkage) return {};
|
||
const linkage = active.childField.relationLinkage;
|
||
const parentIdentity = relationIdentity(form[linkage.parentKey]);
|
||
const childIdentity = relationIdentity(form[active.childField.key]);
|
||
return {
|
||
filters: linkedRelationFilters(parentIdentity, linkage.filterKey),
|
||
preserveIdentities: childIdentity ? [childIdentity] : [],
|
||
};
|
||
}
|
||
|
||
async function reloadChildOptions() {
|
||
const childField = active?.childField;
|
||
const resource = childField?.relation;
|
||
if (!resource) return;
|
||
relations.cancelSearch(resource);
|
||
await relations.loadField(childField, '', childRequest());
|
||
}
|
||
|
||
/** 预加载普通关联项,并单独按父级条件加载启用联动的子选项。 */
|
||
async function preload(fields: ResourceField[]) {
|
||
initialized = false;
|
||
configure(fields);
|
||
if (!active?.childField.relationLinkage || !active.childField.relation) {
|
||
await relations.preload(
|
||
fields.filter((field) => field.key !== organizationStaffField?.key),
|
||
);
|
||
await relations.ensureValues(fields, form);
|
||
await reloadStaffOptions();
|
||
initialized = true;
|
||
return;
|
||
}
|
||
|
||
await relations.preload(
|
||
fields.filter(
|
||
(field) =>
|
||
field.key !== active?.childField.key &&
|
||
field.key !== organizationStaffField?.key,
|
||
),
|
||
);
|
||
const linkage = active.childField.relationLinkage;
|
||
const parentIdentity = relationIdentity(form[linkage.parentKey]);
|
||
const childIdentity = relationIdentity(form[active.childField.key]);
|
||
if (parentIdentity && active.parentField?.relation) {
|
||
await relations.ensure(active.parentField.relation, parentIdentity);
|
||
}
|
||
if (childIdentity) {
|
||
await relations.ensure(active.childField.relation, childIdentity);
|
||
}
|
||
const staffIdentity = relationIdentity(
|
||
organizationStaffField ? form[organizationStaffField.key] : '',
|
||
);
|
||
if (staffIdentity && organizationStaffField?.relation) {
|
||
await relations.ensure(organizationStaffField.relation, staffIdentity);
|
||
}
|
||
await reloadChildOptions();
|
||
await reloadStaffOptions();
|
||
initialized = true;
|
||
|
||
const warning = validationMessage();
|
||
if (warning) Message.warning(`当前组织归属需要确认:${warning}`);
|
||
}
|
||
|
||
async function handleParentChange(parentIdentity: string) {
|
||
if (!active?.childField.relationLinkage || !active.childField.relation)
|
||
return;
|
||
const linkage = active.childField.relationLinkage;
|
||
const childIdentity = relationIdentity(form[active.childField.key]);
|
||
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));
|
||
if (
|
||
relationIdentity(form[linkage.parentKey]) !== parentIdentity ||
|
||
relationIdentity(form[active.childField.key]) !== childIdentity
|
||
) {
|
||
return;
|
||
}
|
||
if (
|
||
shouldClearLinkedOption(parentIdentity, option, linkage.optionParentKey)
|
||
) {
|
||
form[active.childField.key] = '';
|
||
Message.info('所属气站已变更,请重新选择配送点');
|
||
}
|
||
}
|
||
await reloadChildOptions();
|
||
}
|
||
|
||
async function handleChildChange(childIdentity: string) {
|
||
if (!active?.childField.relationLinkage || !active.childField.relation)
|
||
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));
|
||
if (
|
||
!option ||
|
||
relationIdentity(form[active.childField.key]) !== childIdentity
|
||
) {
|
||
return;
|
||
}
|
||
if (linkage.backfillParent) {
|
||
const nextParent = optionParentIdentity(option, linkage.optionParentKey);
|
||
const currentParent = relationIdentity(form[linkage.parentKey]);
|
||
if (nextParent && active.parentField?.relation) {
|
||
await relations.ensure(active.parentField.relation, nextParent);
|
||
if (relationIdentity(form[active.childField.key]) !== childIdentity) {
|
||
return;
|
||
}
|
||
}
|
||
if (currentParent !== nextParent) {
|
||
form[linkage.parentKey] = nextParent;
|
||
if (!nextParent && currentParent) {
|
||
Message.info('平台主管配送点不隶属于气站,已清空所属气站');
|
||
}
|
||
}
|
||
}
|
||
await reloadChildOptions();
|
||
}
|
||
|
||
/** 响应用户主动修改关联字段;初始化回显不会触发自动清理。 */
|
||
async function change(field: ResourceField, value: unknown) {
|
||
if (!initialized || !active?.childField.relationLinkage) return;
|
||
const identity = relationIdentity(value);
|
||
if (field.key === active.childField.relationLinkage.parentKey) {
|
||
await handleParentChange(identity);
|
||
await synchronizeStaff();
|
||
} else if (field.key === active.childField.key) {
|
||
await handleChildChange(identity);
|
||
await synchronizeStaff();
|
||
} else if (field.key === organizationStaffField?.key) {
|
||
await synchronizeStaff();
|
||
}
|
||
}
|
||
|
||
/** 搜索联动子项时始终保留父级过滤和当前选项。 */
|
||
function search(field: ResourceField, keyword: string) {
|
||
if (!field.relation) return;
|
||
if (field.key === active?.childField.key) {
|
||
relations.searchField(field, keyword, childRequest());
|
||
return;
|
||
}
|
||
if (field.key === organizationStaffField?.key) {
|
||
relations.searchField(field, keyword, staffRequest());
|
||
return;
|
||
}
|
||
relations.searchField(field, keyword);
|
||
}
|
||
|
||
/** 返回保存前的父子关系错误,空字符串代表当前组合可提交。 */
|
||
function validationMessage() {
|
||
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);
|
||
const linkedMessage = linkedRelationValidationMessage(
|
||
parentIdentity,
|
||
childIdentity,
|
||
option,
|
||
linkage.optionParentKey,
|
||
);
|
||
if (linkedMessage) return linkedMessage;
|
||
const staffField = organizationStaffField;
|
||
if (!staffField?.relation) return '';
|
||
const staffIdentity = relationIdentity(form[staffField.key]);
|
||
return staffOrganizationValidationMessage(
|
||
parentIdentity,
|
||
childIdentity,
|
||
staffIdentity,
|
||
findOption(staffField.relation, staffIdentity),
|
||
);
|
||
}
|
||
|
||
return { preload, change, search, validationMessage };
|
||
}
|