refactor: 优化估值审核详情页表格显示,改用NDataTable组件解决表头显示问题

This commit is contained in:
Wei_佳 2025-11-14 11:25:29 +08:00
parent b63306890d
commit 60b2a2777d

View File

@ -1,5 +1,5 @@
<script setup>
import { computed, ref, watch } from 'vue'
import { computed, ref, watch, h } from 'vue'
import {
NButton,
NTag,
@ -8,6 +8,7 @@ import {
NSpin,
NImage,
NImageGroup,
NDataTable,
} from 'naive-ui'
import { formatDate } from '@/utils'
@ -45,11 +46,12 @@ watch(
const detailSections = computed(() => {
const detail = props.detailData
if (!detail) return []
return [
const sections = [
{
key: 'basic',
title: '基础信息',
columns: [
fields: [
{ label: '资产名称', type: 'text', value: detail.asset_name || '-' },
{ label: '所属机构', type: 'text', value: detail.institution || '-' },
{ label: '所属行业', type: 'text', value: detail.industry || '-' },
@ -58,7 +60,7 @@ const detailSections = computed(() => {
{
key: 'finance',
title: '财务状况',
columns: [
fields: [
{ label: '近12个月机构营收/万元', type: 'text', value: formatNumberValue(detail.annual_revenue) },
{ label: '近12个月机构研发投入/万元', type: 'text', value: formatNumberValue(detail.rd_investment) },
{ label: '近三年机构收益/万元', type: 'list', value: formatThreeYearIncome(detail.three_year_income) },
@ -68,7 +70,7 @@ const detailSections = computed(() => {
{
key: 'tech',
title: '非遗等级与技术',
columns: [
fields: [
{ label: '非遗传承人等级', type: 'text', value: detail.inheritor_level || '-' },
{ label: '非遗传承人年龄水平及数量', type: 'list', value: formatAgeDistribution(detail.inheritor_age_count) },
{ label: '非遗传承人等级证书', type: 'images', value: detail.inheritor_certificates || [] },
@ -85,7 +87,7 @@ const detailSections = computed(() => {
{
key: 'promotion',
title: '非遗应用与推广',
columns: [
fields: [
{ label: '非遗资产应用成熟度', type: 'text', value: detail.application_maturity || detail.implementation_stage || '-' },
{ label: '非遗资产应用覆盖范围', type: 'text', value: detail.application_coverage || detail.coverage_area || '-' },
{ label: '非遗资产跨界合作深度', type: 'text', value: detail.cooperation_depth || detail.collaboration_type || '-' },
@ -96,7 +98,7 @@ const detailSections = computed(() => {
{
key: 'products',
title: '非遗资产衍生商品信息',
columns: [
fields: [
{ label: '代表产品近12个月销售数量', type: 'text', value: formatNumberValue(detail.sales_volume) },
{ label: '商品链接浏览量', type: 'text', value: formatNumberValue(detail.link_views) },
{ label: '发行量', type: 'text', value: detail.circulation || detail.scarcity_level || '-' },
@ -106,6 +108,73 @@ const detailSections = computed(() => {
],
},
]
// section NDataTable columns data
return sections.map(section => {
const columns = [
{
title: '字段名',
key: 'fieldName',
width: 120,
align: 'center',
fixed: 'left',
},
...section.fields.map(field => ({
title: field.label,
key: field.label,
width: 200,
ellipsis: {
tooltip: true,
},
render: (row) => {
const fieldData = row[field.label]
if (!fieldData) return '-'
if (fieldData.type === 'list') {
if (fieldData.value && fieldData.value.length) {
return h('div', { class: 'cell-multi' },
fieldData.value.map(item => h('span', item))
)
}
return '-'
} else if (fieldData.type === 'images') {
if (fieldData.value && fieldData.value.length) {
return h(NImageGroup, {}, () =>
fieldData.value.map(img =>
h(NImage, {
src: img,
width: 72,
height: 48,
objectFit: 'cover',
style: 'margin-right: 8px;'
})
)
)
}
return '-'
} else {
return fieldData.value || '-'
}
}
})),
]
const data = [
{
fieldName: '用户输入',
...section.fields.reduce((acc, field) => {
acc[field.label] = field
return acc
}, {}),
},
]
return {
...section,
columns,
data,
}
})
})
const calcFlow = computed(() => props.detailData?.calculation_result?.flow || [])
@ -152,47 +221,17 @@ const calcFlow = computed(() => props.detailData?.calculation_result?.flow || []
<span class="dot" />
<span>{{ section.title }}</span>
</div>
<div class="table-wrapper">
<table class="info-table">
<thead>
<tr>
<th class="first-col">字段名</th>
<th v-for="column in section.columns" :key="column.label">
{{ column.label }}
</th>
</tr>
</thead>
<tbody>
<tr>
<td class="first-col">用户输入</td>
<td v-for="column in section.columns" :key="column.label">
<div v-if="column.type === 'list'" class="cell-multi">
<template v-if="column.value && column.value.length">
<span v-for="(item, idx) in column.value" :key="idx">{{ item }}</span>
</template>
<span v-else>-</span>
</div>
<div v-else-if="column.type === 'images'">
<template v-if="column.value && column.value.length">
<NImageGroup>
<NImage
v-for="(img, idx) in column.value"
:key="idx"
width="72"
height="48"
:src="img"
object-fit="cover"
/>
</NImageGroup>
</template>
<span v-else>-</span>
</div>
<span v-else>{{ column.value || '-' }}</span>
</td>
</tr>
</tbody>
</table>
</div>
<NDataTable
:columns="section.columns"
:data="section.data"
:bordered="true"
:single-line="false"
:scroll-x="section.fields.length * 200 + 120"
>
<template #empty>
<span>暂无数据</span>
</template>
</NDataTable>
</div>
</NSpin>
</NTabPane>
@ -305,36 +344,24 @@ const calcFlow = computed(() => props.detailData?.calculation_result?.flow || []
background: #409eff;
}
.table-wrapper {
overflow-x: auto;
}
.info-table {
width: 100%;
border-collapse: collapse;
.detail-section :deep(.n-data-table) {
background: #f9fafe;
table-layout: fixed;
}
.info-table th,
.info-table td {
border: 1px solid #e5e6eb;
padding: 12px;
text-align: left;
min-width: 140px;
word-break: break-word;
}
.info-table .first-col {
width: 120px;
text-align: center;
.detail-section :deep(.n-data-table-th) {
background: #f1f2f5;
font-weight: 600;
}
.info-table th:not(.first-col),
.info-table td:not(.first-col) {
width: 180px;
.detail-section :deep(.n-data-table-th:first-child) {
background: #f1f2f5;
text-align: center;
}
.detail-section :deep(.n-data-table-td:first-child) {
background: #f1f2f5;
text-align: center;
font-weight: 600;
}
.cell-multi {