修复配送订单创建方动态联动
This commit is contained in:
@@ -202,6 +202,8 @@
|
|||||||
|
|
||||||
创建订单时必须提交唯一请求号、有效合同、创建方、用户地址、合同气瓶集合、联系人和联系方式。后端根据合同价格和默认配送费计算订单金额,不接受前端自行决定最终金额。
|
创建订单时必须提交唯一请求号、有效合同、创建方、用户地址、合同气瓶集合、联系人和联系方式。后端根据合同价格和默认配送费计算订单金额,不接受前端自行决定最终金额。
|
||||||
|
|
||||||
|
平台创建订单时,创建方类型支持用户、工作人员、配送站和气站。创建方候选必须根据已选类型分别加载用户账户、工作人员账户、配送站或气站;未选择类型时禁用创建方字段,切换类型时清空原创建方并重新加载候选。候选以用户名或机构名称等业务名称展示,不直接要求管理员识别唯一标识。
|
||||||
|
|
||||||
创建订单页面必须先选择配送合同,收货地址下拉仅展示该合同签约用户的地址。地址选项以完整地址为主文案并标记默认地址;存在默认地址时自动选中,切换合同时清空原地址。若合同用户没有可用地址,页面应明确引导先维护用户地址并禁止提交。
|
创建订单页面必须先选择配送合同,收货地址下拉仅展示该合同签约用户的地址。地址选项以完整地址为主文案并标记默认地址;存在默认地址时自动选中,切换合同时清空原地址。若合同用户没有可用地址,页面应明确引导先维护用户地址并禁止提交。
|
||||||
|
|
||||||
合同气瓶下拉仅展示所选合同中尚未解绑的气瓶,按气瓶类型和气瓶编码排序,并支持按气瓶编码或类型搜索。选项以气瓶类型名称展示;切换合同时清空原选择。若合同没有可用气瓶,页面应引导先为合同绑定气瓶并禁止提交。合同气瓶管理列表仍保留完整绑定和解绑历史。
|
合同气瓶下拉仅展示所选合同中尚未解绑的气瓶,按气瓶类型和气瓶编码排序,并支持按气瓶编码或类型搜索。选项以气瓶类型名称展示;切换合同时清空原选择。若合同没有可用气瓶,页面应引导先为合同绑定气瓶并禁止提交。合同气瓶管理列表仍保留完整绑定和解绑历史。
|
||||||
|
|||||||
49
docs/项目文档_配送订单创建方动态联动_v1.0.md
Normal file
49
docs/项目文档_配送订单创建方动态联动_v1.0.md
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
# 项目文档_配送订单创建方动态联动_v1.0
|
||||||
|
|
||||||
|
## 1. 项目概述
|
||||||
|
|
||||||
|
本次修复平台总后台创建配送订单时“创建方标识”始终显示“暂无数据”的问题。后端已经支持四种创建方,但前端字段只有关系控件类型,没有绑定数据资源,也没有根据创建方类型切换候选。
|
||||||
|
|
||||||
|
## 2. 业务规则
|
||||||
|
|
||||||
|
- 创建方类型支持用户、工作人员、配送站和气站。
|
||||||
|
- 未选择创建方类型时,创建方下拉框保持禁用并提示先选择类型。
|
||||||
|
- 用户对应 `/user_account`。
|
||||||
|
- 工作人员对应 `/staff_account`。
|
||||||
|
- 配送站对应 `/delivery_basic`。
|
||||||
|
- 气站对应 `/gas_basic`。
|
||||||
|
- 切换创建方类型时清空原创建方,防止跨类型提交旧标识。
|
||||||
|
- 候选显示用户名、人员显示名称或机构名称等现有业务字段。
|
||||||
|
- 后端继续校验创建方类型与唯一标识,不修改数据库。
|
||||||
|
|
||||||
|
## 3. 核心文件
|
||||||
|
|
||||||
|
- `frontend/platform_admin/src/api/resources.ts`:声明动态关系配置和四类资源映射。
|
||||||
|
- `frontend/platform_admin/src/views/resource/ResourceFieldForm.vue`:动态资源渲染、父类型禁用和选择事件。
|
||||||
|
- `frontend/platform_admin/src/views/resource/use-resource-relation-linkage.ts`:动态候选加载、搜索与类型切换清理。
|
||||||
|
- `frontend/platform_admin/scripts/check-gasorder-creator-linkage.mjs`:创建方动态联动专项检查。
|
||||||
|
|
||||||
|
## 4. 维护指南
|
||||||
|
|
||||||
|
- 新增创建方类型时必须同时更新后端 `gasorderCreatorModels` 和前端动态资源映射。
|
||||||
|
- 不得把不同模型的唯一标识混放在同一个静态候选列表中。
|
||||||
|
- 切换父类型必须先清空原值,再加载新类型候选。
|
||||||
|
- 动态关系能力是通用扩展,其他多类型主体字段可复用,避免页面级硬编码。
|
||||||
|
|
||||||
|
## 5. 变更记录
|
||||||
|
|
||||||
|
操作时间:2026-08-14
|
||||||
|
|
||||||
|
操作类型:修复、扩展
|
||||||
|
|
||||||
|
影响模块:平台总后台、气体配送订单创建
|
||||||
|
|
||||||
|
操作前状态:创建方标识没有关系资源,选择创建方类型后仍显示“暂无数据”。
|
||||||
|
|
||||||
|
具体操作:增加父字段驱动的动态关系配置,接入候选加载、搜索、禁用和切换清理流程。
|
||||||
|
|
||||||
|
操作后状态:管理员选择创建方类型后可选择对应业务主体,切换类型会清空旧选择。
|
||||||
|
|
||||||
|
验证范围:前端专项检查、类型检查、生产构建和既有资源契约检查。
|
||||||
|
|
||||||
|
风险评估:后端接口和数据库不变;动态关系仅在显式配置字段启用,不影响既有固定关系字段。
|
||||||
@@ -25,6 +25,7 @@
|
|||||||
"gasorder-address:check": "node scripts/check-gasorder-address-linkage.mjs",
|
"gasorder-address:check": "node scripts/check-gasorder-address-linkage.mjs",
|
||||||
"gasorder-contract-candidates:check": "node scripts/check-gasorder-contract-candidates.mjs",
|
"gasorder-contract-candidates:check": "node scripts/check-gasorder-contract-candidates.mjs",
|
||||||
"gasorder-contract-products:check": "node scripts/check-gasorder-contract-product-display.mjs",
|
"gasorder-contract-products:check": "node scripts/check-gasorder-contract-product-display.mjs",
|
||||||
|
"gasorder-creator:check": "node scripts/check-gasorder-creator-linkage.mjs",
|
||||||
"product-ownership:check": "node scripts/check-product-ownership-action.mjs",
|
"product-ownership:check": "node scripts/check-product-ownership-action.mjs",
|
||||||
"product-ownership-display:check": "node scripts/check-product-ownership-display.mjs",
|
"product-ownership-display:check": "node scripts/check-product-ownership-display.mjs",
|
||||||
"product-lifecycle-display:check": "node scripts/check-product-lifecycle-display.mjs",
|
"product-lifecycle-display:check": "node scripts/check-product-lifecycle-display.mjs",
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
/**
|
||||||
|
* 功能:静态检查配送订单创建方类型与业务主体候选的动态联动。
|
||||||
|
* 版本: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 form = readFileSync(new URL('../src/views/resource/ResourceFieldForm.vue', import.meta.url), 'utf8');
|
||||||
|
const linkage = readFileSync(new URL('../src/views/resource/use-resource-relation-linkage.ts', import.meta.url), 'utf8');
|
||||||
|
|
||||||
|
assert.match(resources, /parentKey: 'creator_type'/, '创建方必须由创建方类型驱动');
|
||||||
|
for (const mapping of [
|
||||||
|
"user: '/user_account'",
|
||||||
|
"staff: '/staff_account'",
|
||||||
|
"delivery: '/delivery_basic'",
|
||||||
|
"gas: '/gas_basic'",
|
||||||
|
]) {
|
||||||
|
assert.ok(resources.includes(mapping), `创建方动态资源缺少映射:${mapping}`);
|
||||||
|
}
|
||||||
|
assert.match(resources, /label: '创建方'/, '创建方字段必须使用业务名称');
|
||||||
|
assert.match(resources, /创建方类型已变更,请重新选择创建方/, '切换类型时缺少清空提示');
|
||||||
|
assert.match(form, /field\.dynamicRelation && !relationResource\(field\)/, '未选择类型时必须禁用创建方');
|
||||||
|
assert.match(form, /v-else-if="field\.type === 'select'"[\s\S]*?emit\('change-relation'/, '普通选择框未触发动态联动');
|
||||||
|
assert.match(linkage, /reloadDynamicOptions/, '动态关系候选未接入加载流程');
|
||||||
|
assert.match(linkage, /form\[childField\.key\] = ''/, '切换类型时未清空旧创建方');
|
||||||
|
|
||||||
|
console.log('配送订单创建方检查通过:四类创建方按类型动态加载,切换类型会清空旧值。');
|
||||||
@@ -39,6 +39,14 @@ export type ResourceRelationLinkage = {
|
|||||||
parentChangeMessage?: string;
|
parentChangeMessage?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** 根据父字段值选择关系资源,用于创建方等多类型业务主体。 */
|
||||||
|
export type ResourceDynamicRelation = {
|
||||||
|
parentKey: string;
|
||||||
|
parentLabel: string;
|
||||||
|
resources: Record<string, string>;
|
||||||
|
parentChangeMessage?: string;
|
||||||
|
};
|
||||||
|
|
||||||
export type ResourceField = {
|
export type ResourceField = {
|
||||||
key: string;
|
key: string;
|
||||||
label: string;
|
label: string;
|
||||||
@@ -60,6 +68,8 @@ export type ResourceField = {
|
|||||||
readonlyOnCreate?: boolean;
|
readonlyOnCreate?: boolean;
|
||||||
unknownValueLabel?: string;
|
unknownValueLabel?: string;
|
||||||
relationLinkage?: ResourceRelationLinkage;
|
relationLinkage?: ResourceRelationLinkage;
|
||||||
|
/** 父字段值决定实际关系资源,未选择父字段时不加载候选。 */
|
||||||
|
dynamicRelation?: ResourceDynamicRelation;
|
||||||
/** 关联选项优先使用的业务展示字段。 */
|
/** 关联选项优先使用的业务展示字段。 */
|
||||||
relationOptionLabelKey?: string;
|
relationOptionLabelKey?: string;
|
||||||
/** 该字段为真时,在关联选项后追加“默认地址”。 */
|
/** 该字段为真时,在关联选项后追加“默认地址”。 */
|
||||||
@@ -523,7 +533,7 @@ export const resources: ResourceUiDefinition[] = [
|
|||||||
{ name: '解绑气瓶', resource: '/gasorder_contract_product/:identity/unbind', danger: true, fields: reason },
|
{ name: '解绑气瓶', resource: '/gasorder_contract_product/:identity/unbind', danger: true, fields: reason },
|
||||||
]),
|
]),
|
||||||
define('gasorder_contract_revision', '合同修订记录', 'readonly', []),
|
define('gasorder_contract_revision', '合同修订记录', 'readonly', []),
|
||||||
define('gasorder_basic', '气体配送订单', 'append_only', [f('request_no', { required: true }), relation('gasorder_contract_identity', '/gasorder_contract', true, { label: '配送合同', placeholder: '请选择当前可履约的生效合同', relationFilters: { candidate: 'order' }, relationStrictFilter: true, relationInvalidMessage: '所选配送合同已不可履约,已清空,请重新选择', relationEmptyText: '暂无可下单的生效合同,请先启用或续签配送合同' }), f('creator_type', { required: true, type: 'select', options: resourceSearchEnumOptions('gasorder_basic', 'creator_type') }), f('creator_identity', { required: true }), relation('user_address_identity', '/user_address', true, {
|
define('gasorder_basic', '气体配送订单', 'append_only', [f('request_no', { required: true }), relation('gasorder_contract_identity', '/gasorder_contract', true, { label: '配送合同', placeholder: '请选择当前可履约的生效合同', relationFilters: { candidate: 'order' }, relationStrictFilter: true, relationInvalidMessage: '所选配送合同已不可履约,已清空,请重新选择', relationEmptyText: '暂无可下单的生效合同,请先启用或续签配送合同' }), f('creator_type', { required: true, type: 'select', options: resourceSearchEnumOptions('gasorder_basic', 'creator_type') }), f('creator_identity', { label: '创建方', required: true, placeholder: '请选择创建方', relationEmptyText: '当前类型暂无可用的创建方数据', dynamicRelation: { parentKey: 'creator_type', parentLabel: '创建方类型', resources: { user: '/user_account', staff: '/staff_account', delivery: '/delivery_basic', gas: '/gas_basic' }, parentChangeMessage: '创建方类型已变更,请重新选择创建方' } }), relation('user_address_identity', '/user_address', true, {
|
||||||
label: '收货地址', placeholder: '请先选择配送合同,再选择该合同用户的收货地址',
|
label: '收货地址', placeholder: '请先选择配送合同,再选择该合同用户的收货地址',
|
||||||
relationOptionLabelKey: 'address', relationOptionDefaultKey: 'is_default',
|
relationOptionLabelKey: 'address', relationOptionDefaultKey: 'is_default',
|
||||||
relationAutoSelectKey: 'is_default', relationEmptyText: '该合同用户暂无收货地址,请先维护用户地址',
|
relationAutoSelectKey: 'is_default', relationEmptyText: '该合同用户暂无收货地址,请先维护用户地址',
|
||||||
@@ -619,3 +629,14 @@ export function getResource(resourcePath: string): ResourceUiDefinition {
|
|||||||
if (!definition) throw new Error(`未知资源:${resourcePath}`);
|
if (!definition) throw new Error(`未知资源:${resourcePath}`);
|
||||||
return definition;
|
return definition;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 返回动态关系字段当前应使用的资源;父值为空或未知时返回空字符串。 */
|
||||||
|
export function dynamicRelationResource(
|
||||||
|
field: ResourceField,
|
||||||
|
values: Record<string, unknown>,
|
||||||
|
) {
|
||||||
|
const dynamic = field.dynamicRelation;
|
||||||
|
if (!dynamic) return field.relation ?? '';
|
||||||
|
const parentValue = String(values[dynamic.parentKey] ?? '').trim();
|
||||||
|
return dynamic.resources[parentValue] ?? '';
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<!--
|
<!--
|
||||||
功能:渲染标准资源的新建、编辑和业务动作字段控件。
|
功能:渲染标准资源的新建、编辑和业务动作字段控件。
|
||||||
版本:v1.1.0
|
版本:v1.2.0
|
||||||
-->
|
-->
|
||||||
<template>
|
<template>
|
||||||
<div class="field-grid">
|
<div class="field-grid">
|
||||||
@@ -71,6 +71,7 @@
|
|||||||
v-model="model[field.key]"
|
v-model="model[field.key]"
|
||||||
:disabled="disabledSet.has(field.key)"
|
:disabled="disabledSet.has(field.key)"
|
||||||
allow-clear
|
allow-clear
|
||||||
|
@change="(value: unknown) => emit('change-relation', field, value)"
|
||||||
>
|
>
|
||||||
<a-option v-for="option in selectOptions(field)" :key="option.value" :value="option.value">
|
<a-option v-for="option in selectOptions(field)" :key="option.value" :value="option.value">
|
||||||
{{ option.label }}
|
{{ option.label }}
|
||||||
@@ -93,14 +94,14 @@
|
|||||||
:disabled="disabledSet.has(field.key) || relationRequiresParent(field)"
|
:disabled="disabledSet.has(field.key) || relationRequiresParent(field)"
|
||||||
:multiple="field.type === 'identity-list'"
|
:multiple="field.type === 'identity-list'"
|
||||||
:placeholder="relationPlaceholder(field)"
|
:placeholder="relationPlaceholder(field)"
|
||||||
:loading="relationLoading[field.relation ?? '']"
|
:loading="relationLoading[relationResource(field)]"
|
||||||
allow-clear
|
allow-clear
|
||||||
allow-search
|
allow-search
|
||||||
@change="(value: unknown) => emit('change-relation', field, value)"
|
@change="(value: unknown) => emit('change-relation', field, value)"
|
||||||
@search="(value: string) => emit('search-relation', field, value)"
|
@search="(value: string) => emit('search-relation', field, value)"
|
||||||
>
|
>
|
||||||
<a-option
|
<a-option
|
||||||
v-for="option in relationOptions[field.relation ?? ''] ?? []"
|
v-for="option in relationOptions[relationResource(field)] ?? []"
|
||||||
:key="String(option.identity)"
|
:key="String(option.identity)"
|
||||||
:value="String(option.identity)"
|
:value="String(option.identity)"
|
||||||
>
|
>
|
||||||
@@ -131,7 +132,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed } from 'vue';
|
import { computed } from 'vue';
|
||||||
import { relationOptionLabel } from '@/api/resource-display';
|
import { relationOptionLabel } from '@/api/resource-display';
|
||||||
import type { ResourceField } from '@/api/resources';
|
import { dynamicRelationResource, type ResourceField } from '@/api/resources';
|
||||||
import type { ResourceRow } from '@/api/resource-page-rules';
|
import type { ResourceRow } from '@/api/resource-page-rules';
|
||||||
import type { PlatformRole } from '@/api/platform';
|
import type { PlatformRole } from '@/api/platform';
|
||||||
import IdentityText from '@/components/IdentityText.vue';
|
import IdentityText from '@/components/IdentityText.vue';
|
||||||
@@ -188,24 +189,33 @@ function isWide(field: ResourceField) {
|
|||||||
function readonlyRelationLabel(field: ResourceField) {
|
function readonlyRelationLabel(field: ResourceField) {
|
||||||
const identity = String(model.value[field.key] ?? '');
|
const identity = String(model.value[field.key] ?? '');
|
||||||
if (!identity) return field.emptyText ?? '暂未分配';
|
if (!identity) return field.emptyText ?? '暂未分配';
|
||||||
const option = (props.relationOptions[field.relation ?? ''] ?? []).find(
|
const option = (props.relationOptions[relationResource(field)] ?? []).find(
|
||||||
(item) => String(item.identity ?? '') === identity,
|
(item) => String(item.identity ?? '') === identity,
|
||||||
);
|
);
|
||||||
return option ? relationOptionLabel(field, option) : identity;
|
return option ? relationOptionLabel(field, option) : identity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 解析固定或由父字段动态决定的关系资源。 */
|
||||||
|
function relationResource(field: ResourceField) {
|
||||||
|
return dynamicRelationResource(field, model.value);
|
||||||
|
}
|
||||||
|
|
||||||
/** 父级尚未选择时禁用联动下拉,避免用户误以为可以跨合同选择。 */
|
/** 父级尚未选择时禁用联动下拉,避免用户误以为可以跨合同选择。 */
|
||||||
function relationRequiresParent(field: ResourceField) {
|
function relationRequiresParent(field: ResourceField) {
|
||||||
const linkage = field.relationLinkage;
|
const linkage = field.relationLinkage;
|
||||||
return Boolean(
|
return Boolean(
|
||||||
linkage?.requiresParent &&
|
(linkage?.requiresParent &&
|
||||||
!String(model.value[linkage.parentKey] ?? '').trim(),
|
!String(model.value[linkage.parentKey] ?? '').trim()) ||
|
||||||
|
(field.dynamicRelation && !relationResource(field)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 父级未选择时直接在控件内提示操作顺序,选择后恢复字段搜索提示。 */
|
/** 父级未选择时直接在控件内提示操作顺序,选择后恢复字段搜索提示。 */
|
||||||
function relationPlaceholder(field: ResourceField) {
|
function relationPlaceholder(field: ResourceField) {
|
||||||
if (!relationRequiresParent(field)) return field.placeholder;
|
if (!relationRequiresParent(field)) return field.placeholder;
|
||||||
|
if (field.dynamicRelation) {
|
||||||
|
return `请先选择${field.dynamicRelation.parentLabel}`;
|
||||||
|
}
|
||||||
return field.relationLinkage?.parentKey === 'gasorder_contract_identity'
|
return field.relationLinkage?.parentKey === 'gasorder_contract_identity'
|
||||||
? '请先选择配送合同'
|
? '请先选择配送合同'
|
||||||
: '请先选择上级数据';
|
: '请先选择上级数据';
|
||||||
@@ -214,6 +224,9 @@ function relationPlaceholder(field: ResourceField) {
|
|||||||
/** 根据父级和候选状态给出明确的关联选择引导。 */
|
/** 根据父级和候选状态给出明确的关联选择引导。 */
|
||||||
function relationEmptyText(field: ResourceField) {
|
function relationEmptyText(field: ResourceField) {
|
||||||
if (relationRequiresParent(field)) {
|
if (relationRequiresParent(field)) {
|
||||||
|
if (field.dynamicRelation) {
|
||||||
|
return `请先选择${field.dynamicRelation.parentLabel}`;
|
||||||
|
}
|
||||||
const parentName =
|
const parentName =
|
||||||
field.relationLinkage?.parentKey === 'gasorder_contract_identity'
|
field.relationLinkage?.parentKey === 'gasorder_contract_identity'
|
||||||
? '配送合同'
|
? '配送合同'
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
/**
|
/**
|
||||||
* 功能:协调资源表单中显式启用的多组父子关联下拉、搜索和保存前校验。
|
* 功能:协调资源表单中显式启用的多组父子关联下拉、搜索和保存前校验。
|
||||||
* 版本:v1.1.0
|
* 版本:v1.2.0
|
||||||
*/
|
*/
|
||||||
import { Message } from '@arco-design/web-vue';
|
import { Message } from '@arco-design/web-vue';
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import type { ResourceField } from '@/api/resources';
|
import { dynamicRelationResource, type ResourceField } from '@/api/resources';
|
||||||
import {
|
import {
|
||||||
linkedRelationFilters,
|
linkedRelationFilters,
|
||||||
linkedRelationValidationMessage,
|
linkedRelationValidationMessage,
|
||||||
@@ -52,6 +52,25 @@ export function useResourceRelationLinkage(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 为动态关系字段补入当前父值对应的实际资源。 */
|
||||||
|
function resolvedField(field: ResourceField) {
|
||||||
|
const resource = dynamicRelationResource(field, form);
|
||||||
|
return resource && resource !== field.relation
|
||||||
|
? { ...field, relation: resource }
|
||||||
|
: field;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 加载由父字段类型决定的关系候选。 */
|
||||||
|
async function reloadDynamicOptions(field: ResourceField) {
|
||||||
|
const resolved = resolvedField(field);
|
||||||
|
if (!resolved.relation) return;
|
||||||
|
const identity = relationIdentity(form[field.key]);
|
||||||
|
relations.cancelSearch(resolved.relation);
|
||||||
|
await relations.loadField(resolved, '', {
|
||||||
|
preserveIdentities: identity ? [identity] : [],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function staffRequest() {
|
function staffRequest() {
|
||||||
const staffIdentity = relationIdentity(
|
const staffIdentity = relationIdentity(
|
||||||
organizationStaffField ? form[organizationStaffField.key] : '',
|
organizationStaffField ? form[organizationStaffField.key] : '',
|
||||||
@@ -147,14 +166,22 @@ export function useResourceRelationLinkage(
|
|||||||
fields.filter(
|
fields.filter(
|
||||||
(field) =>
|
(field) =>
|
||||||
!linkedChildKeys.has(field.key) &&
|
!linkedChildKeys.has(field.key) &&
|
||||||
field.key !== organizationStaffField?.key,
|
field.key !== organizationStaffField?.key &&
|
||||||
|
!field.dynamicRelation,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
await relations.ensureValues(
|
await relations.ensureValues(
|
||||||
fields.filter((field) => !field.relationStrictFilter),
|
fields.filter(
|
||||||
|
(field) => !field.relationStrictFilter && !field.dynamicRelation,
|
||||||
|
),
|
||||||
form,
|
form,
|
||||||
);
|
);
|
||||||
await Promise.all(active.map((item) => reloadChildOptions(item)));
|
await Promise.all(active.map((item) => reloadChildOptions(item)));
|
||||||
|
await Promise.all(
|
||||||
|
fields
|
||||||
|
.filter((field) => field.dynamicRelation)
|
||||||
|
.map((field) => reloadDynamicOptions(field)),
|
||||||
|
);
|
||||||
await reloadStaffOptions();
|
await reloadStaffOptions();
|
||||||
clearInvalidStrictSelections();
|
clearInvalidStrictSelections();
|
||||||
initialized = true;
|
initialized = true;
|
||||||
@@ -263,6 +290,20 @@ export function useResourceRelationLinkage(
|
|||||||
async function change(field: ResourceField, value: unknown) {
|
async function change(field: ResourceField, value: unknown) {
|
||||||
if (!initialized) return;
|
if (!initialized) return;
|
||||||
const identity = relationIdentity(value);
|
const identity = relationIdentity(value);
|
||||||
|
const dynamicChildren = configuredFields.value.filter(
|
||||||
|
(item) => item.dynamicRelation?.parentKey === field.key,
|
||||||
|
);
|
||||||
|
for (const childField of dynamicChildren) {
|
||||||
|
const previousIdentity = relationIdentity(form[childField.key]);
|
||||||
|
form[childField.key] = '';
|
||||||
|
await reloadDynamicOptions(childField);
|
||||||
|
if (previousIdentity) {
|
||||||
|
Message.info(
|
||||||
|
childField.dynamicRelation?.parentChangeMessage ??
|
||||||
|
'关联类型已变更,请重新选择关联数据',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
const parentLinkages = active.filter(
|
const parentLinkages = active.filter(
|
||||||
(item) => item.childField.relationLinkage?.parentKey === field.key,
|
(item) => item.childField.relationLinkage?.parentKey === field.key,
|
||||||
);
|
);
|
||||||
@@ -282,22 +323,23 @@ export function useResourceRelationLinkage(
|
|||||||
|
|
||||||
/** 搜索联动子项时始终保留对应父级过滤和当前选项。 */
|
/** 搜索联动子项时始终保留对应父级过滤和当前选项。 */
|
||||||
function search(field: ResourceField, keyword: string) {
|
function search(field: ResourceField, keyword: string) {
|
||||||
if (!field.relation) return;
|
const resolved = resolvedField(field);
|
||||||
|
if (!resolved.relation) return;
|
||||||
const linkageItem = active.find((item) => item.childField.key === field.key);
|
const linkageItem = active.find((item) => item.childField.key === field.key);
|
||||||
if (linkageItem) {
|
if (linkageItem) {
|
||||||
const linkage = linkageItem.childField.relationLinkage;
|
const linkage = linkageItem.childField.relationLinkage;
|
||||||
if (linkage?.requiresParent && !relationIdentity(form[linkage.parentKey])) {
|
if (linkage?.requiresParent && !relationIdentity(form[linkage.parentKey])) {
|
||||||
relations.clear(field.relation);
|
relations.clear(resolved.relation);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
relations.searchField(field, keyword, childRequest(linkageItem));
|
relations.searchField(resolved, keyword, childRequest(linkageItem));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (field.key === organizationStaffField?.key) {
|
if (field.key === organizationStaffField?.key) {
|
||||||
relations.searchField(field, keyword, staffRequest());
|
relations.searchField(resolved, keyword, staffRequest());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
relations.searchField(field, keyword);
|
relations.searchField(resolved, keyword);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 返回保存前的父子关系错误,空字符串代表当前组合可提交。 */
|
/** 返回保存前的父子关系错误,空字符串代表当前组合可提交。 */
|
||||||
@@ -331,11 +373,12 @@ export function useResourceRelationLinkage(
|
|||||||
function unavailableMessage() {
|
function unavailableMessage() {
|
||||||
for (const field of configuredFields.value) {
|
for (const field of configuredFields.value) {
|
||||||
const linkage = field.relationLinkage;
|
const linkage = field.relationLinkage;
|
||||||
|
const resource = dynamicRelationResource(field, form);
|
||||||
if (
|
if (
|
||||||
!field.required ||
|
!field.required ||
|
||||||
!field.relation ||
|
!resource ||
|
||||||
!field.relationEmptyText ||
|
!field.relationEmptyText ||
|
||||||
relations.loading[field.relation]
|
relations.loading[resource]
|
||||||
) {
|
) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -345,7 +388,7 @@ export function useResourceRelationLinkage(
|
|||||||
) {
|
) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ((relations.options[field.relation] ?? []).length === 0) {
|
if ((relations.options[resource] ?? []).length === 0) {
|
||||||
return field.relationEmptyText;
|
return field.relationEmptyText;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user