fix: 增强报告生成的数据校验,并优化报告模板的数据处理与格式化。
This commit is contained in:
parent
5332324b10
commit
7c59d3385a
Binary file not shown.
@ -12,6 +12,11 @@ import {
|
||||
|
||||
export const generateReport = async (detailData) => {
|
||||
try {
|
||||
// Validate input
|
||||
if (!detailData || typeof detailData !== 'object') {
|
||||
throw new Error('无效的详情数据')
|
||||
}
|
||||
|
||||
// Load the template
|
||||
const response = await fetch('/report_template.docx')
|
||||
if (!response.ok) {
|
||||
@ -23,99 +28,146 @@ export const generateReport = async (detailData) => {
|
||||
const doc = new Docxtemplater(zip, {
|
||||
paragraphLoop: true,
|
||||
linebreaks: true,
|
||||
delimiters: { start: '[', end: ']' },
|
||||
delimiters: { start: '${', end: '}' },
|
||||
// 当字段不存在时,保持原始的 ${字段名} 格式,不替换
|
||||
nullGetter: (part) => {
|
||||
if (!part.module) {
|
||||
return '${' + part.value + '}'
|
||||
}
|
||||
return ''
|
||||
},
|
||||
})
|
||||
|
||||
// Helper to get safe number
|
||||
const getNum = (val) => (val || val === 0 ? Number(val) : '-')
|
||||
const getWan = (val) => (val || val === 0 ? formatNumberValue(val) : '-')
|
||||
|
||||
// Prepare data
|
||||
const data = {
|
||||
...detailData,
|
||||
// Summary
|
||||
B: getWan(detailData.model_value_b),
|
||||
B1: getWan(detailData.economic_value_b1),
|
||||
B2: getWan(detailData.cultural_value_b2),
|
||||
B3: getNum(detailData.risk_coefficient_b3),
|
||||
C: getWan(detailData.market_value_c),
|
||||
DPR: getNum(detailData.pledge_rate),
|
||||
|
||||
// Basic Info
|
||||
asset_name: detailData.asset_name || '-',
|
||||
institution: detailData.institution || '-',
|
||||
credit_code: detailData.credit_code || detailData.credit_code_or_id || '-',
|
||||
industry: detailData.industry || '-',
|
||||
business_heritage_intro: detailData.business_heritage_intro || detailData.biz_intro || '-',
|
||||
|
||||
// Finance
|
||||
annual_revenue: getWan(detailData.annual_revenue),
|
||||
rd_investment: getWan(detailData.rd_investment),
|
||||
three_year_income: Array.isArray(detailData.three_year_income) ? detailData.three_year_income.join(',') : '-',
|
||||
funding_status: detailData.funding_status || '-',
|
||||
|
||||
// Tech / Non-heritage attributes
|
||||
heritage_level: detailData.heritage_level || detailData.heritage_asset_level || '-',
|
||||
inheritor_age_count_50: detailData.inheritor_age_count?.[0] || 0,
|
||||
inheritor_age_count_50_70: detailData.inheritor_age_count?.[1] || 0,
|
||||
inheritor_age_count_70: detailData.inheritor_age_count?.[2] || 0,
|
||||
|
||||
historical_evidence_artifacts: detailData.historical_evidence?.artifacts || 0,
|
||||
historical_evidence_literature: detailData.historical_evidence?.ancient_literature || 0,
|
||||
historical_evidence_testimony: detailData.historical_evidence?.inheritor_testimony || 0,
|
||||
historical_evidence_research: detailData.historical_evidence?.modern_research || 0,
|
||||
|
||||
offline_activities: getNum(detailData.offline_activities ?? detailData.offline_teaching_count),
|
||||
online_clicks: getWan(detailData.online_clicks), // Assuming this field exists or needs mapping
|
||||
|
||||
// Market
|
||||
platform_accounts_bilibili: detailData.platform_accounts?.bilibili?.account || '-',
|
||||
platform_accounts_douyin: detailData.platform_accounts?.douyin?.account || '-',
|
||||
price_fluctuation_min: detailData.price_fluctuation?.[0] || '-',
|
||||
price_fluctuation_max: detailData.price_fluctuation?.[1] || '-',
|
||||
monthly_transaction: detailData.monthly_transaction || detailData.monthly_transaction_amount || '-',
|
||||
circulation: detailData.circulation || detailData.scarcity_level || '-',
|
||||
|
||||
// Detailed Parameters (Assuming these keys exist in detailData or calculation_result)
|
||||
// Economic Value B1
|
||||
B11: getWan(detailData.basic_value_b11),
|
||||
F: getWan(detailData.financial_value_p),
|
||||
L: getNum(detailData.legal_strength_l),
|
||||
D: getNum(detailData.development_potential_d),
|
||||
|
||||
B12: getNum(detailData.traffic_factor_b12),
|
||||
search_index_ratio: getNum(detailData.search_index_ratio),
|
||||
S3: getNum(detailData.social_media_spread_s3),
|
||||
|
||||
B13: getNum(detailData.policy_multiplier_b13),
|
||||
policy_fit_score: getNum(detailData.policy_fit_score),
|
||||
|
||||
// Cultural Value B2
|
||||
B21: getNum(detailData.living_inheritance_b21),
|
||||
inheritor_level_score: getNum(detailData.inheritor_level_score),
|
||||
teaching_frequency_score: getNum(detailData.teaching_frequency_score),
|
||||
cooperation_depth_score: getNum(detailData.cooperation_depth_score),
|
||||
|
||||
B22: getNum(detailData.pattern_entropy_b22),
|
||||
SC: getNum(detailData.structure_complexity_sc),
|
||||
H: getNum(detailData.info_entropy_h),
|
||||
HI: getNum(detailData.history_inheritance_hi),
|
||||
|
||||
// Risk
|
||||
risk_market: getNum(detailData.risk_market),
|
||||
risk_legal: getNum(detailData.risk_legal),
|
||||
risk_inheritance: getNum(detailData.risk_inheritance),
|
||||
|
||||
// Market Verification
|
||||
C1: getWan(detailData.market_bidding_c1),
|
||||
C2: getNum(detailData.heat_coefficient_c2),
|
||||
C3: getNum(detailData.scarcity_multiplier_c3),
|
||||
C4: getNum(detailData.time_decay_c4),
|
||||
|
||||
// Current Date
|
||||
current_date: new Date().toLocaleDateString('zh-CN'),
|
||||
// Helper function to safely add field only if it exists
|
||||
const addIfExists = (obj, key, value) => {
|
||||
if (value !== undefined && value !== null) {
|
||||
obj[key] = value
|
||||
}
|
||||
}
|
||||
|
||||
// Extract calculation data
|
||||
const calcInput = detailData.calculation_input || {}
|
||||
const calcResult = detailData.calculation_result || {}
|
||||
const modelData = calcInput.model_data || {}
|
||||
const ecoData = modelData.economic_data || {}
|
||||
const cultData = modelData.cultural_data || {}
|
||||
const riskData = modelData.risky_data || {}
|
||||
const marketData = calcInput.market_data || {}
|
||||
|
||||
// Prepare data - only include fields that actually exist
|
||||
const data = {
|
||||
// Spread all existing detailData fields
|
||||
...detailData,
|
||||
|
||||
// Date fields (always generated)
|
||||
yyyy: new Date().getFullYear(),
|
||||
mm: String(new Date().getMonth() + 1).padStart(2, '0'),
|
||||
dd: String(new Date().getDate()).padStart(2, '0'),
|
||||
yyyymmdd: `${new Date().getFullYear()}${String(new Date().getMonth() + 1).padStart(2, '0')}${String(new Date().getDate()).padStart(2, '0')}`,
|
||||
}
|
||||
|
||||
// Handle inheritor_age_count array - format each item
|
||||
if (detailData.inheritor_age_count && Array.isArray(detailData.inheritor_age_count)) {
|
||||
const ageData = formatAgeDistribution(detailData.inheritor_age_count)
|
||||
// 提供格式化后的完整文本
|
||||
data.inheritor_age_count_text = ageData.join('\n')
|
||||
// 提供单独的数值,支持 ${inheritor_age_count[0]} 这样的用法
|
||||
if (detailData.inheritor_age_count[0] !== undefined) {
|
||||
data['inheritor_age_count[0]'] = detailData.inheritor_age_count[0]
|
||||
}
|
||||
if (detailData.inheritor_age_count[1] !== undefined) {
|
||||
data['inheritor_age_count[1]'] = detailData.inheritor_age_count[1]
|
||||
}
|
||||
if (detailData.inheritor_age_count[2] !== undefined) {
|
||||
data['inheritor_age_count[2]'] = detailData.inheritor_age_count[2]
|
||||
}
|
||||
}
|
||||
|
||||
// Handle historical_evidence object - format as text
|
||||
if (detailData.historical_evidence && typeof detailData.historical_evidence === 'object') {
|
||||
const evidenceData = formatHistoricalEvidence(detailData.historical_evidence)
|
||||
// 提供格式化后的完整文本(换行分隔)
|
||||
data.historical_evidence = evidenceData.join('\n')
|
||||
}
|
||||
|
||||
// Handle platform_accounts object - format as text
|
||||
if (detailData.platform_accounts && typeof detailData.platform_accounts === 'object') {
|
||||
const accountsData = formatPlatformAccounts(detailData.platform_accounts)
|
||||
// 提供格式化后的完整文本(换行分隔)
|
||||
data.platform_accounts = accountsData.join('\n')
|
||||
}
|
||||
|
||||
// Handle price_fluctuation array
|
||||
if (detailData.price_fluctuation && Array.isArray(detailData.price_fluctuation)) {
|
||||
const min = detailData.price_fluctuation[0]
|
||||
const max = detailData.price_fluctuation[1]
|
||||
|
||||
// 提供单独的数值,支持 ${price_fluctuation[0]} 这样的用法
|
||||
if (min !== undefined) {
|
||||
data['price_fluctuation[0]'] = min
|
||||
data.price_min = min
|
||||
}
|
||||
if (max !== undefined) {
|
||||
data['price_fluctuation[1]'] = max
|
||||
data.price_max = max
|
||||
}
|
||||
|
||||
// 提供多种格式的范围文本
|
||||
if (min !== undefined && max !== undefined) {
|
||||
// 简单范围(数字-数字)
|
||||
data.price_range = `${min}-${max}`
|
||||
// 带"元"的范围
|
||||
data.price_range_yuan = `${min}-${max}元`
|
||||
// 带货币符号的范围
|
||||
data.price_fluctuation_range = formatPriceRange(detailData.price_fluctuation)
|
||||
// 精确匹配模板中的字段名(作为一个整体的字段名)
|
||||
data['price_fluctuation[0]-price_fluctuation[1]'] = `${min}-${max}`
|
||||
}
|
||||
}
|
||||
|
||||
// Add calculation results if they exist
|
||||
if (calcResult.model_value_b !== undefined) data.B = formatNumberValue(calcResult.model_value_b)
|
||||
if (calcResult.economic_value_b1 !== undefined) data.B1 = formatNumberValue(calcResult.economic_value_b1)
|
||||
if (calcResult.cultural_value_b2 !== undefined) data.B2 = formatNumberValue(calcResult.cultural_value_b2)
|
||||
if (calcResult.risk_adjustment_b3 !== undefined) data.B3 = calcResult.risk_adjustment_b3
|
||||
if (calcResult.market_value_c !== undefined) data.C = formatNumberValue(calcResult.market_value_c)
|
||||
|
||||
// Add DPR if exists
|
||||
const dpr = detailData.drp_result?.dynamic_pledge_rate || detailData.dynamic_pledge_rate
|
||||
if (dpr !== undefined) data.DPR = dpr
|
||||
|
||||
// Add economic data fields if they exist
|
||||
if (ecoData.basic_value_b11 !== undefined) data.B11 = formatNumberValue(ecoData.basic_value_b11)
|
||||
if (ecoData.financial_value !== undefined) data.F = formatNumberValue(ecoData.financial_value)
|
||||
if (ecoData.legal_strength !== undefined) data.L = ecoData.legal_strength
|
||||
if (ecoData.development_potential !== undefined) data.D = ecoData.development_potential
|
||||
if (ecoData.traffic_factor_b12 !== undefined) data.B12 = ecoData.traffic_factor_b12
|
||||
if (ecoData.search_index_s1 !== undefined) data.search_index_ratio = ecoData.search_index_s1
|
||||
if (ecoData.social_media_spread_s3 !== undefined) data.S3 = ecoData.social_media_spread_s3
|
||||
if (ecoData.policy_multiplier_b13 !== undefined) data.B13 = ecoData.policy_multiplier_b13
|
||||
if (ecoData.policy_compatibility_score !== undefined) data.policy_fit_score = ecoData.policy_compatibility_score
|
||||
|
||||
// Add cultural data fields if they exist
|
||||
if (cultData.living_inheritance_b21 !== undefined) data.B21 = cultData.living_inheritance_b21
|
||||
if (cultData.inheritor_level_coefficient !== undefined) data.inheritor_level_score = cultData.inheritor_level_coefficient
|
||||
if (cultData.teaching_frequency !== undefined) data.teaching_frequency_score = cultData.teaching_frequency
|
||||
if (cultData.cross_border_depth !== undefined) data.cooperation_depth_score = cultData.cross_border_depth
|
||||
if (cultData.pattern_entropy_b22 !== undefined) data.B22 = cultData.pattern_entropy_b22
|
||||
if (cultData.structure_complexity !== undefined) data.SC = cultData.structure_complexity
|
||||
if (cultData.normalized_entropy !== undefined) data.H = cultData.normalized_entropy
|
||||
if (cultData.historical_inheritance !== undefined) data.HI = cultData.historical_inheritance
|
||||
|
||||
// Add risk data fields if they exist
|
||||
if (riskData.risk_market !== undefined) data.risk_market = riskData.risk_market
|
||||
if (riskData.risk_legal !== undefined) data.risk_legal = riskData.risk_legal
|
||||
if (riskData.risk_inheritance !== undefined) data.risk_inheritance = riskData.risk_inheritance
|
||||
|
||||
// Add market data fields if they exist
|
||||
if (marketData.market_bidding_c1 !== undefined) data.C1 = formatNumberValue(marketData.market_bidding_c1)
|
||||
if (marketData.heat_coefficient_c2 !== undefined) data.C2 = marketData.heat_coefficient_c2
|
||||
if (marketData.scarcity_multiplier_c3 !== undefined) data.C3 = marketData.scarcity_multiplier_c3
|
||||
if (marketData.time_decay_c4 !== undefined) data.C4 = marketData.time_decay_c4
|
||||
|
||||
doc.render(data)
|
||||
|
||||
const out = doc.getZip().generate({
|
||||
|
||||
@ -63,9 +63,9 @@ const detailSections = computed(() => {
|
||||
fields: [
|
||||
{ label: '资产名称', type: 'text', value: detail.asset_name || '-' },
|
||||
{ label: '所属机构/权利人', type: 'text', value: detail.institution || '-' },
|
||||
{ label: '统一社会信用代码/身份证号', type: 'text', value: detail.credit_code || detail.credit_code_or_id || '-' },
|
||||
{ label: '统一社会信用代码/身份证号', type: 'text', value: detail.credit_code_or_id || '-' },
|
||||
{ label: '所属行业', type: 'text', value: detail.industry || '-' },
|
||||
{ label: '业务/传承介绍', type: 'text', value: detail.business_heritage_intro || detail.biz_intro || '-' },
|
||||
{ label: '业务/传承介绍', type: 'text', value: detail.biz_intro || '-' },
|
||||
],
|
||||
},
|
||||
{
|
||||
@ -74,8 +74,7 @@ const detailSections = computed(() => {
|
||||
fields: [
|
||||
{ label: '近12个月机构营收/万元', type: 'text', value: formatNumberValue(detail.annual_revenue) },
|
||||
{ label: '近12个月机构研发投入/万元', type: 'text', value: formatNumberValue(detail.rd_investment) },
|
||||
{ label: '近三年机构收益/万元', type: 'text', value: formatThreeYearIncome(detail.three_year_income) },
|
||||
// { label: '近三年机构收益/万元', type: 'list', value: formatThreeYearIncome(detail.three_year_income) },
|
||||
{ label: '近三年机构收益/万元', type: 'list', value: formatThreeYearIncome(detail.three_year_income) },
|
||||
{ label: '资产受资助情况', type: 'text', value: detail.funding_status || '-' },
|
||||
],
|
||||
},
|
||||
@ -86,15 +85,13 @@ const detailSections = computed(() => {
|
||||
{ label: '非遗传承人等级', type: 'text', value: detail.inheritor_level || '-' },
|
||||
{
|
||||
label: '非遗传承人年龄水平及数量',
|
||||
type: 'text',
|
||||
// type: 'list',
|
||||
type: 'list',
|
||||
value: formatAgeDistribution(detail.inheritor_age_count || detail.inheritor_ages),
|
||||
},
|
||||
{ label: '非遗传承人等级证书', type: 'images', value: detail.inheritor_certificates || [] },
|
||||
{ label: '非遗等级', type: 'text', value: detail.heritage_level || detail.heritage_asset_level || '-' },
|
||||
{ label: '非遗资产所用专利的申请号', type: 'text', value: detail.patent_application_no || '-' },
|
||||
{ label: '非遗资产历史证明证据及数量', type: 'text', value: formatHistoricalEvidence(detail.historical_evidence) },
|
||||
// { label: '非遗资产历史证明证据及数量', type: 'list', value: formatHistoricalEvidence(detail.historical_evidence) },
|
||||
{ label: '非遗资产历史证明证据及数量', type: 'list', value: formatHistoricalEvidence(detail.historical_evidence) },
|
||||
{
|
||||
label: '非遗资产所用专利/纹样图片',
|
||||
type: 'images',
|
||||
@ -114,8 +111,7 @@ const detailSections = computed(() => {
|
||||
type: 'text',
|
||||
value: formatNumberValue(detail.offline_activities ?? detail.offline_teaching_count),
|
||||
},
|
||||
{ label: '线上相关宣传账号信息', type: 'text', value: formatPlatformAccounts(detail.platform_accounts) },
|
||||
// { label: '线上相关宣传账号信息', type: 'list', value: formatPlatformAccounts(detail.platform_accounts) },
|
||||
{ label: '线上相关宣传账号信息', type: 'list', value: formatPlatformAccounts(detail.platform_accounts) },
|
||||
],
|
||||
},
|
||||
{
|
||||
@ -146,7 +142,7 @@ const detailSections = computed(() => {
|
||||
title: field.label,
|
||||
key: field.label,
|
||||
width: 200,
|
||||
ellipsis: {
|
||||
ellipsis: field.type === 'list' ? false : {
|
||||
tooltip: true,
|
||||
},
|
||||
render: (row) => {
|
||||
@ -155,7 +151,7 @@ const detailSections = computed(() => {
|
||||
|
||||
if (fieldData.type === 'list') {
|
||||
if (fieldData.value && fieldData.value.length) {
|
||||
return h('div', { class: 'cell-multi' },
|
||||
return h('div', { style: 'display: flex; flex-direction: column; gap: 4px;' },
|
||||
fieldData.value.map(item => h('span', item))
|
||||
)
|
||||
}
|
||||
@ -305,7 +301,9 @@ const mockFlowHtml = ref(`
|
||||
// 证书相关功能
|
||||
const handleUploadCertificate = () => {
|
||||
certificateModalMode.value = 'upload'
|
||||
certificateData.value = {}
|
||||
certificateData.value = {
|
||||
detailData: props.detailData
|
||||
}
|
||||
certificateModalVisible.value = true
|
||||
}
|
||||
|
||||
|
||||
@ -165,6 +165,10 @@ const isUploadMode = computed(() => props.mode === 'upload')
|
||||
// 下载报告
|
||||
const handleDownloadReport = async () => {
|
||||
try {
|
||||
if (!props.certificateData?.detailData) {
|
||||
message.error('缺少详情数据,无法生成报告')
|
||||
return
|
||||
}
|
||||
message.loading('正在生成报告...')
|
||||
await generateReport(props.certificateData.detailData)
|
||||
message.success('报告生成并下载成功')
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user