feat(用户主页): 添加客户信息自动填充功能
新增从URL参数获取wecom_id并自动填充客户信息的功能,优化表单数据回显逻辑。同时简化文件上传和提交逻辑,移除冗余代码。
This commit is contained in:
@@ -215,10 +215,9 @@
|
||||
</div>
|
||||
</n-config-provider>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { reactive, ref } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { reactive, ref, onMounted } from 'vue' // 👉 增加 onMounted
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import {
|
||||
useMessage, zhCN, dateZhCN, NConfigProvider, NCard, NSpace, NGrid, NGridItem,
|
||||
NForm, NFormItem, NInput, NInputNumber, NDatePicker, NUpload, NUploadDragger,
|
||||
@@ -231,10 +230,10 @@ import {
|
||||
CreateOutline, CloseOutline, CheckmarkCircleOutline
|
||||
} from '@vicons/ionicons5'
|
||||
|
||||
// 👉 引入你项目中的请求封装文件
|
||||
import http from '@/utils/request'
|
||||
|
||||
const router = useRouter()
|
||||
const route = useRoute() // 👉 用于获取 URL 中的参数
|
||||
const message = useMessage()
|
||||
const formRef = ref(null)
|
||||
|
||||
@@ -255,152 +254,118 @@ const formData = reactive({
|
||||
signatureFileList: []
|
||||
})
|
||||
|
||||
// 表单校验规则
|
||||
const rules = {
|
||||
analystName: [{ required: true, message: '请输入分析师姓名', trigger: 'blur' }],
|
||||
parentName: [{ required: true, message: '请输入家长姓名', trigger: 'blur' }],
|
||||
parentPhone: [{ required: true, message: '请输入联系电话', trigger: 'blur' }],
|
||||
transactionAmount: [{ required: true, type: 'number', message: '请输入成交金额', trigger: 'blur' }],
|
||||
}
|
||||
|
||||
// 预览功能
|
||||
const handlePreview = (file) => {
|
||||
// 优先预览从服务端获取到的 url
|
||||
if (file.url) {
|
||||
window.open(file.url)
|
||||
} else if (file.file) {
|
||||
const url = URL.createObjectURL(file.file)
|
||||
window.open(url)
|
||||
}
|
||||
}
|
||||
|
||||
// 退出登录
|
||||
const logout = () => {
|
||||
localStorage.clear()
|
||||
message.info('已退出系统')
|
||||
// router.push('/login')
|
||||
}
|
||||
|
||||
// 取消
|
||||
const handleCancel = () => {
|
||||
message.info('操作已取消')
|
||||
}
|
||||
|
||||
// 👉 自定义文件上传逻辑
|
||||
const customUpload = async ({ file, data, headers, onFinish, onError, onProgress }) => {
|
||||
// 1. 构造 FormData 对象
|
||||
const uploadData = new FormData()
|
||||
// naive-ui 的 file 是一个包装对象,原生的 File 对象在 file.file 属性中
|
||||
uploadData.append('file', file.file)
|
||||
|
||||
// 如果组件传入了额外数据,也追加进去
|
||||
if (data) {
|
||||
Object.keys(data).forEach((key) => {
|
||||
uploadData.append(key, data[key])
|
||||
})
|
||||
}
|
||||
// 👉 新增:初始化获取数据的方法
|
||||
const fetchCustomerInfo = async () => {
|
||||
// 优先从 URL 获取 wecom_id,如果没有则使用你提供的测试 ID
|
||||
const wecom_id = route.query.wecom_id || 'wmcr-ECwAAzKclEfIKNcVgOdxD-TcqLg'
|
||||
|
||||
const d = message.loading('正在加载客户信息...')
|
||||
try {
|
||||
// 2. 调用封装好的上传接口 (注意:这里直接写 /v1/material/upload,前提是 utils/request.js 中配置好了 /api 等前缀)
|
||||
const res = await http.post('/v1/material/upload', uploadData, {
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
...headers
|
||||
},
|
||||
// 监听上传进度,并在页面上显示绿色进度条
|
||||
onUploadProgress: (progressEvent) => {
|
||||
const percentCompleted = Math.round((progressEvent.loaded * 100) / progressEvent.total)
|
||||
onProgress({ percent: percentCompleted })
|
||||
}
|
||||
})
|
||||
const res = await http.get('/v1/customer/get_customers_info', { wecom_id })
|
||||
|
||||
// 3. 上传成功后处理数据
|
||||
// 根据你 utils/request.js 的响应拦截器逻辑,`res` 已经是接口的 `data` 部分了
|
||||
// 这里把后台返回的 url 赋值给当前文件对象,便于后续图片预览及提交时抽取数据
|
||||
file.url = res.url
|
||||
file.object_name = res.object_name // 保留一下 object_name,以防后台提交需要用到
|
||||
// 👉 数据映射回显
|
||||
formData.parentName = res.customerName
|
||||
formData.parentPhone = res.customerPhone
|
||||
formData.analystName = res.analystName
|
||||
|
||||
// 4. 通知组件上传成功
|
||||
onFinish()
|
||||
// 数组取第一个
|
||||
formData.analystDepartment = res.analystDepartmentName?.[0] || ''
|
||||
formData.analystSupervisor = res.analystDepartmentLeader?.[0] || ''
|
||||
|
||||
// 金额转数字
|
||||
formData.transactionAmount = res.dealAmount ? Number(res.dealAmount) : null
|
||||
|
||||
// 日期字符串转时间戳
|
||||
formData.transactionDate = res.dealDate ? new Date(res.dealDate).getTime() : null
|
||||
|
||||
formData.analystNotes = res.notes || ''
|
||||
|
||||
// 👉 回显付款截图 (将 URL 数组转为 Upload 组件需要的对象格式)
|
||||
if (res.proofOfPayment && Array.isArray(res.proofOfPayment)) {
|
||||
formData.paymentFileList = res.proofOfPayment.map((url, index) => ({
|
||||
id: 'init-' + index,
|
||||
name: '已上传凭证-' + (index + 1),
|
||||
status: 'finished',
|
||||
url: url
|
||||
}))
|
||||
}
|
||||
|
||||
message.success('客户资料已自动填充')
|
||||
} catch (error) {
|
||||
console.error('上传失败:', error)
|
||||
// 5. 通知组件上传失败,变红
|
||||
onError()
|
||||
message.error(`${file.name} 上传失败,请重试`)
|
||||
console.error('获取初始信息失败:', error)
|
||||
message.error('无法获取客户基础信息')
|
||||
} finally {
|
||||
d.destroy()
|
||||
}
|
||||
}
|
||||
|
||||
// 👉 提交表单数据
|
||||
// 👉 修改后的提交方法
|
||||
// 👉 页面加载时执行
|
||||
onMounted(() => {
|
||||
fetchCustomerInfo()
|
||||
})
|
||||
|
||||
// --- 以下是之前的逻辑,保持不变 ---
|
||||
|
||||
// 自定义上传逻辑
|
||||
const customUpload = async ({ file, onFinish, onError, onProgress }) => {
|
||||
const uploadData = new FormData()
|
||||
uploadData.append('file', file.file)
|
||||
try {
|
||||
const res = await http.post('/v1/material/upload', uploadData, {
|
||||
onUploadProgress: (p) => onProgress({ percent: Math.round((p.loaded * 100) / p.total) })
|
||||
})
|
||||
file.url = res.url
|
||||
onFinish()
|
||||
} catch (e) {
|
||||
onError()
|
||||
message.error('上传失败')
|
||||
}
|
||||
}
|
||||
|
||||
// 最终提交逻辑
|
||||
const handleSubmit = () => {
|
||||
formRef.value?.validate(async (errors) => {
|
||||
if (!errors) {
|
||||
// 1. 检查文件上传状态
|
||||
const allFiles = [
|
||||
...formData.documentFileList,
|
||||
...formData.paymentFileList,
|
||||
...formData.signatureFileList
|
||||
]
|
||||
const isUploading = allFiles.some(file => file.status === 'uploading')
|
||||
const hasError = allFiles.some(file => file.status === 'error')
|
||||
|
||||
if (isUploading) return message.warning('文件正在上传中,请稍候')
|
||||
if (hasError) return message.error('部分文件上传失败,请处理后再提交')
|
||||
|
||||
// 2. 构造符合后端接口要求的 JSON 对象
|
||||
// 注意:接口字段为下划线命名,且文件URL要求为字符串
|
||||
const submitPayload = {
|
||||
// 从缓存获取 wecom_id (如果没有则传空字符串或从路由获取)
|
||||
wecom_id: localStorage.getItem('wecom_id') || 'default_user',
|
||||
|
||||
// 文件 URL 处理:取第一个,或者用逗号拼接(根据你接口单数命名的理解,通常传第一个或拼接)
|
||||
wecom_id: route.query.wecom_id || 'wmcr-ECwAAvBzsjWQ6RQZuXmxzXHMLiQ',
|
||||
payment_image_url: formData.paymentFileList.map(f => f.url).filter(Boolean).join(','),
|
||||
signature_image_url: formData.signatureFileList.map(f => f.url).filter(Boolean).join(','),
|
||||
attachment_file_url: formData.documentFileList.map(f => f.url).filter(Boolean).join(','),
|
||||
|
||||
// 基础文本信息
|
||||
analyst_supervisor: formData.analystSupervisor,
|
||||
analyst_department: formData.analystDepartment,
|
||||
analyst_name: formData.analystName,
|
||||
parent_name: formData.parentName,
|
||||
parent_phone: formData.parentPhone,
|
||||
parent_id_card: formData.parentIdCard,
|
||||
|
||||
// 指导周期
|
||||
guidance_period: formData.guidancePeriod,
|
||||
|
||||
// 特殊处理:金额转为字符串
|
||||
transaction_amount: String(formData.transactionAmount || '0'),
|
||||
|
||||
// 特殊处理:日期转为 YYYY-MM-DD 字符串
|
||||
transaction_date: formData.transactionDate
|
||||
? new Date(formData.transactionDate).toISOString().split('T')[0]
|
||||
: ''
|
||||
transaction_date: formData.transactionDate ? new Date(formData.transactionDate).toISOString().split('T')[0] : '',
|
||||
transaction_amount: String(formData.transactionAmount || ''),
|
||||
guidance_period: formData.guidancePeriod
|
||||
}
|
||||
|
||||
const d = message.loading('正在提报材料...', { duration: 0 })
|
||||
|
||||
const d = message.loading('提交中...')
|
||||
try {
|
||||
// 3. 调用提交接口
|
||||
// 你的 request.js baseURL 已经包含 /api,所以这里写相对路径
|
||||
const res = await http.post('/v1/material/submit', submitPayload)
|
||||
|
||||
d.destroy()
|
||||
await http.post('/v1/material/submit', submitPayload)
|
||||
message.success('提报成功!')
|
||||
console.log('提交结果:', res)
|
||||
|
||||
// 4. 提交成功后的操作:比如跳转或重置表单
|
||||
// router.push('/success')
|
||||
} catch (error) {
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
} finally {
|
||||
d.destroy()
|
||||
// 错误提示已在 request.js 拦截器处理,这里可以做特定逻辑
|
||||
console.error('提报失败', error)
|
||||
}
|
||||
} else {
|
||||
message.error('请完善表单必填项')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const handlePreview = (file) => {
|
||||
window.open(file.url)
|
||||
}
|
||||
const logout = () => { localStorage.clear(); message.info('已退出'); }
|
||||
const handleCancel = () => { message.info('已取消'); }
|
||||
|
||||
const rules = {
|
||||
analystName: [{ required: true, message: '必填', trigger: 'blur' }],
|
||||
parentName: [{ required: true, message: '必填', trigger: 'blur' }],
|
||||
parentPhone: [{ required: true, message: '必填', trigger: 'blur' }],
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
Reference in New Issue
Block a user