feat(表单信息展示): 支持多表单数据展示和筛选功能
- 重构表单数据解析逻辑,支持从数组格式中提取多表单数据 - 添加表单筛选按钮,可按表单标题筛选显示内容 - 优化数据结构处理,支持问答列表和旧格式的兼容 - 改进UI布局,添加表单标题和分割线提升可读性
This commit is contained in:
@@ -14,12 +14,26 @@
|
|||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<h3 class="card-title">表单信息</h3>
|
<h3 class="card-title">表单信息</h3>
|
||||||
|
<div class="form-filter">
|
||||||
|
<button
|
||||||
|
v-for="option in formFilterOptions"
|
||||||
|
:key="option"
|
||||||
|
class="form-filter-btn"
|
||||||
|
:class="{ active: formFilter === option }"
|
||||||
|
@click="formFilter = option"
|
||||||
|
>
|
||||||
|
{{ option }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<div class="form-data-list">
|
<div v-for="(section, sectionIndex) in displayedFormSections" :key="sectionIndex" class="form-section">
|
||||||
<div v-for="(field, index) in formFields" :key="index" class="form-field">
|
<div v-if="section.title" class="form-section-title">{{ section.title }}</div>
|
||||||
<span class="field-label">{{ field.label }}:</span>
|
<div class="form-data-list">
|
||||||
<span class="field-value">{{ field.value }}</span>
|
<div v-for="(field, index) in section.fields" :key="index" class="form-field">
|
||||||
|
<span class="field-label">{{ field.label }}:</span>
|
||||||
|
<span class="field-value">{{ field.value }}</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -132,7 +146,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed } from 'vue'
|
import { ref, computed, watch } from 'vue'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
|
|
||||||
// Props
|
// Props
|
||||||
@@ -166,79 +180,107 @@ const chatMessages = computed(() => {
|
|||||||
return props.chatInfo?.messages || []
|
return props.chatInfo?.messages || []
|
||||||
})
|
})
|
||||||
|
|
||||||
// 表单字段数据 (已更新)
|
const formFilter = ref('全部')
|
||||||
const formFields = computed(() => {
|
|
||||||
|
const formSections = computed(() => {
|
||||||
const formData = props.formInfo
|
const formData = props.formInfo
|
||||||
console.log(8888888,formData)
|
const emptyFields = [
|
||||||
// --- NEW LOGIC: 处理新的数组格式(问答列表) ---
|
{ label: '姓名', value: '暂无数据' },
|
||||||
if (Array.isArray(formData) && formData.length > 0) {
|
{ label: '联系方式', value: '暂无数据' },
|
||||||
// 检查数组项结构,确保是新的问答格式
|
{ label: '孩子信息', value: '暂无数据' },
|
||||||
if (formData[0].question_label && formData[0].answer) {
|
{ label: '地区', value: '暂无数据' }
|
||||||
// 直接将问答列表映射为 { label: question_label, value: answer } 格式
|
]
|
||||||
return formData.map(item => ({
|
|
||||||
label: item.question_label,
|
const makeSection = (fields, title = '表单信息') => [{ title, fields }]
|
||||||
value: item.answer || '暂无回答'
|
|
||||||
|
const buildFieldsFromAnswers = (answers = []) => {
|
||||||
|
return answers.map(item => ({
|
||||||
|
label: item.question_label,
|
||||||
|
value: item.answer || '暂无回答'
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
let dataArray = null
|
||||||
|
if (Array.isArray(formData)) {
|
||||||
|
dataArray = formData
|
||||||
|
} else if (formData && Array.isArray(formData.data)) {
|
||||||
|
dataArray = formData.data
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(dataArray) && dataArray.length > 0) {
|
||||||
|
if (dataArray[0].form_title && Array.isArray(dataArray[0].answers)) {
|
||||||
|
return dataArray.map(form => ({
|
||||||
|
title: form.form_title || '表单信息',
|
||||||
|
fields: buildFieldsFromAnswers(form.answers || [])
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
if (dataArray[0].question_label && Object.prototype.hasOwnProperty.call(dataArray[0], 'answer')) {
|
||||||
|
return makeSection(buildFieldsFromAnswers(dataArray))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// --------------------------------------------------
|
|
||||||
|
|
||||||
// Fallback: 如果数据为空、null 或旧的空对象格式
|
|
||||||
if (!formData || (typeof formData === 'object' && Object.keys(formData).length === 0)) {
|
if (!formData || (typeof formData === 'object' && Object.keys(formData).length === 0)) {
|
||||||
return [
|
return makeSection(emptyFields)
|
||||||
{ label: '姓名', value: '暂无数据' },
|
}
|
||||||
{ label: '联系方式', value: '暂无数据' },
|
|
||||||
{ label: '孩子信息', value: '暂无数据' },
|
let fields = []
|
||||||
{ label: '地区', value: '暂无数据' }
|
if (formData.name || formData.mobile || formData.child_name) {
|
||||||
|
const customerInfo = [formData.name, formData.mobile, formData.child_relation, formData.occupation].filter(item => item && item !== '暂无').join(' | ')
|
||||||
|
const childInfo = [formData.child_name, formData.child_gender, formData.child_education].filter(item => item && item !== '暂无').join(' | ')
|
||||||
|
|
||||||
|
fields = [
|
||||||
|
{ label: '客户信息', value: customerInfo || '暂无' },
|
||||||
|
{ label: '孩子信息', value: childInfo || '暂无' },
|
||||||
|
{ label: '地区', value: formData.territory || '暂无' }
|
||||||
|
]
|
||||||
|
|
||||||
|
if (formData.additional_info && Array.isArray(formData.additional_info)) {
|
||||||
|
formData.additional_info.forEach((item) => {
|
||||||
|
fields.push({
|
||||||
|
label: item.topic,
|
||||||
|
value: item.answer
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const customerInfo = [formData.expandTwentyOne, formData.expandOne].filter(item => item && item !== '暂无').join(' | ')
|
||||||
|
const childInfo = [formData.expandTwentyNine, formData.expandTwentyFive, formData.expandTwo].filter(item => item && item !== '暂无').join(' | ')
|
||||||
|
|
||||||
|
fields = [
|
||||||
|
{ label: '客户信息', value: customerInfo || '暂无' },
|
||||||
|
{ label: '孩子信息', value: childInfo || '暂无' },
|
||||||
|
{ label: '学习状态', value: formData.expandFive || '暂无' },
|
||||||
|
{ label: '沟通情况', value: formData.expandEight || '暂无' },
|
||||||
|
{ label: '主要问题', value: formData.expandTwentySeven || '暂无' },
|
||||||
|
{ label: '关注领域', value: formData.expandFifteen || '暂无' },
|
||||||
|
{ label: '学习成绩', value: formData.expandFourteen || '暂无' },
|
||||||
|
{ label: '孩子数量', value: formData.expandTwenty || '暂无' },
|
||||||
|
{ label: '预期时间', value: formData.expandThirty || '暂无' }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- OLD LOGIC: 处理旧的对象格式(保持兼容性) ---
|
return makeSection(fields)
|
||||||
let fields = []
|
|
||||||
|
|
||||||
// 检查是否为第一种格式(包含name, mobile等字段)
|
|
||||||
if (formData.name || formData.mobile || formData.child_name) {
|
|
||||||
const customerInfo = [formData.name, formData.mobile, formData.child_relation, formData.occupation].filter(item => item && item !== '暂无').join(' | ')
|
|
||||||
const childInfo = [formData.child_name, formData.child_gender, formData.child_education].filter(item => item && item !== '暂无').join(' | ')
|
|
||||||
|
|
||||||
fields = [
|
|
||||||
{ label: '客户信息', value: customerInfo || '暂无' },
|
|
||||||
{ label: '孩子信息', value: childInfo || '暂无' },
|
|
||||||
{ label: '地区', value: formData.territory || '暂无' }
|
|
||||||
]
|
|
||||||
|
|
||||||
// 如果有additional_info,添加所有问题
|
|
||||||
if (formData.additional_info && Array.isArray(formData.additional_info)) {
|
|
||||||
formData.additional_info.forEach((item) => {
|
|
||||||
fields.push({
|
|
||||||
label: item.topic,
|
|
||||||
value: item.answer
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 第二种格式(expandXXX字段)
|
|
||||||
const customerInfo = [formData.expandTwentyOne, formData.expandOne].filter(item => item && item !== '暂无').join(' | ')
|
|
||||||
const childInfo = [formData.expandTwentyNine, formData.expandTwentyFive, formData.expandTwo].filter(item => item && item !== '暂无').join(' | ')
|
|
||||||
|
|
||||||
fields = [
|
|
||||||
{ label: '客户信息', value: customerInfo || '暂无' },
|
|
||||||
{ label: '孩子信息', value: childInfo || '暂无' },
|
|
||||||
{ label: '学习状态', value: formData.expandFive || '暂无' },
|
|
||||||
{ label: '沟通情况', value: formData.expandEight || '暂无' },
|
|
||||||
{ label: '主要问题', value: formData.expandTwentySeven || '暂无' },
|
|
||||||
{ label: '关注领域', value: formData.expandFifteen || '暂无' },
|
|
||||||
{ label: '学习成绩', value: formData.expandFourteen || '暂无' },
|
|
||||||
{ label: '孩子数量', value: formData.expandTwenty || '暂无' },
|
|
||||||
{ label: '预期时间', value: formData.expandThirty || '暂无' }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
// 合并表单数据和聊天数据
|
|
||||||
const allFields = [...fields]
|
|
||||||
|
|
||||||
return allFields
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const formFilterOptions = computed(() => {
|
||||||
|
const titles = formSections.value.map(section => section.title).filter(Boolean)
|
||||||
|
const uniqueTitles = Array.from(new Set(titles))
|
||||||
|
if (uniqueTitles.length <= 1) return ['全部']
|
||||||
|
return ['全部', ...uniqueTitles]
|
||||||
|
})
|
||||||
|
|
||||||
|
const displayedFormSections = computed(() => {
|
||||||
|
if (formFilter.value === '全部') return formSections.value
|
||||||
|
const filtered = formSections.value.filter(section => section.title === formFilter.value)
|
||||||
|
return filtered.length > 0 ? filtered : formSections.value
|
||||||
|
})
|
||||||
|
|
||||||
|
watch(formFilterOptions, (options) => {
|
||||||
|
if (!options.includes(formFilter.value)) {
|
||||||
|
formFilter.value = options[0] || '全部'
|
||||||
|
}
|
||||||
|
}, { immediate: true })
|
||||||
|
|
||||||
|
|
||||||
// 聊天数据
|
// 聊天数据
|
||||||
const chatData = computed(() => ({
|
const chatData = computed(() => ({
|
||||||
@@ -507,6 +549,58 @@ const formatDateTime = (dateTimeString) => {
|
|||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.form-filter {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-filter-btn {
|
||||||
|
padding: 6px 12px;
|
||||||
|
border-radius: 999px;
|
||||||
|
border: 1px solid #e5e7eb;
|
||||||
|
background: #ffffff;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #6b7280;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-filter-btn.active {
|
||||||
|
border-color: #10b981;
|
||||||
|
color: #059669;
|
||||||
|
background: #ecfdf5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-filter-btn:hover {
|
||||||
|
color: #059669;
|
||||||
|
border-color: #a7f3d0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-section {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-section + .form-section {
|
||||||
|
margin-top: 16px;
|
||||||
|
padding-top: 12px;
|
||||||
|
border-top: 1px dashed #e5e7eb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-section-title {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #111827;
|
||||||
|
background: #f0fdf4;
|
||||||
|
border: 1px solid #dcfce7;
|
||||||
|
padding: 4px 10px;
|
||||||
|
border-radius: 999px;
|
||||||
|
width: fit-content;
|
||||||
|
}
|
||||||
|
|
||||||
// 表单字段样式
|
// 表单字段样式
|
||||||
.form-data-list {
|
.form-data-list {
|
||||||
.form-field {
|
.form-field {
|
||||||
@@ -884,4 +978,4 @@ const formatDateTime = (dateTimeString) => {
|
|||||||
gap: 10px;
|
gap: 10px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -605,7 +605,7 @@ async function getCustomerForm() {
|
|||||||
const res = await getCustomerFormInfo(params)
|
const res = await getCustomerFormInfo(params)
|
||||||
console.log('获取客户表单数据:', res)
|
console.log('获取客户表单数据:', res)
|
||||||
if(res.code === 200) {
|
if(res.code === 200) {
|
||||||
formInfo.value = res.data[0].answers || []
|
formInfo.value = res.data || []
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// 静默处理错误
|
// 静默处理错误
|
||||||
|
|||||||
Reference in New Issue
Block a user