feat: 新增个人客户新增/编辑/查看表单页
parent
96437e7bc4
commit
6c35fbebdd
|
|
@ -0,0 +1,222 @@
|
|||
<!-- src/views/customer/personal/PersonalForm.vue -->
|
||||
<template>
|
||||
<div class="personal-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="身份证照片" required>
|
||||
<a-space size="large">
|
||||
<IdCardUpload
|
||||
side="front"
|
||||
:channel-no="channelNo"
|
||||
v-model:file-no="form.idCardFrontFileNo"
|
||||
@ocr-result="handleOcrResult"
|
||||
@ocr-status="(status) => (ocrStatus = status)"
|
||||
/>
|
||||
<IdCardUpload
|
||||
side="back"
|
||||
:channel-no="channelNo"
|
||||
v-model:file-no="form.idCardBackFileNo"
|
||||
@ocr-result="handleOcrResult"
|
||||
@ocr-status="(status) => (ocrStatus = status)"
|
||||
/>
|
||||
</a-space>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="所属机构" name="organizationId">
|
||||
<OrgTreeSelect v-model="form.organizationId" placeholder="请选择所属机构" />
|
||||
</a-form-item>
|
||||
<a-form-item label="客户名称" name="customerName">
|
||||
<a-input v-model:value="form.customerName" placeholder="请输入客户名称(OCR自动填充)" />
|
||||
</a-form-item>
|
||||
<a-form-item label="证件类型">
|
||||
<a-input value="身份证" disabled />
|
||||
</a-form-item>
|
||||
<a-form-item label="证件号码" name="certificateNumber">
|
||||
<a-input v-model:value="form.certificateNumber" placeholder="请输入证件号码(OCR自动填充)" />
|
||||
</a-form-item>
|
||||
<a-form-item label="出生日期" name="birthDate">
|
||||
<a-date-picker v-model:value="birthDateValue" style="width: 100%" value-format="YYYY-MM-DD" />
|
||||
</a-form-item>
|
||||
<a-form-item label="性别" name="gender">
|
||||
<a-select v-model:value="form.gender">
|
||||
<a-select-option value="MALE">男</a-select-option>
|
||||
<a-select-option value="FEMALE">女</a-select-option>
|
||||
<a-select-option value="UNKNOWN">未知</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item label="民族" name="ethnicity">
|
||||
<a-input v-model:value="form.ethnicity" placeholder="请输入民族(OCR自动填充)" />
|
||||
</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="issuingAuthority">
|
||||
<a-input v-model:value="form.issuingAuthority" placeholder="请输入签发机关(OCR自动填充)" />
|
||||
</a-form-item>
|
||||
<a-form-item label="证件地址" name="certificateAddress">
|
||||
<a-input v-model:value="form.certificateAddress" placeholder="请输入证件地址(OCR自动填充)" />
|
||||
</a-form-item>
|
||||
<a-form-item label="职业" name="occupation">
|
||||
<a-input v-model:value="form.occupation" placeholder="请输入职业" />
|
||||
</a-form-item>
|
||||
<a-form-item label="手机号码" name="mobilePhone">
|
||||
<a-input v-model:value="form.mobilePhone" placeholder="请输入11位手机号" />
|
||||
</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>
|
||||
</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 IdCardUpload from '@/components/IdCardUpload.vue'
|
||||
import OrgTreeSelect from '@/components/OrgTreeSelect.vue'
|
||||
import {
|
||||
fetchPersonalCustomerDetailApi,
|
||||
createPersonalCustomerApi,
|
||||
updatePersonalCustomerApi
|
||||
} from '@/api/customer'
|
||||
import { mapOcrIdCardResult } from '@/utils/ocrMapping'
|
||||
import { phoneValidatorRule, idCardValidatorRule } from '@/utils/validators'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
|
||||
const mode = computed(() => route.query.mode || 'create')
|
||||
const isDetail = computed(() => mode.value === 'detail')
|
||||
const pageTitle = computed(() => ({ create: '新增个人客户', edit: '编辑个人客户', detail: '查看个人客户' }[mode.value]))
|
||||
|
||||
const channelNo = ref(undefined)
|
||||
const ocrStatus = ref('PENDING')
|
||||
const submitting = ref(false)
|
||||
const formRef = ref(null)
|
||||
|
||||
const form = reactive({
|
||||
id: '',
|
||||
organizationId: undefined,
|
||||
customerName: '',
|
||||
certificateNumber: '',
|
||||
birthDate: '',
|
||||
gender: 'UNKNOWN',
|
||||
ethnicity: '',
|
||||
certificateEffectiveDate: '',
|
||||
certificateExpiryDate: '',
|
||||
issuingAuthority: '',
|
||||
certificateAddress: '',
|
||||
occupation: '',
|
||||
mobilePhone: '',
|
||||
idCardFrontFileNo: '',
|
||||
idCardBackFileNo: ''
|
||||
})
|
||||
|
||||
const birthDateValue = computed({
|
||||
get: () => (form.birthDate ? dayjs(form.birthDate) : undefined),
|
||||
set: (val) => (form.birthDate = val ? val.format('YYYY-MM-DD') : '')
|
||||
})
|
||||
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: '请选择所属机构' }],
|
||||
customerName: [{ required: true, message: '请输入客户名称' }],
|
||||
certificateNumber: [idCardValidatorRule()],
|
||||
mobilePhone: [phoneValidatorRule()]
|
||||
}
|
||||
|
||||
function handleOcrResult(ocrData) {
|
||||
Object.assign(form, mapOcrIdCardResult(ocrData))
|
||||
}
|
||||
|
||||
async function loadDetail(id) {
|
||||
const res = await fetchPersonalCustomerDetailApi({ id })
|
||||
if (res.data.code === 200) {
|
||||
Object.assign(form, res.data.data)
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if (route.query.id) {
|
||||
loadDetail(route.query.id)
|
||||
}
|
||||
})
|
||||
|
||||
function goBack() {
|
||||
router.push('/customer/personal')
|
||||
}
|
||||
|
||||
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,
|
||||
customerName: form.customerName,
|
||||
certificateType: 'ID_CARD',
|
||||
certificateNumber: form.certificateNumber,
|
||||
birthDate: toFullDate(form.birthDate),
|
||||
gender: form.gender,
|
||||
ethnicity: form.ethnicity,
|
||||
certificateEffectiveDate: toFullDate(form.certificateEffectiveDate),
|
||||
certificateExpiryDate: toFullDate(form.certificateExpiryDate),
|
||||
issuingAuthority: form.issuingAuthority,
|
||||
mobilePhone: form.mobilePhone,
|
||||
certificateAddress: form.certificateAddress,
|
||||
idCardFrontFileNo: form.idCardFrontFileNo,
|
||||
idCardBackFileNo: form.idCardBackFileNo,
|
||||
occupation: form.occupation,
|
||||
ocrStatus: ocrStatus.value
|
||||
}
|
||||
const res =
|
||||
mode.value === 'create'
|
||||
? await createPersonalCustomerApi(payload)
|
||||
: await updatePersonalCustomerApi({ id: form.id, ...payload })
|
||||
if (res.data.code === 200) {
|
||||
message.success(mode.value === 'create' ? '新增成功' : '修改成功')
|
||||
goBack()
|
||||
}
|
||||
} finally {
|
||||
submitting.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.expired-hint {
|
||||
color: #ff4d4f;
|
||||
font-size: 12px;
|
||||
margin-top: 4px;
|
||||
}
|
||||
</style>
|
||||
Loading…
Reference in New Issue