feat: customer form and search UI for pinyin initials.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
1 parent
b151ac6499
commit
021bd73301
5 files changed
+44
-37
No files matched your search
@@ -63,6 +63,8 @@ export interface CustomerForm {
|
||||
id?: number | string;
|
||||
/** 客户名称 */
|
||||
customerName: string;
|
||||
/** 客户名称拼音首字母(小写) */
|
||||
namePinyinAbbr?: string;
|
||||
/** 客户简称 */
|
||||
shortName: string;
|
||||
/** 客户类型(company-企业/person-个人) */
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
allowCreate?: boolean
|
||||
}>(),
|
||||
{
|
||||
placeholder: '请输入客户名称搜索',
|
||||
placeholder: '请输入客户名称/拼音搜索',
|
||||
allowCreate: true
|
||||
}
|
||||
)
|
||||
|
||||
@@ -605,6 +605,7 @@ const viewSections = computed<ViewSection[]>(() => {
|
||||
const address = [c.province, c.city, c.district, c.address].filter(Boolean).join(' ')
|
||||
const basicFields: ViewField[] = [
|
||||
tagField('客户类型', 'crm_customer_type', c.customerType),
|
||||
{ label: '拼音首字母', value: c.namePinyinAbbr },
|
||||
{ label: '客户简称', value: c.shortName },
|
||||
{ label: '手机号', value: c.mobile },
|
||||
{ label: '固定电话', value: c.telephone },
|
||||
|
||||
@@ -24,6 +24,20 @@
|
||||
<el-form-item label="客户名称" prop="customerName">
|
||||
<el-input v-model="form.customerName" placeholder="请输入客户名称" maxlength="200" />
|
||||
</el-form-item>
|
||||
<el-form-item label="拼音首字母" class="form-field-span-2">
|
||||
<div class="pinyin-abbr-row">
|
||||
<el-input
|
||||
v-model="form.namePinyinAbbr"
|
||||
placeholder="默认按名称自动生成,可手改"
|
||||
maxlength="100"
|
||||
clearable
|
||||
/>
|
||||
<el-button class="btn-ghost" @click="regeneratePinyinAbbr">
|
||||
<el-icon><Refresh /></el-icon>
|
||||
重新生成
|
||||
</el-button>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="客户简称" prop="shortName">
|
||||
<el-input v-model="form.shortName" placeholder="请输入客户简称" maxlength="100" />
|
||||
</el-form-item>
|
||||
@@ -152,7 +166,7 @@
|
||||
|
||||
<el-divider content-position="left">证件信息</el-divider>
|
||||
<div class="form-grid-4">
|
||||
<el-form-item label="营业执照" prop="businessLicenseImages" class="form-field-span-2">
|
||||
<el-form-item label="营业执照" class="form-field-span-2">
|
||||
<AttachmentUploadField
|
||||
ref="businessLicenseUploadRef"
|
||||
v-model="form.businessLicenseImages"
|
||||
@@ -160,10 +174,9 @@
|
||||
accept="image/*,.pdf"
|
||||
folder="crm/customer/license"
|
||||
hint="支持 JPG、PNG、PDF,最多 5 个"
|
||||
@update:model-value="handleCertFieldChange('businessLicenseImages')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="经营许可证" prop="businessPermitImages" class="form-field-span-2">
|
||||
<el-form-item label="经营许可证" class="form-field-span-2">
|
||||
<AttachmentUploadField
|
||||
ref="businessPermitUploadRef"
|
||||
v-model="form.businessPermitImages"
|
||||
@@ -171,7 +184,6 @@
|
||||
accept="image/*,.pdf"
|
||||
folder="crm/customer/permit"
|
||||
hint="支持 JPG、PNG、PDF,最多 5 个"
|
||||
@update:model-value="handleCertFieldChange('businessPermitImages')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="其他证件" class="form-col-span-2">
|
||||
@@ -262,7 +274,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, computed, nextTick } from 'vue'
|
||||
import { Close, Check } from '@element-plus/icons-vue'
|
||||
import { Close, Check, Refresh } from '@element-plus/icons-vue'
|
||||
import type { FormItemRule } from 'element-plus'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import {
|
||||
@@ -288,6 +300,7 @@ const emit = defineEmits(['success'])
|
||||
const form = ref<CustomerFormType>({
|
||||
id: undefined,
|
||||
customerName: '',
|
||||
namePinyinAbbr: '',
|
||||
shortName: '',
|
||||
customerType: '未分类',
|
||||
mobile: undefined,
|
||||
@@ -312,11 +325,6 @@ const form = ref<CustomerFormType>({
|
||||
otherCertImages: undefined
|
||||
})
|
||||
|
||||
/** 证件字段变更后触发表单校验 */
|
||||
function handleCertFieldChange(field: 'businessLicenseImages' | 'businessPermitImages') {
|
||||
formRef.value?.validateField(field)
|
||||
}
|
||||
|
||||
function unwrapApiData<T>(res: T | { data?: T }): T {
|
||||
if (res != null && typeof res === 'object' && 'data' in res && (res as { data?: T }).data !== undefined) {
|
||||
return (res as { data: T }).data
|
||||
@@ -334,30 +342,6 @@ const rules = ref<Record<string, FormItemRule[]>>({
|
||||
province: [{ required: true, message: '省份不能为空', trigger: 'blur' }],
|
||||
city: [{ required: true, message: '城市不能为空', trigger: 'blur' }],
|
||||
district: [{ required: true, message: '区县不能为空', trigger: 'blur' }],
|
||||
businessLicenseImages: [
|
||||
{
|
||||
validator: (_rule: any, value: any, callback: any) => {
|
||||
if (!value || !String(value).trim()) {
|
||||
callback(new Error('请至少上传一张营业执照图片'))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
},
|
||||
trigger: 'change'
|
||||
}
|
||||
],
|
||||
businessPermitImages: [
|
||||
{
|
||||
validator: (_rule: any, value: any, callback: any) => {
|
||||
if (!value || !String(value).trim()) {
|
||||
callback(new Error('请至少上传一张经营许可证图片'))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
},
|
||||
trigger: 'change'
|
||||
}
|
||||
],
|
||||
mobile: [{ pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号', trigger: 'blur' }],
|
||||
email: [{ type: 'email', message: '请输入正确的邮箱地址', trigger: 'blur' }]
|
||||
})
|
||||
@@ -539,9 +523,16 @@ function buildSubmitPayload() {
|
||||
const payload: Record<string, any> = { ...form.value }
|
||||
// 详情接口会同时返回 businessLicenseImg(旧字段),避免覆盖新上传的 businessLicenseImages
|
||||
delete payload.businessLicenseImg
|
||||
// 显式传空串:后端按「重新生成」处理;有值则手改入库
|
||||
payload.namePinyinAbbr = (form.value.namePinyinAbbr || '').trim()
|
||||
return payload
|
||||
}
|
||||
|
||||
function regeneratePinyinAbbr() {
|
||||
form.value.namePinyinAbbr = ''
|
||||
ElMessage.info('已清空,保存时将按客户名称重新生成拼音首字母')
|
||||
}
|
||||
|
||||
/** 提交表单 */
|
||||
const submitForm = () => {
|
||||
if (hasAttachmentUploading()) {
|
||||
@@ -591,6 +582,7 @@ const reset = () => {
|
||||
form.value = {
|
||||
id: undefined,
|
||||
customerName: '',
|
||||
namePinyinAbbr: '',
|
||||
shortName: '',
|
||||
customerType: '未分类',
|
||||
mobile: undefined,
|
||||
@@ -625,4 +617,16 @@ defineExpose({ open })
|
||||
.form-grid-4 .form-field-span-2 {
|
||||
grid-column: span 2;
|
||||
}
|
||||
|
||||
.pinyin-abbr-row {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
|
||||
.el-input {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -24,7 +24,7 @@
|
||||
<el-form-item label="客户名称">
|
||||
<el-input
|
||||
v-model="searchForm.customerName"
|
||||
placeholder="客户名称"
|
||||
placeholder="客户名称/拼音首字母"
|
||||
clearable
|
||||
@keyup.enter="handleSearch"
|
||||
/>
|
||||
@@ -133,7 +133,7 @@
|
||||
<div class="list-toolbar-row">
|
||||
<ListQuickSearchInput
|
||||
v-model="quickSearchKeyword"
|
||||
placeholder="客户名称/编号/手机号"
|
||||
placeholder="客户名称/编号/手机号/拼音首字母"
|
||||
@search="handleQuickSearch"
|
||||
@clear="handleQuickSearchClear"
|
||||
/>
|
||||
|
||||
Reference in new issue
Block a user