强化配送订单合同调度约束
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* 功能:定义工作人员关联字段的显式过滤、角色展示与资质来源校验策略。
|
||||
* 版本:v1.0.0
|
||||
* 版本:v1.1.0
|
||||
*/
|
||||
|
||||
export const staffRoleCodes = ['installer', 'delivery', 'operations'] as const;
|
||||
@@ -11,6 +11,8 @@ export type StaffRelationPolicy = {
|
||||
roles: readonly StaffRoleCode[] | 'context';
|
||||
enabledOnly?: boolean;
|
||||
workStatus?: 'on_duty' | 'off_duty';
|
||||
/** 仅展示至少拥有一条启用且未过期资质的工作人员。 */
|
||||
validCredentialOnly?: boolean;
|
||||
lockPrefilled?: boolean;
|
||||
showIdentityCopy?: boolean;
|
||||
organizationScoped?: boolean;
|
||||
@@ -78,6 +80,9 @@ export function staffRelationFilters(
|
||||
if (field.staffRelation.workStatus) {
|
||||
filters.work_status = field.staffRelation.workStatus;
|
||||
}
|
||||
if (field.staffRelation.validCredentialOnly) {
|
||||
filters.valid_credential_only = '1';
|
||||
}
|
||||
return filters;
|
||||
}
|
||||
|
||||
|
||||
@@ -587,7 +587,7 @@ export const resources: ResourceUiDefinition[] = [
|
||||
parentChangeMessage: '配送合同已变更,请重新选择该合同用户的收货地址',
|
||||
},
|
||||
}), f('gasorder_contract_product_identities', { label: '合同气瓶', required: true, type: 'identity-list', listDisplayKey: 'contract_products_summary', listDetailLink: true, emptyText: '未填写', relation: '/gasorder_contract_product', placeholder: '请输入智能气阀名称、设备类型或设备编码搜索', relationOptionDisplay: 'product-name-type', relationEmptyText: '该合同暂无可用气瓶,请先为合同绑定气瓶', relationLinkage: { parentKey: 'gasorder_contract_identity', optionParentKey: '', filterKey: 'contract_identity', filterOnly: true, requiresParent: true, parentChangeMessage: '配送合同已变更,请重新选择该合同可用的气瓶' } }), f('contact_name', { required: true }), f('contact_phone', { required: true }), f('discount_amount'), f('remark')], 'list', [
|
||||
{ name: '分配订单', resource: '/gasorder_basic/:identity/assign', fields: [relation('delivery_basic_identity', '/delivery_basic', true), relation('staff_account_identity', '/staff_account', true, { staffRelation: { roles: ['delivery'], enabledOnly: true, workStatus: 'on_duty' } }), ...reason], visibleFor: { field: 'order_status', values: [16, 18] } },
|
||||
{ name: '分配订单', resource: '/gasorder_basic/:identity/assign', fields: [relation('delivery_basic_identity', '/delivery_basic', true, { label: '配送点', placeholder: '请选择合同履约范围内的配送点', relationFilters: { status: '1' } }), relation('staff_account_identity', '/staff_account', true, { label: '配送人员', placeholder: '请先选择配送点', relationEmptyText: '该配送点暂无在岗且资质有效的配送人员', staffRelation: { roles: ['delivery'], enabledOnly: true, workStatus: 'on_duty', validCredentialOnly: true } }), ...reason], visibleFor: { field: 'order_status', values: [16, 18] } },
|
||||
{ name: '开始罐装', resource: '/gasorder_basic/:identity/filling', fields: reason, visibleFor: { field: 'order_status', values: [18] } },
|
||||
{ name: '待配送', resource: '/gasorder_basic/:identity/ready', fields: reason, visibleFor: { field: 'order_status', values: [19] } },
|
||||
{ name: '开始配送', resource: '/gasorder_basic/:identity/delivering', fields: reason, visibleFor: { field: 'order_status', values: [20] } },
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<!--
|
||||
功能:承载资源详情页中的审核、流转、归属调整和菜单分配等短业务操作。
|
||||
版本:v1.0.0
|
||||
版本:v1.1.0
|
||||
-->
|
||||
<template>
|
||||
<a-modal
|
||||
@@ -21,11 +21,15 @@
|
||||
<a-alert v-if="isProductLifecycleAction" class="action-alert" type="info" show-icon>
|
||||
当前状态:{{ currentProductStatusLabel }}。请选择一个不同的目标状态,服务端会校验检修和订单占用情况。
|
||||
</a-alert>
|
||||
<a-alert v-if="isGasorderAssignmentAction" class="action-alert" type="info" show-icon>
|
||||
{{ assignmentScopeMessage }}
|
||||
</a-alert>
|
||||
<a-form :model="form" layout="vertical">
|
||||
<ResourceFieldForm
|
||||
v-model="form"
|
||||
:fields="actionFields"
|
||||
:required-keys="requiredKeys"
|
||||
:disabled-keys="disabledKeys"
|
||||
:relation-options="relations.options"
|
||||
:relation-loading="relations.loading"
|
||||
@change-relation="changeRelation"
|
||||
@@ -62,6 +66,30 @@ const relations = useResourceRelations();
|
||||
const isProductLifecycleAction = computed(
|
||||
() => props.action?.resource === '/product_info/:identity/lifecycle',
|
||||
);
|
||||
const isGasorderAssignmentAction = computed(
|
||||
() => props.action?.resource === '/gasorder_basic/:identity/assign',
|
||||
);
|
||||
/** 合同指定点始终锁定;无指定点的已分配订单也只能在当前点内改派。 */
|
||||
const lockedAssignmentDeliveryIdentity = computed(() => {
|
||||
return String(props.record.delivery_basic_identity ?? '').trim();
|
||||
});
|
||||
const disabledKeys = computed(() =>
|
||||
isGasorderAssignmentAction.value && lockedAssignmentDeliveryIdentity.value
|
||||
? ['delivery_basic_identity']
|
||||
: [],
|
||||
);
|
||||
const assignmentScopeMessage = computed(() => {
|
||||
if (
|
||||
Number(props.record.order_status) === 16 &&
|
||||
lockedAssignmentDeliveryIdentity.value
|
||||
) {
|
||||
return '配送合同已指定履约配送点,本次只能从该配送点的在岗且资质有效人员中分配。';
|
||||
}
|
||||
if (lockedAssignmentDeliveryIdentity.value) {
|
||||
return '订单已完成配送点分配,本次仅允许在当前配送点内改派配送人员。';
|
||||
}
|
||||
return '配送合同未指定配送点,请先从合同气站直属的启用配送点中选择,再选择该点配送人员。';
|
||||
});
|
||||
const actionFields = computed(() =>
|
||||
(props.action?.fields ?? []).map((field) =>
|
||||
isProductLifecycleAction.value && field.key === 'product_status'
|
||||
@@ -99,13 +127,52 @@ const ownershipKeys = [
|
||||
'user_account_identity',
|
||||
];
|
||||
|
||||
/** 业务动作字段不启用记录页联动,只沿用普通关联搜索。 */
|
||||
/** 为订单分配动作保留履约范围,其余业务动作沿用普通关联搜索。 */
|
||||
function searchRelation(field: ResourceField, keyword: string) {
|
||||
if (isGasorderAssignmentAction.value) {
|
||||
if (field.key === 'delivery_basic_identity') {
|
||||
relations.searchField(field, keyword, {
|
||||
filters: assignmentDeliveryFilters(),
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (field.key === 'staff_account_identity') {
|
||||
const deliveryIdentity = String(
|
||||
form.delivery_basic_identity ?? '',
|
||||
).trim();
|
||||
if (!deliveryIdentity) {
|
||||
relations.clear(field.relation);
|
||||
return;
|
||||
}
|
||||
relations.searchField(field, keyword, {
|
||||
filters: assignmentStaffFilters(deliveryIdentity),
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
relations.searchField(field, keyword);
|
||||
}
|
||||
|
||||
/** 选择智能气阀的新归属时清空其余互斥归属,避免提交非法多重归属。 */
|
||||
/** 处理订单配送点级联及智能气阀互斥归属,避免提交已经失效的关联值。 */
|
||||
function changeRelation(field: ResourceField, value: unknown) {
|
||||
if (
|
||||
isGasorderAssignmentAction.value &&
|
||||
field.key === 'delivery_basic_identity'
|
||||
) {
|
||||
form.staff_account_identity = undefined;
|
||||
const deliveryIdentity = String(value ?? '').trim();
|
||||
const staffField = actionFields.value.find(
|
||||
(item) => item.key === 'staff_account_identity',
|
||||
);
|
||||
if (!staffField || !deliveryIdentity) {
|
||||
relations.clear('/staff_account');
|
||||
return;
|
||||
}
|
||||
void relations.loadField(staffField, '', {
|
||||
filters: assignmentStaffFilters(deliveryIdentity),
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (
|
||||
!isOwnershipAction.value ||
|
||||
!ownershipKeys.includes(field.key) ||
|
||||
@@ -119,6 +186,47 @@ function changeRelation(field: ResourceField, value: unknown) {
|
||||
}
|
||||
}
|
||||
|
||||
/** 将订单履约气站转换为配送点候选接口的精确筛选参数。 */
|
||||
function assignmentDeliveryFilters(): Record<string, string> {
|
||||
const gasIdentity = String(props.record.gas_basic_identity ?? '').trim();
|
||||
return gasIdentity ? { gas_basic_identities: gasIdentity } : {};
|
||||
}
|
||||
|
||||
/** 配送人员必须同时属于订单气站和当前选择的配送点。 */
|
||||
function assignmentStaffFilters(deliveryIdentity: string) {
|
||||
const filters: Record<string, string> = {
|
||||
delivery_basic_identities: deliveryIdentity,
|
||||
};
|
||||
const gasIdentity = String(props.record.gas_basic_identity ?? '').trim();
|
||||
if (gasIdentity) filters.gas_basic_identities = gasIdentity;
|
||||
return filters;
|
||||
}
|
||||
|
||||
/** 按合同和订单快照初始化分配动作,禁止预加载全平台候选。 */
|
||||
async function initializeGasorderAssignment() {
|
||||
const deliveryField = actionFields.value.find(
|
||||
(field) => field.key === 'delivery_basic_identity',
|
||||
);
|
||||
const staffField = actionFields.value.find(
|
||||
(field) => field.key === 'staff_account_identity',
|
||||
);
|
||||
if (!deliveryField || !staffField) return;
|
||||
relations.clear('/delivery_basic');
|
||||
relations.clear('/staff_account');
|
||||
const lockedIdentity = lockedAssignmentDeliveryIdentity.value;
|
||||
if (lockedIdentity) {
|
||||
form.delivery_basic_identity = lockedIdentity;
|
||||
await relations.ensure('/delivery_basic', lockedIdentity);
|
||||
await relations.loadField(staffField, '', {
|
||||
filters: assignmentStaffFilters(lockedIdentity),
|
||||
});
|
||||
return;
|
||||
}
|
||||
await relations.loadField(deliveryField, '', {
|
||||
filters: assignmentDeliveryFilters(),
|
||||
});
|
||||
}
|
||||
|
||||
watch(
|
||||
() => [props.visible, props.action?.name] as const,
|
||||
async ([visible]) => {
|
||||
@@ -128,6 +236,10 @@ watch(
|
||||
? props.record[field.key]
|
||||
: undefined;
|
||||
}
|
||||
if (isGasorderAssignmentAction.value) {
|
||||
await initializeGasorderAssignment();
|
||||
return;
|
||||
}
|
||||
await relations.preload(actionFields.value);
|
||||
if (props.action.resource.includes('/menu')) {
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user