feat(用户主页): 添加客户信息自动填充功能
新增从URL参数获取wecom_id并自动填充客户信息的功能,优化表单数据回显逻辑。同时简化文件上传和提交逻辑,移除冗余代码。
This commit is contained in:
@@ -215,10 +215,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</n-config-provider>
|
</n-config-provider>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { reactive, ref } from 'vue'
|
import { reactive, ref, onMounted } from 'vue' // 👉 增加 onMounted
|
||||||
import { useRouter } from 'vue-router'
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
import {
|
import {
|
||||||
useMessage, zhCN, dateZhCN, NConfigProvider, NCard, NSpace, NGrid, NGridItem,
|
useMessage, zhCN, dateZhCN, NConfigProvider, NCard, NSpace, NGrid, NGridItem,
|
||||||
NForm, NFormItem, NInput, NInputNumber, NDatePicker, NUpload, NUploadDragger,
|
NForm, NFormItem, NInput, NInputNumber, NDatePicker, NUpload, NUploadDragger,
|
||||||
@@ -231,10 +230,10 @@ import {
|
|||||||
CreateOutline, CloseOutline, CheckmarkCircleOutline
|
CreateOutline, CloseOutline, CheckmarkCircleOutline
|
||||||
} from '@vicons/ionicons5'
|
} from '@vicons/ionicons5'
|
||||||
|
|
||||||
// 👉 引入你项目中的请求封装文件
|
|
||||||
import http from '@/utils/request'
|
import http from '@/utils/request'
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
const route = useRoute() // 👉 用于获取 URL 中的参数
|
||||||
const message = useMessage()
|
const message = useMessage()
|
||||||
const formRef = ref(null)
|
const formRef = ref(null)
|
||||||
|
|
||||||
@@ -255,152 +254,118 @@ const formData = reactive({
|
|||||||
signatureFileList: []
|
signatureFileList: []
|
||||||
})
|
})
|
||||||
|
|
||||||
// 表单校验规则
|
// 👉 新增:初始化获取数据的方法
|
||||||
const rules = {
|
const fetchCustomerInfo = async () => {
|
||||||
analystName: [{ required: true, message: '请输入分析师姓名', trigger: 'blur' }],
|
// 优先从 URL 获取 wecom_id,如果没有则使用你提供的测试 ID
|
||||||
parentName: [{ required: true, message: '请输入家长姓名', trigger: 'blur' }],
|
const wecom_id = route.query.wecom_id || 'wmcr-ECwAAzKclEfIKNcVgOdxD-TcqLg'
|
||||||
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 d = message.loading('正在加载客户信息...')
|
||||||
try {
|
try {
|
||||||
// 2. 调用封装好的上传接口 (注意:这里直接写 /v1/material/upload,前提是 utils/request.js 中配置好了 /api 等前缀)
|
const res = await http.get('/v1/customer/get_customers_info', { wecom_id })
|
||||||
const res = await http.post('/v1/material/upload', uploadData, {
|
|
||||||
headers: {
|
// 👉 数据映射回显
|
||||||
'Content-Type': 'multipart/form-data',
|
formData.parentName = res.customerName
|
||||||
...headers
|
formData.parentPhone = res.customerPhone
|
||||||
},
|
formData.analystName = res.analystName
|
||||||
// 监听上传进度,并在页面上显示绿色进度条
|
|
||||||
onUploadProgress: (progressEvent) => {
|
// 数组取第一个
|
||||||
const percentCompleted = Math.round((progressEvent.loaded * 100) / progressEvent.total)
|
formData.analystDepartment = res.analystDepartmentName?.[0] || ''
|
||||||
onProgress({ percent: percentCompleted })
|
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
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
})
|
|
||||||
|
|
||||||
// 3. 上传成功后处理数据
|
message.success('客户资料已自动填充')
|
||||||
// 根据你 utils/request.js 的响应拦截器逻辑,`res` 已经是接口的 `data` 部分了
|
|
||||||
// 这里把后台返回的 url 赋值给当前文件对象,便于后续图片预览及提交时抽取数据
|
|
||||||
file.url = res.url
|
|
||||||
file.object_name = res.object_name // 保留一下 object_name,以防后台提交需要用到
|
|
||||||
|
|
||||||
// 4. 通知组件上传成功
|
|
||||||
onFinish()
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('上传失败:', error)
|
console.error('获取初始信息失败:', error)
|
||||||
// 5. 通知组件上传失败,变红
|
message.error('无法获取客户基础信息')
|
||||||
onError()
|
} finally {
|
||||||
message.error(`${file.name} 上传失败,请重试`)
|
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 = () => {
|
const handleSubmit = () => {
|
||||||
formRef.value?.validate(async (errors) => {
|
formRef.value?.validate(async (errors) => {
|
||||||
if (!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 = {
|
const submitPayload = {
|
||||||
// 从缓存获取 wecom_id (如果没有则传空字符串或从路由获取)
|
wecom_id: route.query.wecom_id || 'wmcr-ECwAAvBzsjWQ6RQZuXmxzXHMLiQ',
|
||||||
wecom_id: localStorage.getItem('wecom_id') || 'default_user',
|
|
||||||
|
|
||||||
// 文件 URL 处理:取第一个,或者用逗号拼接(根据你接口单数命名的理解,通常传第一个或拼接)
|
|
||||||
payment_image_url: formData.paymentFileList.map(f => f.url).filter(Boolean).join(','),
|
payment_image_url: formData.paymentFileList.map(f => f.url).filter(Boolean).join(','),
|
||||||
signature_image_url: formData.signatureFileList.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(','),
|
attachment_file_url: formData.documentFileList.map(f => f.url).filter(Boolean).join(','),
|
||||||
|
|
||||||
// 基础文本信息
|
|
||||||
analyst_supervisor: formData.analystSupervisor,
|
analyst_supervisor: formData.analystSupervisor,
|
||||||
analyst_department: formData.analystDepartment,
|
analyst_department: formData.analystDepartment,
|
||||||
analyst_name: formData.analystName,
|
analyst_name: formData.analystName,
|
||||||
parent_name: formData.parentName,
|
parent_name: formData.parentName,
|
||||||
parent_phone: formData.parentPhone,
|
parent_phone: formData.parentPhone,
|
||||||
parent_id_card: formData.parentIdCard,
|
parent_id_card: formData.parentIdCard,
|
||||||
|
transaction_date: formData.transactionDate ? new Date(formData.transactionDate).toISOString().split('T')[0] : '',
|
||||||
// 指导周期
|
transaction_amount: String(formData.transactionAmount || ''),
|
||||||
guidance_period: formData.guidancePeriod,
|
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]
|
|
||||||
: ''
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const d = message.loading('正在提报材料...', { duration: 0 })
|
const d = message.loading('提交中...')
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 3. 调用提交接口
|
await http.post('/v1/material/submit', submitPayload)
|
||||||
// 你的 request.js baseURL 已经包含 /api,所以这里写相对路径
|
|
||||||
const res = await http.post('/v1/material/submit', submitPayload)
|
|
||||||
|
|
||||||
d.destroy()
|
|
||||||
message.success('提报成功!')
|
message.success('提报成功!')
|
||||||
console.log('提交结果:', res)
|
} catch (e) {
|
||||||
|
console.error(e)
|
||||||
// 4. 提交成功后的操作:比如跳转或重置表单
|
} finally {
|
||||||
// router.push('/success')
|
|
||||||
} catch (error) {
|
|
||||||
d.destroy()
|
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>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
Reference in New Issue
Block a user