feat(表单信息展示): 支持多表单数据展示和筛选功能

- 重构表单数据解析逻辑,支持从数组格式中提取多表单数据
- 添加表单筛选按钮,可按表单标题筛选显示内容
- 优化数据结构处理,支持问答列表和旧格式的兼容
- 改进UI布局,添加表单标题和分割线提升可读性
This commit is contained in:
2026-01-23 18:56:46 +08:00
parent 2cd59adfc9
commit 8260b345dc
2 changed files with 163 additions and 69 deletions

View File

@@ -14,16 +14,30 @@
</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 v-for="(section, sectionIndex) in displayedFormSections" :key="sectionIndex" class="form-section">
<div v-if="section.title" class="form-section-title">{{ section.title }}</div>
<div class="form-data-list"> <div class="form-data-list">
<div v-for="(field, index) in formFields" :key="index" class="form-field"> <div v-for="(field, index) in section.fields" :key="index" class="form-field">
<span class="field-label">{{ field.label }}:</span> <span class="field-label">{{ field.label }}:</span>
<span class="field-value">{{ field.value }}</span> <span class="field-value">{{ field.value }}</span>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div>
<!-- 聊天记录和通话录音卡片 --> <!-- 聊天记录和通话录音卡片 -->
<div class="data-card communication-card"> <div class="data-card communication-card">
@@ -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,37 +180,50 @@ const chatMessages = computed(() => {
return props.chatInfo?.messages || [] return props.chatInfo?.messages || []
}) })
// 表单字段数据 (已更新) const formFilter = ref('全部')
const formFields = computed(() => {
const formData = props.formInfo
console.log(8888888,formData)
// --- NEW LOGIC: 处理新的数组格式(问答列表) ---
if (Array.isArray(formData) && formData.length > 0) {
// 检查数组项结构,确保是新的问答格式
if (formData[0].question_label && formData[0].answer) {
// 直接将问答列表映射为 { label: question_label, value: answer } 格式
return formData.map(item => ({
label: item.question_label,
value: item.answer || '暂无回答'
}))
}
}
// --------------------------------------------------
// Fallback: 如果数据为空、null 或旧的空对象格式 const formSections = computed(() => {
if (!formData || (typeof formData === 'object' && Object.keys(formData).length === 0)) { const formData = props.formInfo
return [ const emptyFields = [
{ label: '姓名', value: '暂无数据' }, { label: '姓名', value: '暂无数据' },
{ label: '联系方式', value: '暂无数据' }, { label: '联系方式', value: '暂无数据' },
{ label: '孩子信息', value: '暂无数据' }, { label: '孩子信息', value: '暂无数据' },
{ label: '地区', value: '暂无数据' } { label: '地区', value: '暂无数据' }
] ]
const makeSection = (fields, title = '表单信息') => [{ title, fields }]
const buildFieldsFromAnswers = (answers = []) => {
return answers.map(item => ({
label: item.question_label,
value: item.answer || '暂无回答'
}))
} }
// --- OLD LOGIC: 处理旧的对象格式(保持兼容性) --- let dataArray = null
let fields = [] if (Array.isArray(formData)) {
dataArray = formData
} else if (formData && Array.isArray(formData.data)) {
dataArray = formData.data
}
// 检查是否为第一种格式包含name, mobile等字段 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))
}
}
if (!formData || (typeof formData === 'object' && Object.keys(formData).length === 0)) {
return makeSection(emptyFields)
}
let fields = []
if (formData.name || formData.mobile || formData.child_name) { 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 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(' | ') const childInfo = [formData.child_name, formData.child_gender, formData.child_education].filter(item => item && item !== '暂无').join(' | ')
@@ -207,7 +234,6 @@ console.log(8888888,formData)
{ label: '地区', value: formData.territory || '暂无' } { label: '地区', value: formData.territory || '暂无' }
] ]
// 如果有additional_info添加所有问题
if (formData.additional_info && Array.isArray(formData.additional_info)) { if (formData.additional_info && Array.isArray(formData.additional_info)) {
formData.additional_info.forEach((item) => { formData.additional_info.forEach((item) => {
fields.push({ fields.push({
@@ -217,7 +243,6 @@ console.log(8888888,formData)
}) })
} }
} else { } else {
// 第二种格式expandXXX字段
const customerInfo = [formData.expandTwentyOne, formData.expandOne].filter(item => item && item !== '暂无').join(' | ') const customerInfo = [formData.expandTwentyOne, formData.expandOne].filter(item => item && item !== '暂无').join(' | ')
const childInfo = [formData.expandTwentyNine, formData.expandTwentyFive, formData.expandTwo].filter(item => item && item !== '暂无').join(' | ') const childInfo = [formData.expandTwentyNine, formData.expandTwentyFive, formData.expandTwo].filter(item => item && item !== '暂无').join(' | ')
@@ -233,12 +258,29 @@ console.log(8888888,formData)
{ label: '预期时间', value: formData.expandThirty || '暂无' } { label: '预期时间', value: formData.expandThirty || '暂无' }
] ]
} }
// 合并表单数据和聊天数据
const allFields = [...fields]
return allFields return makeSection(fields)
}) })
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 {

View File

@@ -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) {
// 静默处理错误 // 静默处理错误