From 2d168b2a7700d81678995073ba3880ea1d4f699e Mon Sep 17 00:00:00 2001 From: dqytc Date: Sun, 9 Aug 2026 19:26:42 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E4=B8=AA=E4=BA=BA=E5=BC=80?= =?UTF-8?q?=E6=88=B7=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/ChannelSelect.vue | 16 ++++-- .../wallet/personal-open/PersonalOpenForm.vue | 50 +++++++++++++++++-- 2 files changed, 60 insertions(+), 6 deletions(-) diff --git a/src/components/ChannelSelect.vue b/src/components/ChannelSelect.vue index df3c37b..e3af8a2 100644 --- a/src/components/ChannelSelect.vue +++ b/src/components/ChannelSelect.vue @@ -10,7 +10,7 @@ :placeholder="placeholder" style="width: 220px" allow-clear - @update:value="$emit('update:modelValue', $event)" + @update:value="handleChange" /> @@ -26,11 +26,21 @@ defineProps({ // 不能被"未选择渠道时冻结其他输入框"的联动规则连带锁死) disabled: { type: Boolean, default: false } }) -defineEmits(['update:modelValue']) +// update:channelName:部分页面(如个人开户 create-draft)需要把渠道名称一起提交给后端, +// 单靠 modelValue(渠道编号)不够,选中项变化时把对应的渠道名称一起回传给调用方, +// 不使用 v-model 双向绑定(避免多出一个未声明的 prop 通过 attrs 落到 a-select 根节点上), +// 调用方按普通事件监听 @update:channel-name 即可。 +const emit = defineEmits(['update:modelValue', 'update:channelName']) const options = ref([]) const loading = ref(false) +function handleChange(value) { + emit('update:modelValue', value) + const opt = options.value.find((o) => o.value === value) + emit('update:channelName', opt?.name || '') +} + async function loadChannelOptions() { loading.value = true try { @@ -42,7 +52,7 @@ async function loadChannelOptions() { options.value = (res.data.data.records || []).map((item) => { const no = item.channelNo || item.enterpriseCode const name = item.channelName || item.enterpriseName - return { label: `${no} - ${name}`, value: no } + return { label: `${no} - ${name}`, value: no, name } }) } } finally { diff --git a/src/views/wallet/personal-open/PersonalOpenForm.vue b/src/views/wallet/personal-open/PersonalOpenForm.vue index dfe96fd..e2ef135 100644 --- a/src/views/wallet/personal-open/PersonalOpenForm.vue +++ b/src/views/wallet/personal-open/PersonalOpenForm.vue @@ -64,7 +64,12 @@ >
- +
@@ -238,6 +243,7 @@ import { queryCardInfoApi } from '@/api/wallet' import { fetchPersonalCustomerDetailApi } from '@/api/customer' +import { fetchOrgListAllApi } from '@/api/system' import { phoneValidatorRule, isValidBankCard } from '@/utils/validators' import { showErrorModal } from '@/utils/errorModal' import { mapOcrGender } from '@/utils/ocrMapping' @@ -249,6 +255,10 @@ const router = useRouter() const formRef = ref(null) const pickerRef = ref(null) const channelNo = ref(undefined) +// 渠道名称:2026-08-09 起 create-draft 请求体新增 channelName 字段,由 ChannelSelect 选中渠道时 +// 通过 update:channel-name 事件回传(渠道列表本身已带 channelName,只是组件对外 v-model 之前只暴露 +// 编号),不是另外调接口查询 +const channelName = ref('') const agreementChecked = ref(false) // 提交前校验未通过时,定位到对应必填项所在区域(部分必填项不是 a-form-item 的 name 字段, @@ -326,9 +336,27 @@ const form = reactive({ // 银行卡号校验通过后由 /api/wallet-account/query-card-info 响应静默回填,不在页面展示, // 仅随提交请求体一起带给后端(create-draft/update 均已支持这两个选填字段,详见《缺失的后端接口.md》) bankName: '', - bankNo: '' + bankNo: '', + // 2026-08-09 起 create-draft 请求体新增 organizationId/organizationName 字段:选择客户时 + // /api/customer-info/personal/list(-detail) 已带 organizationId,organizationName 前端本地没有, + // 需再查一次机构接口按 id 换取名称,不在页面展示,仅随提交请求体一起带给后端 + organizationId: undefined, + organizationName: '' }) +// 机构 id -> 机构名称的映射,懒加载并缓存(项目未提供"按 id 查询单个机构名称"的接口,统一做法是 +// 拉取机构全量列表 /api/organization/list-all 后本地建 map,详见《缺失的后端接口.md》与 +// PersonalList.vue 的同类实现) +const orgNameMap = ref({}) +async function loadOrgNameMap() { + if (Object.keys(orgNameMap.value).length) return orgNameMap.value + const res = await fetchOrgListAllApi() + if (res.data.code === 200) { + orgNameMap.value = Object.fromEntries((res.data.data || []).map((o) => [o.id, o.organizationName])) + } + return orgNameMap.value +} + const effectiveDateValue = computed(() => (form.certificateEffectiveDate ? dayjs(form.certificateEffectiveDate) : undefined)) const isLongTerm = computed( () => !!form.certificateExpiryDate && String(form.certificateExpiryDate).startsWith(CERTIFICATE_LONG_TERM_DATE.slice(0, 10)) @@ -529,6 +557,11 @@ async function handleSelectCustomer(record) { form.gender = detail.gender form.ethnic = detail.ethnicity form.mobilePhone = detail.mobilePhone || form.mobilePhone + // 2026-08-09 起 create-draft 需要一起带上机构ID/机构名称:客户详情已带 organizationId, + // 机构名称本地没有,再查一次机构全量列表本地建 map 换取 + form.organizationId = detail.organizationId + const orgMap = await loadOrgNameMap() + form.organizationName = orgMap[detail.organizationId] || '' // occupation 目前是"个人客户管理"档案里的自由文本字段(与本页面职业字典 job 是两套独立的数据源), // 仅当命中 job 字典里已知的某个叶子 itemValue 时才预选,否则留空由人工重新选择——避免把客户档案 // 里可能不属于当前字典的旧值,静默当成合法选项带入本次开户申请 @@ -560,6 +593,10 @@ async function loadDetail() { } const data = res.data.data || {} channelNo.value = data.channelNo + // 2026-08-09 起假设 detail 响应比照 create-draft 一并补充 channelName/organizationName + // (detail 接口本身仍是前端假设契约,详见《缺失的后端接口.md》Part 11);若后端暂未返回 + // organizationName,兜底用 organizationId 本地查机构全量列表换取 + channelName.value = data.channelName || '' Object.assign(form, { customerId: data.customerId, customerName: data.customerName, @@ -578,8 +615,10 @@ async function loadDetail() { mobilePhone: data.mobilePhone, bankCardNumber: data.bankCardNumber, bankName: data.bankName || '', - bankNo: data.bankNo || '' + bankNo: data.bankNo || '', + organizationId: data.organizationId }) + form.organizationName = data.organizationName || (await loadOrgNameMap())[data.organizationId] || '' applyFileList(data.fileList) detailInfo.applicationStatus = data.applicationStatus detailInfo.failReason = data.failReason @@ -659,8 +698,13 @@ function buildSubmitPayload() { const payload = { accountProperty: '1', channelNo: channelNo.value, + // 2026-08-09 后端 CreateDraftRequest 新增字段:渠道名称(ChannelSelect 选中时回传)、 + // 客户所属机构ID/机构名称(选择客户时从客户详情取机构ID,再查机构全量列表换取名称) + channelName: channelName.value || undefined, customerId: form.customerId, customerName: form.customerName, + organizationId: form.organizationId, + organizationName: form.organizationName || undefined, certificateType: form.certificateType, certificateNumber: form.certificateNumber, certificateEffectiveDate: form.certificateEffectiveDate,