fix(导出): 修复客户数据导出功能并增强表单数据处理
- 更新导出API端点以匹配后端接口变更 - 重构表单数据解析逻辑,支持多种数据结构格式 - 动态生成Excel列宽,避免数据截断 - 添加客户姓名字段到导出数据 - 优化重复字段处理,确保导出数据完整性
This commit is contained in:
@@ -87,7 +87,7 @@ export const cancelSwitchHistoryCampPeriod = (params) => {
|
||||
|
||||
// 一键导出 api/v1/level_four/overview/export_customers
|
||||
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)
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -90,12 +90,14 @@ async function exportData() {
|
||||
try {
|
||||
ElMessage.info('正在导出数据,请稍候...')
|
||||
console.log('导出参数:', params)
|
||||
const res = await exportCustomers(params)
|
||||
const res = await exportCustomers()
|
||||
if (res.code === 200 && res.data && res.data.length > 0) {
|
||||
ElMessage.success('数据导出成功')
|
||||
// 处理数据,将复杂的嵌套对象展平
|
||||
const exportData = res.data.map(customer => {
|
||||
const flatData = {
|
||||
'昵称': customer.nickname || '',
|
||||
'客户姓名': customer.customer_name || '',
|
||||
'性别': customer.gender || '',
|
||||
'跟进人': customer.follow_up_name || '',
|
||||
'手机号': customer.phone || '',
|
||||
@@ -103,18 +105,104 @@ async function exportData() {
|
||||
'用户ID': customer.mantis_user_id || '',
|
||||
}
|
||||
|
||||
// 处理微信表单信息
|
||||
if (customer.wechat_form) {
|
||||
flatData['家长姓名'] = customer.wechat_form.name || ''
|
||||
flatData['孩子姓名'] = customer.wechat_form.child_name || ''
|
||||
flatData['孩子性别'] = customer.wechat_form.child_gender || ''
|
||||
flatData['职业'] = customer.wechat_form.occupation || ''
|
||||
flatData['孩子教育阶段'] = customer.wechat_form.child_education || ''
|
||||
flatData['与孩子关系'] = customer.wechat_form.child_relation || ''
|
||||
flatData['联系电话'] = customer.wechat_form.mobile || ''
|
||||
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 parseFormData = (formData) => {
|
||||
if (typeof formData === 'string') {
|
||||
try {
|
||||
return JSON.parse(formData)
|
||||
} catch (e) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
return formData || null
|
||||
}
|
||||
|
||||
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) {
|
||||
customer.wechat_form.additional_info.forEach((item) => {
|
||||
flatData[item.topic || ''] = item.answer || ''
|
||||
if (parsedFormData && parsedFormData.additional_info) {
|
||||
parsedFormData.additional_info.forEach((item) => {
|
||||
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 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 = [
|
||||
{ wch: 10 }, // 昵称
|
||||
{ wch: 6 }, // 性别
|
||||
{ wch: 12 }, // 跟进人
|
||||
{ wch: 15 }, // 手机号
|
||||
{ wch: 10 }, // 是否入群
|
||||
{ wch: 20 }, // 用户ID
|
||||
{ wch: 12 }, // 家长姓名
|
||||
{ wch: 12 }, // 孩子姓名
|
||||
{ wch: 8 }, // 孩子性别
|
||||
{ wch: 12 }, // 职业
|
||||
{ wch: 12 }, // 孩子教育阶段
|
||||
{ wch: 15 }, // 与孩子关系
|
||||
{ wch: 15 }, // 联系电话
|
||||
{ wch: 20 }, // 地区
|
||||
{ wch: 20 }, // 创建时间
|
||||
{ wch: 20 }, // 更新时间
|
||||
]
|
||||
const colWidths = allKeys.map(key => {
|
||||
const maxCellLength = exportData.reduce((max, row) => {
|
||||
const value = row[key]
|
||||
const length = value === null || value === undefined ? 0 : String(value).length
|
||||
return Math.max(max, length)
|
||||
}, 0)
|
||||
return { wch: Math.min(50, Math.max(10, key.length, maxCellLength)) }
|
||||
})
|
||||
ws['!cols'] = colWidths
|
||||
|
||||
// 添加工作表到工作簿
|
||||
@@ -356,4 +438,4 @@ async function exportData() {
|
||||
color: #909399;
|
||||
font-size: 16px;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user