fix(导出): 修复客户数据导出功能并增强表单数据处理

- 更新导出API端点以匹配后端接口变更
- 重构表单数据解析逻辑,支持多种数据结构格式
- 动态生成Excel列宽,避免数据截断
- 添加客户姓名字段到导出数据
- 优化重复字段处理,确保导出数据完整性
This commit is contained in:
2026-01-29 19:58:21 +08:00
parent 8260b345dc
commit b2ce9d93db
2 changed files with 119 additions and 37 deletions

View File

@@ -87,7 +87,7 @@ export const cancelSwitchHistoryCampPeriod = (params) => {
// 一键导出 api/v1/level_four/overview/export_customers // 一键导出 api/v1/level_four/overview/export_customers
export const exportCustomers = (params) => { export const exportCustomers = (params) => {
return https.post('/api/v1/level_four/overview/export_customers', params) return https.post('/api/v1/level_four/overview/export_all_customers_under_sales', params)
} }

View File

@@ -90,12 +90,14 @@ async function exportData() {
try { try {
ElMessage.info('正在导出数据,请稍候...') ElMessage.info('正在导出数据,请稍候...')
console.log('导出参数:', params) console.log('导出参数:', params)
const res = await exportCustomers(params) const res = await exportCustomers()
if (res.code === 200 && res.data && res.data.length > 0) { if (res.code === 200 && res.data && res.data.length > 0) {
ElMessage.success('数据导出成功')
// 处理数据,将复杂的嵌套对象展平 // 处理数据,将复杂的嵌套对象展平
const exportData = res.data.map(customer => { const exportData = res.data.map(customer => {
const flatData = { const flatData = {
'昵称': customer.nickname || '', '昵称': customer.nickname || '',
'客户姓名': customer.customer_name || '',
'性别': customer.gender || '', '性别': customer.gender || '',
'跟进人': customer.follow_up_name || '', '跟进人': customer.follow_up_name || '',
'手机号': customer.phone || '', '手机号': customer.phone || '',
@@ -103,18 +105,104 @@ async function exportData() {
'用户ID': customer.mantis_user_id || '', '用户ID': customer.mantis_user_id || '',
} }
// 处理微信表单信息 const parseFormData = (formData) => {
if (customer.wechat_form) { if (typeof formData === 'string') {
flatData['家长姓名'] = customer.wechat_form.name || '' try {
flatData['孩子姓名'] = customer.wechat_form.child_name || '' return JSON.parse(formData)
flatData['孩子性别'] = customer.wechat_form.child_gender || '' } catch (e) {
flatData['职业'] = customer.wechat_form.occupation || '' return null
flatData['孩子教育阶段'] = customer.wechat_form.child_education || '' }
flatData['与孩子关系'] = customer.wechat_form.child_relation || '' }
flatData['联系电话'] = customer.wechat_form.mobile || '' return formData || null
flatData['地区'] = customer.wechat_form.territory || '' }
flatData['创建时间'] = customer.wechat_form.created_at ? new Date(customer.wechat_form.created_at).toLocaleString() : ''
flatData['更新时间'] = customer.wechat_form.updated_at ? new Date(customer.wechat_form.updated_at).toLocaleString() : '' const normalizeFormArray = (formData) => {
const data = parseFormData(formData)
console.log('解析后的表单数据:', data)
if (Array.isArray(data)) return data
if (data && Array.isArray(data.data)) return data.data
if (data && typeof data === 'object' && !data.answers) {
const numericKeys = Object.keys(data).filter(key => String(Number(key)) === key)
if (numericKeys.length > 0) {
return numericKeys
.sort((a, b) => Number(a) - Number(b))
.map(key => data[key])
.filter(Boolean)
}
}
if (data && data.answers) return [data]
return data ? [data] : []
}
const ensureUniqueKey = (key) => {
if (!flatData[key]) return key
let index = 2
while (flatData[`${key}(${index})`]) {
index += 1
}
return `${key}(${index})`
}
const parsedFormData = parseFormData(customer.wechat_form)
const formArray = normalizeFormArray(parsedFormData)
if (formArray.length > 0) {
console.log('表单数组:', formArray)
const isAnswerList = formArray.every(item => item && item.question_label && Object.prototype.hasOwnProperty.call(item, 'answer'))
const isFormWithAnswers = formArray.every(item => item && Array.isArray(item.answers))
console.log('是否为答案列表:', isAnswerList)
console.log('是否为表单含 answers:', isFormWithAnswers)
if (isAnswerList) {
let formAnswerCount = 0
formArray.forEach((answerItem) => {
const label = String(answerItem.question_label || '').trim()
if (!label) return
const key = ensureUniqueKey(label)
flatData[key] = answerItem.answer ?? ''
formAnswerCount += 1
})
if (formAnswerCount === 0 && formArray.length > 0) {
const fallbackKey = ensureUniqueKey('表单答案')
flatData[fallbackKey] = formArray.map(item => `${item.question_label || ''}: ${item.answer || ''}`).join(' | ')
}
} else if (isFormWithAnswers) {
console.log('表单含 answers:', formArray)
formArray.forEach((formItem) => {
const formTitle = formItem.form_title || '表单'
if (Array.isArray(formItem.answers)) {
let formAnswerCount = 0
formItem.answers.forEach((answerItem) => {
const label = String(answerItem.question_label || '').trim()
if (!label) return
const key = ensureUniqueKey(`${formTitle}-${label}`)
flatData[key] = answerItem.answer ?? ''
formAnswerCount += 1
})
if (formAnswerCount === 0 && formItem.answers.length > 0) {
const fallbackKey = ensureUniqueKey(`${formTitle}-表单答案`)
flatData[fallbackKey] = formItem.answers.map(item => `${item.question_label || ''}: ${item.answer || ''}`).join(' | ')
}
}
if (formItem.created_at) {
const key = ensureUniqueKey(`${formTitle}-创建时间`)
flatData[key] = new Date(formItem.created_at).toLocaleString()
}
if (formItem.updated_at) {
const key = ensureUniqueKey(`${formTitle}-更新时间`)
flatData[key] = new Date(formItem.updated_at).toLocaleString()
}
})
}
} else if (parsedFormData && typeof parsedFormData === 'object') {
flatData['家长姓名'] = parsedFormData.name || ''
flatData['孩子姓名'] = parsedFormData.child_name || ''
flatData['孩子性别'] = parsedFormData.child_gender || ''
flatData['职业'] = parsedFormData.occupation || ''
flatData['孩子教育阶段'] = parsedFormData.child_education || ''
flatData['与孩子关系'] = parsedFormData.child_relation || ''
flatData['联系电话'] = parsedFormData.mobile || ''
flatData['地区'] = parsedFormData.territory || ''
flatData['创建时间'] = parsedFormData.created_at ? new Date(parsedFormData.created_at).toLocaleString() : ''
flatData['更新时间'] = parsedFormData.updated_at ? new Date(parsedFormData.updated_at).toLocaleString() : ''
} }
// 处理到课情况 // 处理到课情况
@@ -126,9 +214,12 @@ async function exportData() {
} }
// 处理问卷调查信息 // 处理问卷调查信息
if (customer.wechat_form && customer.wechat_form.additional_info) { if (parsedFormData && parsedFormData.additional_info) {
customer.wechat_form.additional_info.forEach((item) => { parsedFormData.additional_info.forEach((item) => {
flatData[item.topic || ''] = item.answer || '' const key = ensureUniqueKey(item.topic || '')
if (key) {
flatData[key] = item.answer || ''
}
}) })
} }
@@ -137,27 +228,18 @@ async function exportData() {
// 创建工作簿 // 创建工作簿
const wb = XLSX.utils.book_new() const wb = XLSX.utils.book_new()
const ws = XLSX.utils.json_to_sheet(exportData) const allKeys = Array.from(new Set(exportData.flatMap(item => Object.keys(item))))
const ws = XLSX.utils.json_to_sheet(exportData, { header: allKeys })
// 设置列宽 // 设置列宽
const colWidths = [ const colWidths = allKeys.map(key => {
{ wch: 10 }, // 昵称 const maxCellLength = exportData.reduce((max, row) => {
{ wch: 6 }, // 性别 const value = row[key]
{ wch: 12 }, // 跟进人 const length = value === null || value === undefined ? 0 : String(value).length
{ wch: 15 }, // 手机号 return Math.max(max, length)
{ wch: 10 }, // 是否入群 }, 0)
{ wch: 20 }, // 用户ID return { wch: Math.min(50, Math.max(10, key.length, maxCellLength)) }
{ wch: 12 }, // 家长姓名 })
{ wch: 12 }, // 孩子姓名
{ wch: 8 }, // 孩子性别
{ wch: 12 }, // 职业
{ wch: 12 }, // 孩子教育阶段
{ wch: 15 }, // 与孩子关系
{ wch: 15 }, // 联系电话
{ wch: 20 }, // 地区
{ wch: 20 }, // 创建时间
{ wch: 20 }, // 更新时间
]
ws['!cols'] = colWidths ws['!cols'] = colWidths
// 添加工作表到工作簿 // 添加工作表到工作簿
@@ -356,4 +438,4 @@ async function exportData() {
color: #909399; color: #909399;
font-size: 16px; font-size: 16px;
} }
</style> </style>