完善合同气瓶绑定引导

This commit is contained in:
czl231
2026-08-14 20:10:09 +08:00
parent 14263416e0
commit 2cff8fb942
7 changed files with 82 additions and 7 deletions

View File

@@ -1,6 +1,6 @@
/**
* 功能:检查配送合同详情页保留可发现的气瓶绑定入口与合同预填参数。
* 版本v1.0.0
* 版本v1.1.0
*/
import assert from 'node:assert/strict';
import { readFileSync } from 'node:fs';
@@ -17,6 +17,10 @@ const resourcesSource = readFileSync(
new URL('../src/api/resources.ts', import.meta.url),
'utf8',
);
const formSource = readFileSync(
new URL('../src/views/resource/ResourceFieldForm.vue', import.meta.url),
'utf8',
);
assert.match(listSource, /definition\.name === 'gasorder_contract' && Number\(record\.contract_status\) === 0/, '绑定入口必须仅展示在草稿合同列表行');
assert.match(listSource, />\s*绑定气瓶\s*</, '草稿合同操作列必须展示“绑定气瓶”按钮');
@@ -27,5 +31,9 @@ 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/, '锁定合同必须以可读名称展示');
assert.match(resourcesSource, /label: '智能气阀'/, '绑定表单不得继续显示“智能气阀唯一标识”');
assert.match(resourcesSource, /该合同用户暂无可绑定的智能气阀/, '空候选必须说明合同用户归属前置条件');
assert.match(resourcesSource, /routeName: 'product-info'/, '空候选必须提供智能气阀管理入口');
assert.match(formSource, /navigateRelationEmptyAction/, '关系空状态必须渲染可执行的站内引导');
console.log('合同气瓶绑定入口检查通过:草稿合同列表行可见,进入后锁定所选合同。');
console.log('合同气瓶绑定入口检查通过:草稿合同可绑定气阀,空候选会解释归属条件并跳转智能气阀管理。');

View File

@@ -95,6 +95,8 @@ export type ResourceField = {
relationAutoSelectKey?: string;
/** 关联候选为空时展示的业务引导。 */
relationEmptyText?: string;
/** 关联候选为空时提供的站内处理入口。 */
relationEmptyAction?: { label: string; routeName: string };
/** 该关联字段每次加载与搜索都必须携带的精确筛选参数。 */
relationFilters?: Record<string, string>;
/** 筛选结果中不存在当前值时立即清空,禁止通过详情补载绕过候选范围。 */
@@ -541,7 +543,10 @@ export const resources: ResourceUiDefinition[] = [
relationInvalidMessage: '所选合同已不是草稿状态,已清空,请重新选择',
relationEmptyText: '暂无可绑定气瓶的草稿合同,请先新建配送合同',
}), relation('product_info_identity', '/product_info', true, {
label: '智能气阀',
placeholder: '请先选择合同,再选择该合同用户可绑定的气瓶',
relationEmptyText: '该合同用户暂无可绑定的智能气阀。请先到“智能气阀管理”将设备归属变更为该用户,并确认设备已启用、未报废。',
relationEmptyAction: { label: '前往智能气阀管理', routeName: 'product-info' },
relationLinkage: {
parentKey: 'gasorder_contract_identity', optionParentKey: '',
filterKey: 'contract_identity', filterOnly: true,

View File

@@ -1,6 +1,6 @@
<!--
功能渲染标准资源的新建编辑和业务动作字段控件
版本v1.3.0
版本v1.4.0
-->
<template>
<div class="field-grid">
@@ -114,7 +114,17 @@
}}
</a-option>
<template #empty>
<div class="relation-empty">{{ relationEmptyText(field) }}</div>
<div class="relation-empty">
<span>{{ relationEmptyText(field) }}</span>
<a-button
v-if="field.relationEmptyAction && !relationRequiresParent(field)"
type="text"
size="mini"
@click.stop="navigateRelationEmptyAction(field)"
>
{{ field.relationEmptyAction.label }}
</a-button>
</div>
</template>
</a-select>
<div
@@ -137,6 +147,7 @@
<script setup lang="ts">
import { computed } from 'vue';
import { useRouter } from 'vue-router';
import { relationOptionLabel } from '@/api/resource-display';
import { dynamicRelationResource, type ResourceField } from '@/api/resources';
import type { ResourceRow } from '@/api/resource-page-rules';
@@ -181,6 +192,7 @@ const emit = defineEmits<{
'preview-attachment': [];
}>();
const model = defineModel<Record<string, any>>({ required: true });
const router = useRouter();
const disabledSet = computed(() => new Set(props.disabledKeys));
function isWide(field: ResourceField) {
@@ -267,6 +279,12 @@ function relationEmptyText(field: ResourceField) {
return field.relationEmptyText ?? '暂无数据';
}
/** 从空候选引导直接进入对应管理页面,避免管理员只能猜测前置操作。 */
function navigateRelationEmptyAction(field: ResourceField) {
if (!field.relationEmptyAction) return;
void router.push({ name: field.relationEmptyAction.routeName });
}
/** 为历史未知编码补充只读选项,避免下拉框退回显示原始值。 */
function selectOptions(field: ResourceField) {
const options = [...(field.options ?? [])];
@@ -309,6 +327,15 @@ function selectOptions(field: ResourceField) {
display: grid;
gap: 6px;
}
.relation-empty {
display: grid;
justify-items: center;
gap: 4px;
padding: 8px 12px;
color: var(--color-text-3);
text-align: center;
white-space: normal;
}
.relation-identity {
display: flex;
gap: 8px;