diff --git a/src/components/ChannelSelect.vue b/src/components/ChannelSelect.vue index 257e8ae..df3c37b 100644 --- a/src/components/ChannelSelect.vue +++ b/src/components/ChannelSelect.vue @@ -4,6 +4,7 @@ :value="modelValue" :options="options" :loading="loading" + :disabled="disabled" show-search option-filter-prop="label" :placeholder="placeholder" @@ -20,7 +21,10 @@ import { fetchCoreEnterprisePageApi } from '@/api/baseConfig' defineProps({ modelValue: { type: String, default: undefined }, // 不同页面对"渠道"的业务称呼不一致(如个人开户页面原型称"核心企业"),允许调用方自定义占位文案 - placeholder: { type: String, default: '请选择所属渠道' } + placeholder: { type: String, default: '请选择所属渠道' }, + // 显式接收 disabled,避免误吃到外层 a-form 的整体禁用态(渠道归属本身必须始终可选, + // 不能被"未选择渠道时冻结其他输入框"的联动规则连带锁死) + disabled: { type: Boolean, default: false } }) defineEmits(['update:modelValue']) diff --git a/src/views/base-config/dict/DictItemTree.vue b/src/views/base-config/dict/DictItemTree.vue index bfb6c95..8ce5834 100644 --- a/src/views/base-config/dict/DictItemTree.vue +++ b/src/views/base-config/dict/DictItemTree.vue @@ -139,6 +139,22 @@ function decorate(node, parentId) { const displayData = computed(() => rawData.value.map((node) => decorate(node, null))) +// 同一动态字典类型(dictTypeCode)下,字典项标签(itemLabel)不能重复,唯一性范围是整棵树 +// (不区分层级/父节点),因此需要把树形结构展平后再做重复校验,详见《缺失的后端接口.md》Part 23。 +function flattenTree(nodes) { + const result = [] + const walk = (list) => { + list.forEach((node) => { + result.push(node) + if (node.children && node.children.length) walk(node.children) + }) + } + walk(nodes) + return result +} + +const allItems = computed(() => flattenTree(displayData.value)) + async function loadData() { if (!dictCode.value) return loading.value = true @@ -174,9 +190,23 @@ const form = reactive({ remark: '' }) +// 客户端提前拦截重复标签,减少无效请求;后端仍需做同样校验兜底(并发新增等场景客户端校验无法覆盖), +// 见《缺失的后端接口.md》Part 23 第 133 条。 +async function validateItemLabelUnique(_rule, value) { + if (!value) return Promise.resolve() + const duplicated = allItems.value.some((item) => item.itemLabel === value && item.id !== form.id) + if (duplicated) { + return Promise.reject(new Error('同一动态字典下已存在相同的字典项标签,请修改')) + } + return Promise.resolve() +} + const rules = { itemValue: [{ required: true, message: '请输入字典项值' }], - itemLabel: [{ required: true, message: '请输入字典项标签' }] + itemLabel: [ + { required: true, message: '请输入字典项标签' }, + { validator: validateItemLabelUnique, trigger: 'change' } + ] } const modalTitle = computed(() => { diff --git a/src/views/wallet/enterprise-open/EnterpriseOpenForm.vue b/src/views/wallet/enterprise-open/EnterpriseOpenForm.vue index 91353b6..70397c3 100644 --- a/src/views/wallet/enterprise-open/EnterpriseOpenForm.vue +++ b/src/views/wallet/enterprise-open/EnterpriseOpenForm.vue @@ -1,13 +1,16 @@ + 枚举语义映射待确认、受益人材料证明影像 fileType 编码待确认。 + 2026-08-08 按需求调整:①受益人信息中"是/否"语义字段(actCtrl/priBenfit/seniorMgr/seniorMgrCn/ + actConUpperMarket)提交时改用 'Y'/'N' 而非 '是'/'否';②去除短信验证码校验与发送功能,仅保留 + 手机号采集字段;③未选择"渠道归属"时冻结页面其余输入项,防止在渠道未确定前录入业务数据。 -->