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,