fix(导出): 修复客户数据导出功能并增强表单数据处理
- 更新导出API端点以匹配后端接口变更 - 重构表单数据解析逻辑,支持多种数据结构格式 - 动态生成Excel列宽,避免数据截断 - 添加客户姓名字段到导出数据 - 优化重复字段处理,确保导出数据完整性
This commit is contained in:
@@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
Reference in New Issue
Block a user