feat: 新增企业客户新增/编辑/查看表单页

main
halo 2026-07-09 21:39:00 +08:00
parent 3e3a2097a3
commit 801cadbcc4
1 changed files with 275 additions and 0 deletions

View File

@ -0,0 +1,275 @@
<!-- src/views/customer/enterprise/EnterpriseForm.vue -->
<template>
<div class="enterprise-customer-form-page">
<a-page-header :title="pageTitle" @back="goBack" />
<a-card>
<a-form ref="formRef" layout="vertical" :model="form" :rules="rules" :disabled="isDetail">
<a-form-item v-if="!isDetail" label="所属渠道" required>
<ChannelSelect v-model:model-value="channelNo" />
</a-form-item>
<a-form-item label="营业执照照片">
<LicenseUpload :channel-no="channelNo" v-model:file-no="form.businessLicenseFileNo" />
<div v-if="isEdit" class="hint">,</div>
</a-form-item>
<a-form-item label="所属机构" name="organizationId">
<OrgTreeSelect v-model="form.organizationId" placeholder="请选择所属机构" />
</a-form-item>
<a-form-item label="企业名称" name="enterpriseName">
<a-input v-model:value="form.enterpriseName" placeholder="请输入企业名称" />
</a-form-item>
<a-form-item label="证件类型">
<a-input value="营业执照" disabled />
</a-form-item>
<a-form-item label="营业执照号" name="businessLicense">
<a-input v-model:value="form.businessLicense" placeholder="请输入营业执照号" />
</a-form-item>
<a-form-item label="证件生效日" name="certificateEffectiveDate">
<a-date-picker v-model:value="effectiveDateValue" style="width: 100%" value-format="YYYY-MM-DD" />
</a-form-item>
<a-form-item label="证件到期日" name="certificateExpiryDate">
<a-date-picker v-model:value="expiryDateValue" style="width: 100%" value-format="YYYY-MM-DD" />
<div v-if="isExpired" class="expired-hint">,</div>
</a-form-item>
<a-form-item label="手机号码" name="mobilePhone">
<a-input v-model:value="form.mobilePhone" placeholder="请输入11位手机号" />
</a-form-item>
<a-form-item label="证件地址" name="certificateAddress">
<a-input v-model:value="form.certificateAddress" placeholder="请输入详细地址" />
</a-form-item>
<a-form-item label="经营范围" name="businessScope">
<a-textarea v-model:value="form.businessScope" placeholder="请输入经营范围" :rows="3" />
</a-form-item>
<a-form-item label="法定代表人">
<a-space>
<span v-if="legalRepName">{{ legalRepName }}</span>
<a-button v-if="!isDetail" @click="openLegalRepPicker"></a-button>
</a-space>
</a-form-item>
<a-form-item v-if="isCreate" label="股东高管信息">
<a-table :columns="relatedPersonColumns" :data-source="relatedPersonList" :pagination="false" row-key="individualId">
<template #bodyCell="{ column, record, index }">
<template v-if="column.dataIndex === 'customerName'">{{ record.customerName }}</template>
<template v-else-if="column.dataIndex === 'relatedType'">
<a-select v-model:value="record.relatedType" style="width: 140px">
<a-select-option value="SHAREHOLDER">股东</a-select-option>
<a-select-option value="EXECUTIVE">高管</a-select-option>
<a-select-option value="BENEFICIARY_OWNER">受益所有人</a-select-option>
</a-select>
</template>
<template v-else-if="column.dataIndex === 'certificateNumber'">{{ record.certificateNumber }}</template>
<template v-else-if="column.dataIndex === 'action'">
<a @click="removeRelatedPerson(index)"></a>
</template>
</template>
</a-table>
<a-button style="margin-top: 8px" @click="openRelatedPersonPicker">/</a-button>
</a-form-item>
<a-form-item v-else label="股东高管信息">
<div class="hint">股东高管信息仅支持新增时登记,当前接口不支持查询或修改,如需变更请联系技术支持核实数据</div>
</a-form-item>
</a-form>
<a-space v-if="!isDetail">
<a-button type="primary" :loading="submitting" @click="handleSubmit"></a-button>
<a-button @click="goBack"></a-button>
</a-space>
</a-card>
<PersonalCustomerPicker ref="legalRepPickerRef" @select="handleLegalRepSelect" />
<PersonalCustomerPicker ref="relatedPersonPickerRef" @select="handleRelatedPersonSelect" />
</div>
</template>
<script setup>
import { ref, reactive, computed, onMounted } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { message } from 'ant-design-vue'
import dayjs from 'dayjs'
import ChannelSelect from '@/components/ChannelSelect.vue'
import LicenseUpload from '@/components/LicenseUpload.vue'
import OrgTreeSelect from '@/components/OrgTreeSelect.vue'
import PersonalCustomerPicker from '@/components/PersonalCustomerPicker.vue'
import {
fetchEnterpriseCustomerDetailApi,
createEnterpriseCustomerApi,
updateEnterpriseCustomerApi
} from '@/api/customer'
import { fetchPersonalCustomerDetailApi } from '@/api/customer'
import { phoneValidatorRule, businessLicenseValidatorRule } from '@/utils/validators'
const route = useRoute()
const router = useRouter()
const mode = computed(() => route.query.mode || 'create')
const isCreate = computed(() => mode.value === 'create')
const isEdit = computed(() => mode.value === 'edit')
const isDetail = computed(() => mode.value === 'detail')
const pageTitle = computed(() => ({ create: '新增企业客户', edit: '编辑企业客户', detail: '查看企业客户' }[mode.value]))
const channelNo = ref(undefined)
const submitting = ref(false)
const formRef = ref(null)
const legalRepName = ref('')
const legalRepPickerRef = ref(null)
const relatedPersonPickerRef = ref(null)
const relatedPersonList = ref([])
const form = reactive({
id: '',
organizationId: undefined,
enterpriseName: '',
businessLicense: '',
certificateEffectiveDate: '',
certificateExpiryDate: '',
mobilePhone: '',
certificateAddress: '',
businessScope: '',
businessLicenseFileNo: '',
legalRepresentativeId: undefined
})
const effectiveDateValue = computed({
get: () => (form.certificateEffectiveDate ? dayjs(form.certificateEffectiveDate) : undefined),
set: (val) => (form.certificateEffectiveDate = val ? val.format('YYYY-MM-DD') : '')
})
const expiryDateValue = computed({
get: () => (form.certificateExpiryDate ? dayjs(form.certificateExpiryDate) : undefined),
set: (val) => (form.certificateExpiryDate = val ? val.format('YYYY-MM-DD') : '')
})
const isExpired = computed(
() => !!form.certificateExpiryDate && dayjs(form.certificateExpiryDate).isBefore(dayjs(), 'day')
)
const rules = {
organizationId: [{ required: true, message: '请选择所属机构' }],
enterpriseName: [{ required: true, message: '请输入企业名称' }],
businessLicense: [businessLicenseValidatorRule()],
mobilePhone: [phoneValidatorRule()]
}
const relatedPersonColumns = [
{ title: '客户名称', dataIndex: 'customerName' },
{ title: '关联人类型', dataIndex: 'relatedType', width: 160 },
{ title: '证件号码', dataIndex: 'certificateNumber' },
{ title: '操作', dataIndex: 'action', width: 80 }
]
function openLegalRepPicker() {
legalRepPickerRef.value.show()
}
function handleLegalRepSelect(record) {
form.legalRepresentativeId = record.id
legalRepName.value = record.customerName
}
function openRelatedPersonPicker() {
relatedPersonPickerRef.value.show()
}
async function handleRelatedPersonSelect(record) {
// IndividualCustomerListVo ,
const detailRes = await fetchPersonalCustomerDetailApi({ id: record.id })
const detail = detailRes.data.code === 200 ? detailRes.data.data : record
relatedPersonList.value.push({
individualId: record.id,
customerName: record.customerName,
relatedType: 'SHAREHOLDER',
certificateType: detail.certificateType || 'ID_CARD',
certificateNumber: detail.certificateNumber,
certificateEffectiveDate: detail.certificateEffectiveDate,
certificateExpiryDate: detail.certificateExpiryDate
})
}
function removeRelatedPerson(index) {
relatedPersonList.value.splice(index, 1)
}
async function loadDetail(id) {
const res = await fetchEnterpriseCustomerDetailApi({ id })
if (res.data.code === 200) {
Object.assign(form, res.data.data)
if (res.data.data.legalRepresentativeId) {
const repRes = await fetchPersonalCustomerDetailApi({ id: res.data.data.legalRepresentativeId })
if (repRes.data.code === 200) legalRepName.value = repRes.data.data.customerName
}
}
}
onMounted(() => {
if (route.query.id) {
loadDetail(route.query.id)
}
})
function goBack() {
router.push('/customer/enterprise')
}
async function handleSubmit() {
try {
await formRef.value.validate()
} catch {
return
}
submitting.value = true
try {
const toFullDate = (d) => (d ? `${d} 00:00:00` : undefined)
const payload = {
organizationId: form.organizationId,
enterpriseName: form.enterpriseName,
businessLicense: form.businessLicense,
certificateType: 'BUSINESS_LICENSE',
certificateNumber: form.businessLicense,
certificateEffectiveDate: toFullDate(form.certificateEffectiveDate),
certificateExpiryDate: toFullDate(form.certificateExpiryDate),
mobilePhone: form.mobilePhone,
certificateAddress: form.certificateAddress,
businessScope: form.businessScope,
businessLicenseFileNo: form.businessLicenseFileNo,
legalRepresentativeId: form.legalRepresentativeId
}
let res
if (isCreate.value) {
const enterpriseRelatedPersonBtoList = relatedPersonList.value.map((item) => ({
individualId: item.individualId,
relatedType: item.relatedType,
certificateType: item.certificateType,
certificateNumber: item.certificateNumber,
certificateEffectiveDate: toFullDate(item.certificateEffectiveDate),
certificateExpiryDate: toFullDate(item.certificateExpiryDate)
}))
res = await createEnterpriseCustomerApi({
createEnterpriseCustomerBto: { ...payload, enterpriseRelatedPersonBtoList },
enableOcr: true
})
} else {
res = await updateEnterpriseCustomerApi({ id: form.id, ...payload })
}
if (res.data.code === 200) {
message.success(isCreate.value ? '新增成功' : '修改成功')
goBack()
}
} finally {
submitting.value = false
}
}
</script>
<style scoped>
.expired-hint {
color: #ff4d4f;
font-size: 12px;
margin-top: 4px;
}
.hint {
color: #999;
font-size: 12px;
margin-top: 4px;
}
</style>