722 lines
20 KiB
Vue
722 lines
20 KiB
Vue
<script setup>
|
||
import { computed, ref, watch, h } from 'vue'
|
||
import {
|
||
NButton,
|
||
NTag,
|
||
NTabs,
|
||
NTabPane,
|
||
NSpin,
|
||
NImage,
|
||
NImageGroup,
|
||
NDataTable,
|
||
} from 'naive-ui'
|
||
|
||
import { formatDate } from '@/utils'
|
||
import TheIcon from '@/components/icon/TheIcon.vue'
|
||
import CertificateModal from './CertificateModal.vue'
|
||
import api from '@/api'
|
||
import { useMessage } from 'naive-ui'
|
||
|
||
import { getStatusConfig } from '../constants'
|
||
import {
|
||
formatAgeDistribution,
|
||
formatAmount,
|
||
formatHistoricalEvidence,
|
||
formatPercent,
|
||
formatPlatformAccounts,
|
||
formatPriceRange,
|
||
formatThreeYearIncome,
|
||
formatNumberValue,
|
||
} from '../utils'
|
||
|
||
const props = defineProps({
|
||
loading: { type: Boolean, default: false },
|
||
detailData: { type: Object, default: null },
|
||
mode: { type: String, default: 'view' },
|
||
})
|
||
|
||
const emit = defineEmits(['back', 'approve', 'reject'])
|
||
const $message = useMessage()
|
||
|
||
const activeDetailTab = ref('audit')
|
||
|
||
// 证书弹窗相关状态
|
||
const certificateModalVisible = ref(false)
|
||
const certificateModalMode = ref('upload') // 'upload' 或 'view'
|
||
const certificateData = ref({})
|
||
|
||
watch(
|
||
() => props.detailData?.id,
|
||
() => {
|
||
activeDetailTab.value = 'audit'
|
||
}
|
||
)
|
||
|
||
const detailSections = computed(() => {
|
||
const detail = props.detailData
|
||
if (!detail) return []
|
||
|
||
const sections = [
|
||
{
|
||
key: 'basic',
|
||
title: '基础信息',
|
||
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.industry || '-' },
|
||
{ label: '业务/传承介绍', type: 'text', value: detail.business_heritage_intro || detail.biz_intro || '-' },
|
||
],
|
||
},
|
||
{
|
||
key: 'finance',
|
||
title: '财务状况',
|
||
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: 'text', value: detail.funding_status || '-' },
|
||
],
|
||
},
|
||
{
|
||
key: 'tech',
|
||
title: '非遗等级与技术',
|
||
fields: [
|
||
{ label: '非遗传承人等级', type: 'text', value: detail.inheritor_level || '-' },
|
||
{
|
||
label: '非遗传承人年龄水平及数量',
|
||
type: 'text',
|
||
// 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: 'images',
|
||
value: [...(detail.patent_certificates || []), ...(detail.pattern_images || [])],
|
||
},
|
||
],
|
||
},
|
||
{
|
||
key: 'promotion',
|
||
title: '非遗应用与推广',
|
||
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 || '-' },
|
||
{
|
||
label: '近12个月线下相关宣讲活动次数',
|
||
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) },
|
||
],
|
||
},
|
||
{
|
||
key: 'products',
|
||
title: '非遗资产衍生商品信息',
|
||
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 || '-' },
|
||
{ label: '最近一次市场活动时间', type: 'text', value: detail.last_market_activity || detail.market_activity_time || '-' },
|
||
{ label: '月交易额水平', type: 'text', value: detail.monthly_transaction || detail.monthly_transaction_amount || '-' },
|
||
{ label: '近30天价格区间', type: 'text', value: formatPriceRange(detail.price_fluctuation) },
|
||
],
|
||
},
|
||
]
|
||
|
||
// 为每个 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 || [])
|
||
|
||
const mockFlowHtml = ref(`
|
||
<div class="calc-flow-container">
|
||
<!-- 左侧:详细计算流程 -->
|
||
<div class="calc-flow-left">
|
||
<div class="calc-formula-header">
|
||
最终估值A12000=模型估值B12*0.7+市场估值C33*0.3
|
||
</div>
|
||
|
||
<div class="calc-section">
|
||
<div class="calc-section-title">一、模型估值B12=(经济价值B143*0.7+文化价值B255*0.3)*风险调整系数B343</div>
|
||
|
||
<div class="calc-subsection">
|
||
<div class="calc-subsection-title">1、经济价值B143=基础价值B1173*(1+流量因子B1212)*政策驱动B1345</div>
|
||
|
||
<div class="calc-item">
|
||
<div class="calc-item-label">(1) 基础价值B1173=财务价值P2000*(0.45+0.05*行业系数I0.8)+法律强度L0.3*(0.35+0.05*行业系数I0.8)+发展潜力D0.5*0.2</div>
|
||
<div class="calc-detail">
|
||
<div class="calc-detail-item">• 财务价值P2000=[3年内均收益10000*(1+增长率23%)*5]/5</div>
|
||
<div class="calc-detail-item">• 法律强度L12=专利分*12*0.4+商标分*12*0.3+版权分*12*0.3</div>
|
||
<div class="calc-detail-item">• 发展潜力D=专利分*0.5+ESG分*0.2+创新投入比*0.3</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="calc-item">
|
||
<div class="calc-item-label">(2) 流量因子B1212</div>
|
||
<div class="calc-detail">
|
||
<div class="calc-detail-item">• 近 30 天搜索指数M1</div>
|
||
<div class="calc-detail-item">• 行业均值S2</div>
|
||
<div class="calc-detail-item">• 社交媒体传播度S3</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="calc-item">
|
||
<div class="calc-item-label">(3) 政策驱动B13</div>
|
||
<div class="calc-detail">
|
||
<div class="calc-detail-item">• 政策契合度P</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="calc-subsection">
|
||
<div class="calc-subsection-title">2、文化价值B2</div>
|
||
|
||
<div class="calc-item">
|
||
<div class="calc-item-label">(1) 活态传承系数B21</div>
|
||
<div class="calc-detail">
|
||
<div class="calc-detail-item">• 传承人等级系数</div>
|
||
<div class="calc-detail-item">• 教学传播频次</div>
|
||
<div class="calc-detail-item">• 跨界合作深度</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="calc-item">
|
||
<div class="calc-item-label">(2) 纹样基因值B22</div>
|
||
<div class="calc-detail">
|
||
<div class="calc-detail-item">• 纹样复杂度SC</div>
|
||
<div class="calc-detail-item">• 归一化稀缺H</div>
|
||
<div class="calc-detail-item">• 历史承载度HI</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 右侧:计算流程大纲 -->
|
||
<div class="calc-flow-right">
|
||
<div class="calc-outline-title">最终估值A</div>
|
||
<div class="calc-outline">
|
||
<div class="outline-section">
|
||
<div class="outline-title">一、模型估值B</div>
|
||
<div class="outline-subsection">
|
||
<div class="outline-subtitle">1、经济价值B1</div>
|
||
<div class="outline-item">(1) 基础价值B11</div>
|
||
<div class="outline-detail">• 基础价值B1173=财务价值P2000*(0.45+0.05*行业系数I0.8)+法律强度L0.3*(0.35+0.05*行业系数I0.8)+发展潜力D0.5*0.2</div>
|
||
<div class="outline-item">(2) 流量因子B12</div>
|
||
<div class="outline-detail">• 近 30 天搜索指数M1</div>
|
||
<div class="outline-detail">• 行业均值S2</div>
|
||
<div class="outline-detail">• 社交媒体传播度S3</div>
|
||
<div class="outline-item">(3) 政策驱动B13</div>
|
||
<div class="outline-detail">• 政策契合度P</div>
|
||
</div>
|
||
|
||
<div class="outline-subsection">
|
||
<div class="outline-subtitle">2、文化价值B2</div>
|
||
<div class="outline-item">(1) 活态传承系数B21</div>
|
||
<div class="outline-detail">• 传承人等级系数</div>
|
||
<div class="outline-detail">• 教学传播频次</div>
|
||
<div class="outline-detail">• 跨界合作深度</div>
|
||
<div class="outline-item">(2) 纹样基因值B22</div>
|
||
<div class="outline-detail">• 纹样复杂度SC</div>
|
||
<div class="outline-detail">• 归一化稀缺H</div>
|
||
<div class="outline-detail">• 历史承载度HI</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
`)
|
||
|
||
|
||
// 证书相关功能
|
||
const handleUploadCertificate = () => {
|
||
certificateModalMode.value = 'upload'
|
||
certificateData.value = {}
|
||
certificateModalVisible.value = true
|
||
}
|
||
|
||
const handleViewCertificate = () => {
|
||
certificateModalMode.value = 'view'
|
||
|
||
const formatFiles = (urlData) => {
|
||
if (!urlData) return []
|
||
// Handle string (single or comma-separated)
|
||
const urls = typeof urlData === 'string' ? urlData.split(',') : (Array.isArray(urlData) ? urlData : [])
|
||
|
||
return urls.filter(u => u).map((url, index) => ({
|
||
id: String(index),
|
||
name: url.substring(url.lastIndexOf('/') + 1) || 'unknown',
|
||
status: 'finished',
|
||
url: url
|
||
}))
|
||
}
|
||
|
||
certificateData.value = {
|
||
reportFiles: formatFiles(props.detailData?.report_url),
|
||
certificateFiles: formatFiles(props.detailData?.certificate_url)
|
||
}
|
||
certificateModalVisible.value = true
|
||
}
|
||
|
||
const handleCertificateConfirm = async (data) => {
|
||
console.log('证书数据:', data)
|
||
|
||
try {
|
||
const certificateUrl = data.certificateFiles?.map(f => f.url).filter(Boolean) || []
|
||
const reportUrl = data.reportFiles?.map(f => f.url).filter(Boolean) || []
|
||
|
||
// 现在改为只能上传 1 张
|
||
const payload = {
|
||
...props.detailData,
|
||
certificate_url: certificateUrl?.[0],
|
||
report_url: reportUrl?.[0],
|
||
status: 'success'
|
||
}
|
||
|
||
await api.updateValuation(payload)
|
||
|
||
$message.success('上传并通知成功')
|
||
certificateModalVisible.value = false
|
||
emit('back') // 或者 emit('refresh') 取决于需求,这里假设返回列表或刷新
|
||
} catch (error) {
|
||
console.error('更新失败:', error)
|
||
$message.error('操作失败')
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<template>
|
||
<div class="audit-detail">
|
||
<div class="detail-header">
|
||
<div>
|
||
<button type="button" class="back-btn" @click="emit('back')">
|
||
<TheIcon icon="mdi:arrow-left" :size="16" class="mr-4" />
|
||
返回审核列表
|
||
</button>
|
||
<!-- <div class="detail-title">
|
||
<h2>{{ detailData?.asset_name || '审核详情' }}</h2>
|
||
<NTag size="small" :type="getStatusConfig(detailData?.status).type">
|
||
{{ getStatusConfig(detailData?.status).text }}
|
||
</NTag>
|
||
</div>
|
||
<p class="detail-meta">
|
||
<span>手机号:{{ detailData?.phone || '-' }}</span>
|
||
<span>微信号:{{ detailData?.wechat || '-' }}</span>
|
||
<span>提交时间:{{ formatDate(detailData?.created_at) }}</span>
|
||
<span>审核时间:{{ detailData?.reviewed_at ? formatDate(detailData?.reviewed_at) : '-' }}</span>
|
||
</p> -->
|
||
</div>
|
||
</div>
|
||
|
||
<NTabs
|
||
v-model:value="activeDetailTab"
|
||
type="line"
|
||
size="large"
|
||
class="audit-tabs"
|
||
>
|
||
<NTabPane name="audit" tab="审核信息">
|
||
<NSpin :show="loading">
|
||
<div v-for="section in detailSections" :key="section.key" class="detail-section">
|
||
<div class="section-title">
|
||
<span class="dot" />
|
||
<span>{{ section.title }}</span>
|
||
</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>
|
||
<NTabPane name="flow" tab="计算流程">
|
||
<NSpin :show="loading">
|
||
<div v-html="mockFlowHtml"></div>
|
||
</NSpin>
|
||
</NTabPane>
|
||
</NTabs>
|
||
|
||
<!-- 证书按钮 -->
|
||
<div class="certificate-actions">
|
||
<NButton
|
||
v-if="mode === 'approve'"
|
||
type="primary"
|
||
@click="handleUploadCertificate"
|
||
>
|
||
<TheIcon icon="mdi:upload" :size="16" class="mr-4" />
|
||
上传证书
|
||
</NButton>
|
||
<NButton
|
||
v-else
|
||
type="info"
|
||
@click="handleViewCertificate"
|
||
>
|
||
<TheIcon icon="mdi:eye" :size="16" class="mr-4" />
|
||
查看证书
|
||
</NButton>
|
||
</div>
|
||
|
||
<!-- 证书弹窗 -->
|
||
<CertificateModal
|
||
v-model:visible="certificateModalVisible"
|
||
:mode="certificateModalMode"
|
||
:certificate-data="certificateData"
|
||
@confirm="handleCertificateConfirm"
|
||
/>
|
||
</div>
|
||
</template>
|
||
|
||
<style scoped>
|
||
.audit-detail {
|
||
background: #fff;
|
||
border-radius: 12px;
|
||
padding: 24px;
|
||
.certificate-actions {
|
||
margin-top: 20px;
|
||
width: 100%;
|
||
display: flex;
|
||
justify-content: flex-end;
|
||
z-index: 100;
|
||
}
|
||
}
|
||
|
||
.detail-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
gap: 16px;
|
||
margin: -16px 0px 10px ;
|
||
}
|
||
|
||
.back-btn {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 4px;
|
||
padding: 0;
|
||
border: none;
|
||
background: transparent;
|
||
color: #409eff;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.detail-title {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 12px;
|
||
margin: 8px 0;
|
||
}
|
||
|
||
.detail-title h2 {
|
||
margin: 0;
|
||
font-size: 20px;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.detail-meta {
|
||
margin: 0;
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 16px;
|
||
color: #666;
|
||
font-size: 13px;
|
||
}
|
||
|
||
.detail-actions {
|
||
display: flex;
|
||
gap: 12px;
|
||
align-items: center;
|
||
}
|
||
|
||
.detail-section {
|
||
margin-bottom: 24px;
|
||
}
|
||
|
||
.audit-tabs :deep(.n-tabs-nav) {
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
.audit-tabs :deep(.n-tabs-tab) {
|
||
font-size: 16px;
|
||
font-weight: 500;
|
||
color: #1d2129;
|
||
padding: 0 24px;
|
||
}
|
||
|
||
.audit-tabs :deep(.n-tabs-tab.n-tabs-tab--active) {
|
||
color: #ff6f3b;
|
||
}
|
||
|
||
.audit-tabs :deep(.n-tabs-nav__line) {
|
||
background-color: #ff6f3b;
|
||
height: 3px;
|
||
border-radius: 999px;
|
||
}
|
||
|
||
.section-title {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 12px;
|
||
font-weight: 600;
|
||
margin-bottom: 12px;
|
||
font-size: 18px;
|
||
color: #1d2129;
|
||
}
|
||
|
||
.section-title .dot {
|
||
width: 10px;
|
||
height: 18px;
|
||
border-radius: 4px;
|
||
background: #3b82f6;
|
||
}
|
||
|
||
.detail-section :deep(.n-data-table) {
|
||
background: #f9fafe;
|
||
}
|
||
|
||
.detail-section :deep(.n-data-table-th) {
|
||
background: #f1f2f5;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.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 {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 4px;
|
||
}
|
||
|
||
/* 计算流程容器 */
|
||
:deep(.calc-flow-container) {
|
||
display: flex;
|
||
gap: 24px;
|
||
min-height: 600px;
|
||
}
|
||
|
||
/* 左侧详细流程 */
|
||
:deep(.calc-flow-left) {
|
||
flex: 1;
|
||
background: #f8f9fa;
|
||
padding: 20px;
|
||
border-radius: 8px;
|
||
overflow-y: auto;
|
||
max-height: 800px;
|
||
}
|
||
|
||
:deep(.calc-formula-header) {
|
||
font-size: 18px;
|
||
font-weight: 600;
|
||
color: #1d2129;
|
||
margin-bottom: 24px;
|
||
padding-bottom: 16px;
|
||
border-bottom: 2px solid #e5e7eb;
|
||
}
|
||
|
||
:deep(.calc-section) {
|
||
margin-bottom: 24px;
|
||
}
|
||
|
||
:deep(.calc-section-title) {
|
||
font-size: 16px;
|
||
font-weight: 600;
|
||
color: #1d2129;
|
||
margin-bottom: 16px;
|
||
line-height: 1.6;
|
||
}
|
||
|
||
:deep(.calc-subsection) {
|
||
margin-left: 20px;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
:deep(.calc-subsection-title) {
|
||
font-size: 15px;
|
||
font-weight: 600;
|
||
color: #374151;
|
||
margin-bottom: 12px;
|
||
line-height: 1.6;
|
||
}
|
||
|
||
:deep(.calc-item) {
|
||
margin-left: 20px;
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
:deep(.calc-item-label) {
|
||
font-size: 14px;
|
||
color: #4b5563;
|
||
margin-bottom: 8px;
|
||
line-height: 1.6;
|
||
}
|
||
|
||
:deep(.calc-detail) {
|
||
margin-left: 20px;
|
||
margin-top: 8px;
|
||
}
|
||
|
||
:deep(.calc-detail-item) {
|
||
font-size: 13px;
|
||
color: #6b7280;
|
||
margin-bottom: 4px;
|
||
line-height: 1.6;
|
||
}
|
||
|
||
/* 右侧大纲 */
|
||
:deep(.calc-flow-right) {
|
||
width: 320px;
|
||
background: #fff;
|
||
border: 1px solid #e5e7eb;
|
||
border-radius: 8px;
|
||
padding: 20px;
|
||
overflow-y: auto;
|
||
max-height: 800px;
|
||
}
|
||
|
||
:deep(.calc-outline-title) {
|
||
font-size: 16px;
|
||
font-weight: 600;
|
||
color: #1d2129;
|
||
margin-bottom: 16px;
|
||
padding-bottom: 12px;
|
||
border-bottom: 2px solid #e5e7eb;
|
||
}
|
||
|
||
:deep(.calc-outline) {
|
||
font-size: 13px;
|
||
}
|
||
|
||
:deep(.outline-section) {
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
:deep(.outline-title) {
|
||
font-size: 14px;
|
||
font-weight: 600;
|
||
color: #1d2129;
|
||
margin-bottom: 8px;
|
||
}
|
||
|
||
:deep(.outline-subsection) {
|
||
margin-left: 12px;
|
||
margin-bottom: 12px;
|
||
}
|
||
|
||
:deep(.outline-subtitle) {
|
||
font-size: 13px;
|
||
font-weight: 600;
|
||
color: #374151;
|
||
margin-bottom: 6px;
|
||
}
|
||
|
||
:deep(.outline-item) {
|
||
font-size: 12px;
|
||
color: #4b5563;
|
||
margin-bottom: 4px;
|
||
margin-left: 12px;
|
||
}
|
||
|
||
:deep(.outline-detail) {
|
||
font-size: 11px;
|
||
color: #6b7280;
|
||
margin-left: 24px;
|
||
margin-bottom: 2px;
|
||
line-height: 1.5;
|
||
}
|
||
|
||
.calc-empty {
|
||
text-align: center;
|
||
color: #999;
|
||
padding: 40px 0;
|
||
}
|
||
|
||
|
||
</style>
|