From 56063e9bcd0f4361fed2291891280f54ab8b58a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=B5=E5=BF=A0=E6=9E=97?= <170083662@qq.com> Date: Thu, 19 Mar 2026 17:08:20 +0800 Subject: [PATCH] =?UTF-8?q?feat(credit):=20=E6=9B=B4=E6=96=B0=E5=AE=A2?= =?UTF-8?q?=E6=88=B7=E4=BF=A1=E6=81=AF=E7=BC=96=E8=BE=91=E7=BB=84=E4=BB=B6?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 替换城市输入框为省市区级联选择组件 - 新增步骤下拉选择框用于流程状态管理 - 集成文件选择组件替代原有文件路径输入框 - 实现文件上传和删除功能 - 添加文件列表管理和同步逻辑 - 优化搜索组件中关键词搜索框位置 - 完善查询参数过滤逻辑支持数组和单一值处理 --- .../components/creditMpCustomerEdit.vue | 164 +++++++++++++++--- .../creditMpCustomer/components/search.vue | 16 +- src/views/credit/creditMpCustomer/index.vue | 18 +- 3 files changed, 160 insertions(+), 38 deletions(-) diff --git a/src/views/credit/creditMpCustomer/components/creditMpCustomerEdit.vue b/src/views/credit/creditMpCustomer/components/creditMpCustomerEdit.vue index aa37b38..0968bb0 100644 --- a/src/views/credit/creditMpCustomer/components/creditMpCustomerEdit.vue +++ b/src/views/credit/creditMpCustomer/components/creditMpCustomerEdit.vue @@ -62,12 +62,24 @@ - + + + + {{ item.text }} + + + @@ -76,10 +88,12 @@ - @@ -131,9 +145,11 @@ import { CreditMpCustomer } from '@/api/credit/creditMpCustomer/model'; import { useThemeStore } from '@/store/modules/theme'; import { storeToRefs } from 'pinia'; - import { ItemType } from 'ele-admin-pro/es/ele-image-upload/types'; import { FormInstance } from 'ant-design-vue/es/form'; import { FileRecord } from '@/api/system/file/model'; + import RegionsSelect from '@/components/RegionsSelect/index.vue'; + import SelectFile from '@/components/SelectFile/index.vue'; + import { isImage } from '@/utils/common'; // 是否是修改 const isUpdate = ref(false); @@ -160,7 +176,17 @@ const maxable = ref(true); // 表格选中数据 const formRef = ref(null); - const images = ref([]); + const regions = ref(); + const fileList = ref([]); + + const stepOptions = [ + { value: 0, text: '未受理' }, + { value: 1, text: '已受理' }, + { value: 2, text: '材料提交' }, + { value: 3, text: '合同签订' }, + { value: 4, text: '执行回款' }, + { value: 5, text: '完结' } + ]; // 用户信息 const form = reactive({ @@ -175,6 +201,7 @@ city: undefined, region: undefined, files: undefined, + step: 0, hasData: undefined, recommend: undefined, status: undefined, @@ -204,22 +231,103 @@ ] }); - const chooseImage = (data: FileRecord) => { - images.value.push({ - uid: data.id, - url: data.path, - status: 'done' - }); - form.files = data.path; + const guessNameFromUrl = (url: string) => { + const cleanUrl = (url.split('?')[0] ?? '').trim(); + const last = cleanUrl.split('/').pop() || ''; + try { + return decodeURIComponent(last) || url; + } catch { + return last || url; + } }; - const onDeleteItem = (index: number) => { - images.value.splice(index, 1); - form.files = ''; + const normalizeFiles = (raw: unknown) => { + if (!raw) return []; + if (Array.isArray(raw)) { + return raw + .map((item: any) => { + if (!item) return null; + if (typeof item === 'string') { + return { + url: item, + name: guessNameFromUrl(item), + thumbnail: item, + isImage: isImage(item) + }; + } + const url = item.url || item.path || item.href; + if (!url || typeof url !== 'string') return null; + return { + url, + name: typeof item.name === 'string' ? item.name : guessNameFromUrl(url), + thumbnail: typeof item.thumbnail === 'string' ? item.thumbnail : undefined, + isImage: typeof item.isImage === 'boolean' ? item.isImage : isImage(url) + }; + }) + .filter(Boolean); + } + if (typeof raw === 'string') { + const text = raw.trim(); + if (!text) return []; + try { + let parsed: any = JSON.parse(text); + if (typeof parsed === 'string') parsed = JSON.parse(parsed); + if (Array.isArray(parsed)) return normalizeFiles(parsed); + } catch { + // ignore + } + return normalizeFiles(text.includes(',') ? text.split(',') : [text]); + } + return []; + }; + + const syncFilesToForm = () => { + const payload = (fileList.value ?? []) + .map((f: any) => { + const url = f?.url; + if (!url) return null; + return { + name: f?.name || guessNameFromUrl(url), + url, + thumbnail: f?.thumbnail, + isImage: typeof f?.isImage === 'boolean' ? f.isImage : isImage(url) + }; + }) + .filter(Boolean); + form.files = payload.length ? JSON.stringify(payload) : ''; + }; + + const onFileChoose = (data: FileRecord) => { + const url = data.url || data.downloadUrl || data.path; + if (!url) return; + const exists = fileList.value.some((d: any) => d?.url === url); + if (exists) return; + fileList.value.push({ + url, + name: data.name || guessNameFromUrl(url), + thumbnail: data.thumbnail, + isImage: isImage(url) + }); + syncFilesToForm(); + }; + + const onFileDelete = (index: number) => { + fileList.value.splice(index, 1); + syncFilesToForm(); }; const { resetFields } = useForm(form, rules); + // 级联选择回填到表单字段 + watch( + regions, + (val) => { + form.province = val?.[0]; + form.city = val?.[1]; + }, + { immediate: true } + ); + /* 保存编辑 */ const save = () => { if (!formRef.value) { @@ -252,22 +360,22 @@ () => props.visible, (visible) => { if (visible) { - images.value = []; + regions.value = undefined; + fileList.value = []; if (props.data) { assignObject(form, props.data); - if(props.data.files){ - images.value.push({ - uid: uuid(), - url: props.data.files, - status: 'done' - }) - } + regions.value = form.province && form.city ? [form.province, form.city] : undefined; + fileList.value = normalizeFiles(props.data.files); + syncFilesToForm(); isUpdate.value = true; } else { isUpdate.value = false; + form.step = 0; } } else { resetFields(); + regions.value = undefined; + fileList.value = []; } }, { immediate: true } diff --git a/src/views/credit/creditMpCustomer/components/search.vue b/src/views/credit/creditMpCustomer/components/search.vue index 81f1d40..8be76ee 100644 --- a/src/views/credit/creditMpCustomer/components/search.vue +++ b/src/views/credit/creditMpCustomer/components/search.vue @@ -24,14 +24,6 @@ 批量删除 - + diff --git a/src/views/credit/creditMpCustomer/index.vue b/src/views/credit/creditMpCustomer/index.vue index 3540b0a..b0b0f6d 100644 --- a/src/views/credit/creditMpCustomer/index.vue +++ b/src/views/credit/creditMpCustomer/index.vue @@ -143,9 +143,23 @@ const datasource: DatasourceFunction = ({ }) => { const params: CreditMpCustomerParam = {...(where as CreditMpCustomerParam)}; if (filters) { - (params as any).status = filters.status; + const filterStatus = (filters as any).status; + if (Array.isArray(filterStatus)) { + if (filterStatus.length) { + (params as any).status = filterStatus[0]; + } + } else if (filterStatus !== undefined && filterStatus !== null) { + (params as any).status = filterStatus; + } + const stepFilter = (filters as any).step; - (params as any).step = Array.isArray(stepFilter) ? stepFilter[0] : stepFilter; + if (Array.isArray(stepFilter)) { + if (stepFilter.length) { + (params as any).step = stepFilter[0]; + } + } else if (stepFilter !== undefined && stepFilter !== null) { + (params as any).step = stepFilter; + } } return pageCreditMpCustomer({ ...params,