招标解析页面
This commit is contained in:
parent
62b8abc4a8
commit
a8b86d5f77
|
|
@ -212,7 +212,7 @@ export default {
|
||||||
// 表格最大高度(像素),默认700px
|
// 表格最大高度(像素),默认700px
|
||||||
tableMaxHeight: {
|
tableMaxHeight: {
|
||||||
type: [Number, String],
|
type: [Number, String],
|
||||||
default: 700,
|
default: 650,
|
||||||
},
|
},
|
||||||
// 是否自动加载数据 默认自动加载
|
// 是否自动加载数据 默认自动加载
|
||||||
autoLoad: {
|
autoLoad: {
|
||||||
|
|
|
||||||
|
|
@ -52,14 +52,14 @@ import analysisResultMock from '../analysisResultMock.json'
|
||||||
const HTML_TAG_REG = /<\/?[a-z][\s\S]*>/i
|
const HTML_TAG_REG = /<\/?[a-z][\s\S]*>/i
|
||||||
const MAX_PARSE_DEPTH = 5
|
const MAX_PARSE_DEPTH = 5
|
||||||
|
|
||||||
const formatSectionValue = (raw, depth = 0) => {
|
function formatSectionValue(raw, depth = 0) {
|
||||||
const fallback = { content: '--', isHtml: false }
|
const fallback = { content: '--', isHtml: false, tableRows: null }
|
||||||
if (raw === undefined || raw === null) {
|
if (raw === undefined || raw === null) {
|
||||||
return fallback
|
return fallback
|
||||||
}
|
}
|
||||||
if (depth > MAX_PARSE_DEPTH) {
|
if (depth > MAX_PARSE_DEPTH) {
|
||||||
const content = String(raw)
|
const content = String(raw)
|
||||||
return { content, isHtml: HTML_TAG_REG.test(content) }
|
return { content, isHtml: HTML_TAG_REG.test(content), tableRows: null }
|
||||||
}
|
}
|
||||||
if (typeof raw === 'string') {
|
if (typeof raw === 'string') {
|
||||||
const trimmed = raw.trim()
|
const trimmed = raw.trim()
|
||||||
|
|
@ -70,10 +70,14 @@ const formatSectionValue = (raw, depth = 0) => {
|
||||||
const parsed = JSON.parse(trimmed)
|
const parsed = JSON.parse(trimmed)
|
||||||
return formatSectionValue(parsed, depth + 1)
|
return formatSectionValue(parsed, depth + 1)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return { content: trimmed, isHtml: HTML_TAG_REG.test(trimmed) }
|
return { content: trimmed, isHtml: HTML_TAG_REG.test(trimmed), tableRows: null }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (Array.isArray(raw)) {
|
if (Array.isArray(raw)) {
|
||||||
|
const tableRows = buildTableRows(raw, depth)
|
||||||
|
if (tableRows.length > 0) {
|
||||||
|
return { content: '', isHtml: false, tableRows }
|
||||||
|
}
|
||||||
const lines = raw.map(item => {
|
const lines = raw.map(item => {
|
||||||
if (typeof item === 'object' && item !== null) {
|
if (typeof item === 'object' && item !== null) {
|
||||||
const label = item.name || item.label || item.title || item.key || ''
|
const label = item.name || item.label || item.title || item.key || ''
|
||||||
|
|
@ -84,7 +88,7 @@ const formatSectionValue = (raw, depth = 0) => {
|
||||||
return formatSectionValue(item, depth + 1).content
|
return formatSectionValue(item, depth + 1).content
|
||||||
}).filter(Boolean)
|
}).filter(Boolean)
|
||||||
const content = lines.length > 0 ? lines.join('\n') : '--'
|
const content = lines.length > 0 ? lines.join('\n') : '--'
|
||||||
return { content, isHtml: false }
|
return { content, isHtml: false, tableRows: null }
|
||||||
}
|
}
|
||||||
if (typeof raw === 'object') {
|
if (typeof raw === 'object') {
|
||||||
if (Object.prototype.hasOwnProperty.call(raw, 'value')) {
|
if (Object.prototype.hasOwnProperty.call(raw, 'value')) {
|
||||||
|
|
@ -95,10 +99,34 @@ const formatSectionValue = (raw, depth = 0) => {
|
||||||
return `${key}:${formatted.content}`
|
return `${key}:${formatted.content}`
|
||||||
}).filter(Boolean)
|
}).filter(Boolean)
|
||||||
const content = lines.length > 0 ? lines.join('\n') : '--'
|
const content = lines.length > 0 ? lines.join('\n') : '--'
|
||||||
return { content, isHtml: false }
|
return { content, isHtml: false, tableRows: null }
|
||||||
}
|
}
|
||||||
const content = String(raw)
|
const content = String(raw)
|
||||||
return { content, isHtml: HTML_TAG_REG.test(content) }
|
return { content, isHtml: HTML_TAG_REG.test(content), tableRows: null }
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildTableRows(items, depth) {
|
||||||
|
const rows = items.map(item => {
|
||||||
|
if (typeof item !== 'object' || item === null) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
const title = item.name ?? item.label ?? item.title ?? item.key ?? ''
|
||||||
|
if (!title && title !== 0) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
const valueSource = item.content ?? item.value ?? item.text ?? item.desc ?? item.detail
|
||||||
|
const formatted = formatSectionValue(valueSource, depth + 1)
|
||||||
|
const nestedTable = formatted.tableRows && formatted.tableRows.length > 0
|
||||||
|
? formatted.tableRows.map(row => `${row.title}:${row.value}`).join('\n')
|
||||||
|
: ''
|
||||||
|
const value = nestedTable || formatted.content || '--'
|
||||||
|
return {
|
||||||
|
title,
|
||||||
|
value,
|
||||||
|
isHtml: formatted.isHtml
|
||||||
|
}
|
||||||
|
}).filter(Boolean)
|
||||||
|
return rows
|
||||||
}
|
}
|
||||||
|
|
||||||
const collectSectionsFromNode = (node) => {
|
const collectSectionsFromNode = (node) => {
|
||||||
|
|
@ -111,7 +139,8 @@ const collectSectionsFromNode = (node) => {
|
||||||
id: target.id,
|
id: target.id,
|
||||||
title: target.name,
|
title: target.name,
|
||||||
content: formatted.content,
|
content: formatted.content,
|
||||||
isHtml: formatted.isHtml
|
isHtml: formatted.isHtml,
|
||||||
|
tableRows: formatted.tableRows
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if (target.children && target.children.length) {
|
if (target.children && target.children.length) {
|
||||||
|
|
|
||||||
|
|
@ -17,10 +17,33 @@
|
||||||
<div class="content-section" v-for="section in subTab.sections"
|
<div class="content-section" v-for="section in subTab.sections"
|
||||||
:key="section.id">
|
:key="section.id">
|
||||||
<div class="section-title">{{ section.title }}</div>
|
<div class="section-title">{{ section.title }}</div>
|
||||||
|
<template v-if="hasTable(section.tableRows)">
|
||||||
|
<table class="section-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>标题</th>
|
||||||
|
<th>内容</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr v-for="row in section.tableRows"
|
||||||
|
:key="`${section.id}-${row.title}`">
|
||||||
|
<td class="cell-title">{{ row.title }}</td>
|
||||||
|
<td class="cell-value">
|
||||||
|
<div v-if="!row.isHtml"
|
||||||
|
v-html="formatPlainText(row.value)"></div>
|
||||||
|
<div v-else v-html="row.value"></div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
<div class="section-content" v-if="!section.isHtml"
|
<div class="section-content" v-if="!section.isHtml"
|
||||||
v-html="formatPlainText(section.content)"></div>
|
v-html="formatPlainText(section.content)"></div>
|
||||||
<div class="section-content html-content" v-else v-html="section.content">
|
<div class="section-content html-content" v-else v-html="section.content">
|
||||||
</div>
|
</div>
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<div v-else class="empty-content">暂无数据</div>
|
<div v-else class="empty-content">暂无数据</div>
|
||||||
|
|
@ -33,9 +56,32 @@
|
||||||
<template v-if="hasSections(tab.sections)">
|
<template v-if="hasSections(tab.sections)">
|
||||||
<div class="content-section" v-for="section in tab.sections" :key="section.id">
|
<div class="content-section" v-for="section in tab.sections" :key="section.id">
|
||||||
<div class="section-title">{{ section.title }}</div>
|
<div class="section-title">{{ section.title }}</div>
|
||||||
<div class="section-content" v-if="!section.isHtml"
|
<template v-if="hasTable(section.tableRows)">
|
||||||
v-html="formatPlainText(section.content)"></div>
|
<table class="section-table">
|
||||||
<div class="section-content html-content" v-else v-html="section.content"></div>
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>标题</th>
|
||||||
|
<th>内容</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr v-for="row in section.tableRows"
|
||||||
|
:key="`${section.id}-${row.title}`">
|
||||||
|
<td class="cell-title">{{ row.title }}</td>
|
||||||
|
<td class="cell-value">
|
||||||
|
<div v-if="!row.isHtml"
|
||||||
|
v-html="formatPlainText(row.value)"></div>
|
||||||
|
<div v-else v-html="row.value"></div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<div class="section-content" v-if="!section.isHtml"
|
||||||
|
v-html="formatPlainText(section.content)"></div>
|
||||||
|
<div class="section-content html-content" v-else v-html="section.content"></div>
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<div v-else class="empty-content">暂无数据</div>
|
<div v-else class="empty-content">暂无数据</div>
|
||||||
|
|
@ -57,10 +103,33 @@
|
||||||
<div class="content-section" v-for="section in subTab.sections"
|
<div class="content-section" v-for="section in subTab.sections"
|
||||||
:key="section.id">
|
:key="section.id">
|
||||||
<div class="section-title">{{ section.title }}</div>
|
<div class="section-title">{{ section.title }}</div>
|
||||||
<div class="section-content" v-if="!section.isHtml"
|
<template v-if="hasTable(section.tableRows)">
|
||||||
v-html="formatPlainText(section.content)"></div>
|
<table class="section-table">
|
||||||
<div class="section-content html-content" v-else
|
<thead>
|
||||||
v-html="section.content"></div>
|
<tr>
|
||||||
|
<th>标题</th>
|
||||||
|
<th>内容</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr v-for="row in section.tableRows"
|
||||||
|
:key="`${section.id}-${row.title}`">
|
||||||
|
<td class="cell-title">{{ row.title }}</td>
|
||||||
|
<td class="cell-value">
|
||||||
|
<div v-if="!row.isHtml"
|
||||||
|
v-html="formatPlainText(row.value)"></div>
|
||||||
|
<div v-else v-html="row.value"></div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<div class="section-content" v-if="!section.isHtml"
|
||||||
|
v-html="formatPlainText(section.content)"></div>
|
||||||
|
<div class="section-content html-content" v-else
|
||||||
|
v-html="section.content"></div>
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<div v-else class="empty-content">暂无数据</div>
|
<div v-else class="empty-content">暂无数据</div>
|
||||||
|
|
@ -73,10 +142,34 @@
|
||||||
<template v-if="hasSections(tab.sections)">
|
<template v-if="hasSections(tab.sections)">
|
||||||
<div class="content-section" v-for="section in tab.sections" :key="section.id">
|
<div class="content-section" v-for="section in tab.sections" :key="section.id">
|
||||||
<div class="section-title">{{ section.title }}</div>
|
<div class="section-title">{{ section.title }}</div>
|
||||||
<div class="section-content" v-if="!section.isHtml"
|
<template v-if="hasTable(section.tableRows)">
|
||||||
v-html="formatPlainText(section.content)"></div>
|
<table class="section-table">
|
||||||
<div class="section-content html-content" v-else v-html="section.content">
|
<thead>
|
||||||
</div>
|
<tr>
|
||||||
|
<th>标题</th>
|
||||||
|
<th>内容</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr v-for="row in section.tableRows"
|
||||||
|
:key="`${section.id}-${row.title}`">
|
||||||
|
<td class="cell-title">{{ row.title }}</td>
|
||||||
|
<td class="cell-value">
|
||||||
|
<div v-if="!row.isHtml"
|
||||||
|
v-html="formatPlainText(row.value)"></div>
|
||||||
|
<div v-else v-html="row.value"></div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<div class="section-content" v-if="!section.isHtml"
|
||||||
|
v-html="formatPlainText(section.content)"></div>
|
||||||
|
<div class="section-content html-content" v-else
|
||||||
|
v-html="section.content">
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<div v-else class="empty-content">暂无数据</div>
|
<div v-else class="empty-content">暂无数据</div>
|
||||||
|
|
@ -193,6 +286,9 @@ export default {
|
||||||
hasSections(sections) {
|
hasSections(sections) {
|
||||||
return Array.isArray(sections) && sections.length > 0
|
return Array.isArray(sections) && sections.length > 0
|
||||||
},
|
},
|
||||||
|
hasTable(rows) {
|
||||||
|
return Array.isArray(rows) && rows.length > 0
|
||||||
|
},
|
||||||
formatPlainText(text) {
|
formatPlainText(text) {
|
||||||
if (!text) {
|
if (!text) {
|
||||||
return '--'
|
return '--'
|
||||||
|
|
@ -404,7 +500,7 @@ export default {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
padding: 20px;
|
padding: 20px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-tab-pane {
|
.el-tab-pane {
|
||||||
|
|
@ -416,8 +512,7 @@ export default {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
// padding: 20px;
|
padding: 20px;
|
||||||
padding: 20px 0;
|
|
||||||
|
|
||||||
.empty-content {
|
.empty-content {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
@ -458,5 +553,38 @@ export default {
|
||||||
border: 1px solid #EBEEF5;
|
border: 1px solid #EBEEF5;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.section-table {
|
||||||
|
width: 100%;
|
||||||
|
border: 1px solid #EBEEF5;
|
||||||
|
border-collapse: collapse;
|
||||||
|
font-size: 14px;
|
||||||
|
background: #FFFFFF;
|
||||||
|
|
||||||
|
th,
|
||||||
|
td {
|
||||||
|
border: 1px solid #EBEEF5;
|
||||||
|
padding: 12px 16px;
|
||||||
|
text-align: left;
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
|
||||||
|
th {
|
||||||
|
background: #FAFBFF;
|
||||||
|
color: #909399;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cell-title {
|
||||||
|
width: 180px;
|
||||||
|
color: #303133;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cell-value {
|
||||||
|
color: #606266;
|
||||||
|
word-break: break-word;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue