Merge remote-tracking branch 'origin/0.8.X' into 0.8.X

This commit is contained in:
2026-07-03 15:58:51 +08:00
11 changed files with 764 additions and 324 deletions

View File

@@ -0,0 +1,488 @@
<template>
<div class="app-container cost-trend-page">
<!-- 筛选区 -->
<el-card class="mb8">
<div class="filter-bar">
<el-radio-group
v-model="selectedLine"
size="small"
@change="onLineChange"
>
<el-radio-button
v-for="line in productionLines"
:key="line.lineId"
:label="line.lineId"
>
{{ line.lineName }}
</el-radio-button>
</el-radio-group>
<el-button type="primary" size="small" icon="el-icon-search" :loading="loading" @click="fetchData">
查询
</el-button>
</div>
</el-card>
<!-- 统计摘要 -->
<div v-if="reports.length > 0" class="stats-row">
<div class="stat-item stat-blue">
<span class="stat-val">{{ reports.length }}</span>
<span class="stat-label">参与报表数</span>
</div>
<div class="stat-item stat-orange">
<span class="stat-val">{{ summary.seriesCount }}</span>
<span class="stat-label">趋势线数</span>
</div>
<div class="stat-item stat-green">
<span class="stat-val">{{ summary.maxLabel }}</span>
<span class="stat-label">单报表最高数量</span>
</div>
</div>
<!-- 图表筛选 -->
<div v-if="reports.length > 0" class="chart-filter-bar">
<span class="filter-label">图表筛选</span>
<el-select
v-model="selectedCategories"
multiple
collapse-tags
placeholder="成本类别(全部)"
size="small"
style="width:160px"
@change="onCategoryChange"
clearable
>
<el-option label="原料" value="原料" />
<el-option label="能耗" value="能耗" />
<el-option label="辅料" value="辅料" />
<el-option label="设备" value="设备" />
<el-option label="人工" value="人工" />
<el-option label="产出" value="产出" />
<el-option label="轧辊" value="轧辊" />
<el-option label="其他" value="其他" />
</el-select>
<el-select
v-model="selectedItems"
multiple
collapse-tags
filterable
placeholder="成本项(全部)"
size="small"
style="width:220px"
@change="onItemChange"
clearable
>
<el-option
v-for="it in filteredItemOptions"
:key="it.itemId"
:label="it.itemName + ' (' + it.category + ')'"
:value="it.itemId"
/>
</el-select>
</div>
<!-- 图表区 -->
<div class="chart-box" v-loading="loading">
<div ref="trendChart" class="chart-body" />
</div>
<div v-if="summary.seriesCount > 15" class="legend-hint">
<i class="el-icon-info" /> 图例较多可在下方图例区滚动查看或缩小筛选范围以减少趋势线数量
</div>
</div>
</template>
<script>
import * as echarts from 'echarts'
import { mapGetters } from 'vuex'
import { listProdReport } from '@/api/cost/prodReport'
import { listProdDetail } from '@/api/cost/prodDetail'
import { listItem } from '@/api/cost/item'
const COLORS = [
'#409eff', '#67c23a', '#e6a23c', '#f56c6c', '#909399',
'#9b59b6', '#1abc9c', '#e74c3c', '#3498db', '#2ecc71',
'#f39c12', '#e91e63', '#00bcd4', '#8bc34a', '#ff5722',
'#607d8b', '#3f51b5', '#cddc39', '#ff9800', '#795548',
'#2196f3', '#4caf50', '#ffc107', '#9c27b0', '#00bcd4'
]
export default {
name: 'CostTrend',
data() {
return {
selectedLine: null,
selectedCategories: [],
selectedItems: [],
allItems: [],
loading: false,
chart: null,
reports: [],
cachedDetails: [],
summary: { seriesCount: 0, maxLabel: '-' }
}
},
computed: {
...mapGetters(['productionLines']),
selectedLineObj() {
if (!this.selectedLine || !this.productionLines.length) return null
return this.productionLines.find(l => l.lineId === this.selectedLine) || null
},
lineNameDisplay() {
const line = this.selectedLineObj
return line ? line.lineName : ''
},
filteredItemOptions() {
if (!this.selectedCategories.length) return this.allItems
return this.allItems.filter(it => this.selectedCategories.includes(it.category))
}
},
mounted() {
this.$store.dispatch('productionLine/getProductionLines').then(() => {
this.initDefaultLine()
this.$nextTick(() => this.fetchData())
})
this.loadItems()
this._resizeHandler = () => { if (this.chart) this.chart.resize() }
window.addEventListener('resize', this._resizeHandler)
},
beforeDestroy() {
window.removeEventListener('resize', this._resizeHandler)
if (this.chart) { this.chart.dispose(); this.chart = null }
},
methods: {
initDefaultLine() {
if (this.selectedLine != null) return
const lines = this.productionLines || []
const dzLine = lines.find(l => l.lineName && l.lineName.includes('镀锌'))
if (dzLine) {
this.selectedLine = dzLine.lineId
} else if (lines.length) {
this.selectedLine = lines[0].lineId
}
},
onLineChange() {
if (this.selectedLine != null) {
this.fetchData()
}
},
onCategoryChange() {
this.selectedItems = this.selectedItems.filter(id => {
const it = this.allItems.find(item => item.itemId === id)
return it && this.selectedCategories.includes(it.category)
})
this.renderFromCache()
},
onItemChange() {
this.renderFromCache()
},
async loadItems() {
try {
const r = await listItem({ pageNum: 1, pageSize: 999 })
this.allItems = r.rows || []
} catch (e) { /* ignore */ }
},
async fetchData() {
if (this.selectedLine == null) {
return
}
this.loading = true
try {
const params = {
lineType: this.selectedLine,
pageNum: 1,
pageSize: 999
}
const reportRes = await listProdReport(params)
const allReports = (reportRes.rows || []).sort((a, b) => {
return (a.reportDate || '').localeCompare(b.reportDate || '')
})
console.log('[CostTrend] reports:', allReports.length, allReports.map(r => ({ id: r.reportId, title: r.reportTitle, date: r.reportDate })))
if (!allReports.length) {
this.$modal.msgWarning('该产线暂无报表')
this.reports = []
this.summary = { seriesCount: 0, maxLabel: '-' }
if (this.chart) this.chart.clear()
return
}
this.reports = allReports
await this.fetchDetailsAndCache(allReports)
} catch (e) {
console.error('CostTrend fetchData error:', e)
this.$modal.msgError('数据加载失败: ' + (e.message || '未知错误'))
} finally {
this.loading = false
}
},
// ==================== 成本项模式 ====================
async fetchDetailsAndCache(reports) {
const allDetailResults = await Promise.all(
reports.map(r =>
listProdDetail({ reportId: r.reportId, pageNum: 1, pageSize: 99999 })
.then(res => {
console.log('[CostTrend] detail for report', r.reportId, 'rows:', (res.rows || []).length)
return { reportId: r.reportId, rows: res.rows || [] }
})
.catch(e => {
console.error('[CostTrend] detail fetch error for report', r.reportId, e)
return { reportId: r.reportId, rows: [] }
})
)
)
this.cachedDetails = allDetailResults
if (!this.allItems.length) await this.loadItems()
this.renderFromCache()
},
renderFromCache() {
const reports = this.reports
const allDetailResults = this.cachedDetails
if (!reports.length || !allDetailResults.length) return
const itemMap = {}
this.allItems.forEach(it => { itemMap[String(it.itemId)] = it })
const itemSet = this.selectedItems.length ? new Set(this.selectedItems.map(String)) : null
const categorySet = this.selectedCategories.length ? new Set(this.selectedCategories) : null
const reportSums = {}
allDetailResults.forEach(({ reportId, rows }) => {
const sums = {}
rows.forEach(d => {
if (!d.itemId) return
const key = String(d.itemId)
if (itemSet && !itemSet.has(key)) return
if (categorySet) {
const it = itemMap[key]
if (!it || !categorySet.has(it.category)) return
}
sums[key] = (sums[key] || 0) + (parseFloat(d.quantity) || 0)
})
reportSums[reportId] = sums
})
const allItemIds = new Set()
Object.values(reportSums).forEach(sums => {
Object.keys(sums).forEach(id => allItemIds.add(id))
})
const xLabels = reports.map(r => this.reportLabel(r))
const series = []
let globalMax = 0
Array.from(allItemIds).forEach((key, idx) => {
const it = itemMap[key]
const name = it ? it.itemName : `未知(${key})`
const data = reports.map(r => {
const sums = reportSums[r.reportId] || {}
const val = sums[key] ?? null
if (val != null && val > globalMax) globalMax = val
return val
})
if (data.every(v => v === null)) return
series.push({
name,
type: 'line',
data,
smooth: true,
symbol: 'circle',
symbolSize: 6,
lineStyle: { width: 2, color: COLORS[idx % COLORS.length] },
itemStyle: { color: COLORS[idx % COLORS.length] },
emphasis: { focus: 'series' }
})
})
this.summary = {
seriesCount: series.length,
maxLabel: this.formatMoney(globalMax)
}
this.$nextTick(() => {
setTimeout(() => this.renderChart(xLabels, series, '数量'), 50)
})
},
// ==================== 图表渲染 ====================
renderChart(xLabels, series, yAxisName) {
console.log('[CostTrend] renderChart called, ref:', !!this.$refs.trendChart, 'series:', series.length, 'xLabels:', xLabels.length)
if (!this.$refs.trendChart) return
if (this.chart) this.chart.dispose()
this.chart = echarts.init(this.$refs.trendChart)
if (!series.length) {
this.chart.setOption({
title: { text: '暂无数据', left: 'center', top: 'center', textStyle: { color: '#999', fontSize: 14 } },
xAxis: { show: false },
yAxis: { show: false },
series: []
})
return
}
this.chart.setOption({
tooltip: {
trigger: 'axis',
formatter: function (params) {
if (!params || !params.length) return ''
let html = '<b>' + params[0].axisValue + '</b><br/>'
params.forEach(p => {
if (p.value != null) {
html += '<span style="display:inline-block;width:10px;height:10px;border-radius:50%;background:' +
p.color + ';margin-right:5px;"></span>' +
p.seriesName + ': <b>' +
Number(p.value).toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 }) +
'</b><br/>'
}
})
return html
}
},
legend: {
type: 'scroll',
bottom: 0,
textStyle: { fontSize: 11 },
pageIconSize: 12,
pageTextStyle: { fontSize: 11 }
},
grid: {
left: '3%',
right: '4%',
top: '3%',
bottom: series.length > 20 ? '18%' : (series.length > 10 ? '14%' : '10%'),
containLabel: true
},
xAxis: {
type: 'category',
data: xLabels,
boundaryGap: false,
axisLabel: {
fontSize: 11,
rotate: xLabels.length > 8 ? 30 : 0
}
},
yAxis: {
type: 'value',
name: yAxisName,
axisLabel: {
fontSize: 11,
formatter: function (v) {
if (v >= 10000) return (v / 10000).toFixed(1) + '万'
return v
}
},
splitLine: { lineStyle: { type: 'dashed', color: '#e8e8e8' } }
},
dataZoom: xLabels.length > 10 ? [
{
type: 'slider',
bottom: series.length > 10 ? (series.length > 20 ? 60 : 50) : 35,
height: 16,
textStyle: { fontSize: 10 }
},
{ type: 'inside' }
] : [],
series
}, true)
},
reportLabel(r) {
const date = r.reportDate
? (typeof r.reportDate === 'string' ? r.reportDate.slice(0, 10) : String(r.reportDate).slice(0, 10))
: ''
return r.reportTitle || date || `报表#${r.reportId}`
},
formatMoney(val) {
if (val == null || val === '' || isNaN(val)) return '-'
const num = Number(val)
if (num >= 10000) return (num / 10000).toFixed(2) + '万'
return num.toFixed(2)
}
}
}
</script>
<style scoped>
.mb8 { margin-bottom: 10px; }
.filter-bar {
display: flex;
align-items: center;
gap: 10px;
flex-wrap: wrap;
}
.stats-row {
display: flex;
gap: 8px;
margin-bottom: 10px;
}
.stat-item {
flex: 1;
min-width: 100px;
background: #fff;
border: 1px solid #ebeef5;
border-radius: 2px;
padding: 10px 12px;
text-align: center;
}
.stat-val {
display: block;
font-size: 22px;
font-weight: 600;
color: #303133;
line-height: 1.2;
}
.stat-label {
display: block;
font-size: 12px;
color: #909399;
margin-top: 2px;
}
.stat-blue .stat-val { color: #409eff; }
.stat-orange .stat-val { color: #e6a23c; }
.stat-green .stat-val { color: #67c23a; }
.chart-box {
background: #fff;
border: 1px solid #ebeef5;
border-radius: 2px;
}
.chart-filter-bar {
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 8px;
}
.chart-filter-bar .filter-label {
font-size: 13px;
color: #606266;
white-space: nowrap;
}
.chart-body {
width: 100%;
height: 480px;
}
.legend-hint {
margin-top: 8px;
font-size: 12px;
color: #909399;
display: flex;
align-items: center;
gap: 4px;
}
</style>

View File

@@ -110,59 +110,57 @@ export default {
<style scoped> <style scoped>
.detail-section { .detail-section {
margin-bottom: 20px; margin-bottom: 14px;
} }
.detail-section-label { .detail-section-label {
font-family: 'Georgia', 'Times New Roman', serif;
font-size: 11px; font-size: 11px;
font-weight: 600; font-weight: 600;
color: #8c8c8c; color: #64748b;
margin-bottom: 4px; margin-bottom: 4px;
letter-spacing: 0.8px; letter-spacing: 0.4px;
text-transform: uppercase; text-transform: uppercase;
} }
.detail-section-text { .detail-section-text {
font-size: 14px; font-size: 13px;
color: #1a1a1a; color: #1e293b;
line-height: 1.8; line-height: 1.6;
word-break: break-all; word-break: break-all;
padding-bottom: 12px; padding-bottom: 10px;
border-bottom: 1px solid #eeeae4; border-bottom: 1px solid #e2e8f0;
} }
/* ===== 客户信息卡片 ===== */ /* ===== 客户信息卡片 ===== */
.customer-info-card { .customer-info-card {
padding: 10px 14px; padding: 8px 12px;
background: #faf8f5; background: #f8fafc;
border: 1px solid #e8e4de; border: 1px solid #e2e8f0;
border-radius: 2px; border-radius: 0;
margin-bottom: 6px; margin-bottom: 4px;
} }
.customer-row { .customer-row {
display: flex; display: flex;
gap: 14px; gap: 12px;
padding: 3px 0; padding: 2px 0;
} }
.customer-row + .customer-row { .customer-row + .customer-row {
border-top: 1px solid #f0ece6; border-top: 1px solid #e2e8f0;
} }
.customer-row-label { .customer-row-label {
flex-shrink: 0; flex-shrink: 0;
width: 70px; width: 70px;
font-family: 'Georgia', 'Times New Roman', serif;
font-size: 11px; font-size: 11px;
color: #8c8c8c; color: #64748b;
letter-spacing: 0.3px; letter-spacing: 0.2px;
} }
.customer-row-value { .customer-row-value {
flex: 1; flex: 1;
font-size: 13px; font-size: 13px;
color: #1a1a1a; color: #1e293b;
} }
</style> </style>

View File

@@ -60,19 +60,18 @@ export default {
<style scoped> <style scoped>
.section-title { .section-title {
font-family: 'Georgia', 'Times New Roman', 'Noto Serif SC', 'SimSun', serif;
width: 100%; width: 100%;
font-size: 15px; font-size: 13px;
font-weight: 700; font-weight: 600;
color: #1a1a1a; color: #1e293b;
margin: 32px 0 16px 0; margin: 20px 0 10px 0;
padding: 0 0 10px 0; padding: 0 0 8px 0;
border-bottom: 1px solid #d4d0c8; border-bottom: 1px solid #cbd5e1;
white-space: nowrap; white-space: nowrap;
display: flex; display: flex;
align-items: center; align-items: center;
gap: 10px; gap: 8px;
letter-spacing: 0.3px; letter-spacing: 0.2px;
} }
.section-title:first-child { .section-title:first-child {
margin-top: 0; margin-top: 0;
@@ -80,19 +79,16 @@ export default {
.section-title .en-sub { .section-title .en-sub {
font-size: 11px; font-size: 11px;
font-weight: 400; font-weight: 400;
color: #8c8c8c; color: #94a3b8;
letter-spacing: 0.5px; letter-spacing: 0.2px;
font-family: 'Georgia', 'Times New Roman', serif;
font-style: italic;
} }
.section-title i { .section-title i {
font-size: 16px; font-size: 14px;
color: #1a3c6e; color: #475569;
} }
.empty-data { .empty-data {
color: #8c8c8c; color: #94a3b8;
font-size: 13px; font-size: 12px;
padding: 8px 0; padding: 6px 0;
font-style: italic;
} }
</style> </style>

View File

@@ -51,19 +51,18 @@ export default {
<style scoped> <style scoped>
.section-title { .section-title {
font-family: 'Georgia', 'Times New Roman', 'Noto Serif SC', 'SimSun', serif;
width: 100%; width: 100%;
font-size: 15px; font-size: 13px;
font-weight: 700; font-weight: 600;
color: #1a1a1a; color: #1e293b;
margin: 32px 0 16px 0; margin: 20px 0 10px 0;
padding: 0 0 10px 0; padding: 0 0 8px 0;
border-bottom: 1px solid #d4d0c8; border-bottom: 1px solid #cbd5e1;
white-space: nowrap; white-space: nowrap;
display: flex; display: flex;
align-items: center; align-items: center;
gap: 10px; gap: 8px;
letter-spacing: 0.3px; letter-spacing: 0.2px;
} }
.section-title:first-child { .section-title:first-child {
margin-top: 0; margin-top: 0;
@@ -71,19 +70,16 @@ export default {
.section-title .en-sub { .section-title .en-sub {
font-size: 11px; font-size: 11px;
font-weight: 400; font-weight: 400;
color: #8c8c8c; color: #94a3b8;
letter-spacing: 0.5px; letter-spacing: 0.2px;
font-family: 'Georgia', 'Times New Roman', serif;
font-style: italic;
} }
.section-title i { .section-title i {
font-size: 16px; font-size: 14px;
color: #1a3c6e; color: #475569;
} }
.empty-data { .empty-data {
color: #8c8c8c; color: #94a3b8;
font-size: 13px; font-size: 12px;
padding: 8px 0; padding: 6px 0;
font-style: italic;
} }
</style> </style>

View File

@@ -93,19 +93,18 @@ export default {
<style scoped> <style scoped>
.section-title { .section-title {
font-family: 'Georgia', 'Times New Roman', 'Noto Serif SC', 'SimSun', serif;
width: 100%; width: 100%;
font-size: 15px; font-size: 13px;
font-weight: 700; font-weight: 600;
color: #1a1a1a; color: #1e293b;
margin: 32px 0 16px 0; margin: 20px 0 10px 0;
padding: 0 0 10px 0; padding: 0 0 8px 0;
border-bottom: 1px solid #d4d0c8; border-bottom: 1px solid #cbd5e1;
white-space: nowrap; white-space: nowrap;
display: flex; display: flex;
align-items: center; align-items: center;
gap: 10px; gap: 8px;
letter-spacing: 0.3px; letter-spacing: 0.2px;
} }
.section-title:first-child { .section-title:first-child {
margin-top: 0; margin-top: 0;
@@ -113,29 +112,27 @@ export default {
.section-title .en-sub { .section-title .en-sub {
font-size: 11px; font-size: 11px;
font-weight: 400; font-weight: 400;
color: #8c8c8c; color: #94a3b8;
letter-spacing: 0.5px; letter-spacing: 0.2px;
font-family: 'Georgia', 'Times New Roman', serif;
font-style: italic;
} }
.section-title i { .section-title i {
font-size: 16px; font-size: 14px;
color: #1a3c6e; color: #475569;
} }
/* ===== 意见卡片(正式文档风格 ===== */ /* ===== 意见卡片 — 工业风格 ===== */
.card-grid { .card-grid {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
gap: 14px; gap: 10px;
} }
.opinion-card { .opinion-card {
flex: 0 0 calc((100% - 14px) / 2); flex: 0 0 calc((100% - 10px) / 2);
background: #ffffff; background: #ffffff;
border: 1px solid #e8e4de; border: 1px solid #e2e8f0;
border-radius: 2px; border-radius: 0;
padding: 14px 16px 12px; padding: 10px 14px 10px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
@@ -144,25 +141,24 @@ export default {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
margin-bottom: 10px; margin-bottom: 8px;
padding-bottom: 8px; padding-bottom: 6px;
border-bottom: 1px dashed #e0dcd6; border-bottom: 1px solid #e2e8f0;
} }
.opinion-dept { .opinion-dept {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 6px; gap: 6px;
font-family: 'Georgia', 'Times New Roman', 'Noto Serif SC', 'SimSun', serif; font-size: 13px;
font-size: 14px; font-weight: 600;
font-weight: 700; color: #1e293b;
color: #1a3c6e; letter-spacing: 0.2px;
letter-spacing: 0.3px;
} }
.opinion-dept-icon { .opinion-dept-icon {
font-size: 10px; font-size: 8px;
color: #1a3c6e; color: #475569;
} }
.opinion-card-body { .opinion-card-body {
@@ -170,11 +166,11 @@ export default {
} }
.opinion-content { .opinion-content {
font-size: 13px; font-size: 12px;
color: #3a3a3a; color: #475569;
line-height: 1.7; line-height: 1.6;
word-break: break-all; word-break: break-all;
max-height: 100px; max-height: 90px;
overflow-y: auto; overflow-y: auto;
} }
@@ -183,35 +179,31 @@ export default {
} }
.opinion-empty { .opinion-empty {
color: #bab5ae; color: #94a3b8;
font-size: 12px; font-size: 12px;
font-style: italic;
font-family: 'Georgia', 'Times New Roman', serif;
} }
.opinion-file { .opinion-file {
margin-top: 8px; margin-top: 6px;
} }
.opinion-card-footer { .opinion-card-footer {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
gap: 14px; gap: 12px;
margin-top: 10px; margin-top: 8px;
padding-top: 8px; padding-top: 6px;
border-top: 1px dashed #e0dcd6; border-top: 1px solid #e2e8f0;
} }
.opinion-footer-item { .opinion-footer-item {
font-family: 'Georgia', 'Times New Roman', serif;
font-size: 11px; font-size: 11px;
color: #8c8c8c; color: #94a3b8;
} }
.empty-data { .empty-data {
color: #8c8c8c; color: #94a3b8;
font-size: 13px; font-size: 12px;
padding: 8px 0; padding: 6px 0;
font-style: italic;
} }
</style> </style>

View File

@@ -97,16 +97,16 @@ export default {
<style scoped> <style scoped>
.dept-preview-container { .dept-preview-container {
font-size: 13px; font-size: 12px;
color: #3a3a3a; color: #475569;
line-height: 1.7; line-height: 1.6;
} }
.preview-row { .preview-row {
display: flex; display: flex;
gap: 12px; gap: 10px;
padding: 4px 0; padding: 3px 0;
border-bottom: 1px solid #f0ece6; border-bottom: 1px solid #e2e8f0;
} }
.preview-row:last-child { .preview-row:last-child {
@@ -116,22 +116,19 @@ export default {
.preview-label { .preview-label {
flex-shrink: 0; flex-shrink: 0;
width: 100px; width: 100px;
font-family: 'Georgia', 'Times New Roman', serif;
font-size: 11px; font-size: 11px;
color: #8c8c8c; color: #64748b;
letter-spacing: 0.3px; letter-spacing: 0.2px;
} }
.preview-value { .preview-value {
flex: 1; flex: 1;
color: #1a1a1a; color: #1e293b;
word-break: break-all; word-break: break-all;
} }
.preview-empty { .preview-empty {
color: #bab5ae; color: #94a3b8;
font-size: 12px; font-size: 12px;
font-style: italic;
font-family: 'Georgia', 'Times New Roman', serif;
} }
</style> </style>

View File

@@ -78,19 +78,18 @@ export default {
<style scoped> <style scoped>
.section-title { .section-title {
font-family: 'Georgia', 'Times New Roman', 'Noto Serif SC', 'SimSun', serif;
width: 100%; width: 100%;
font-size: 15px; font-size: 13px;
font-weight: 700; font-weight: 600;
color: #1a1a1a; color: #1e293b;
margin: 32px 0 16px 0; margin: 20px 0 10px 0;
padding: 0 0 10px 0; padding: 0 0 8px 0;
border-bottom: 1px solid #d4d0c8; border-bottom: 1px solid #cbd5e1;
white-space: nowrap; white-space: nowrap;
display: flex; display: flex;
align-items: center; align-items: center;
gap: 10px; gap: 8px;
letter-spacing: 0.3px; letter-spacing: 0.2px;
} }
.section-title:first-child { .section-title:first-child {
margin-top: 0; margin-top: 0;
@@ -98,29 +97,27 @@ export default {
.section-title .en-sub { .section-title .en-sub {
font-size: 11px; font-size: 11px;
font-weight: 400; font-weight: 400;
color: #8c8c8c; color: #94a3b8;
letter-spacing: 0.5px; letter-spacing: 0.2px;
font-family: 'Georgia', 'Times New Roman', serif;
font-style: italic;
} }
.section-title i { .section-title i {
font-size: 16px; font-size: 14px;
color: #1a3c6e; color: #475569;
} }
/* ===== 反馈卡片(正式文档风格 ===== */ /* ===== 反馈卡片 — 工业风格 ===== */
.card-grid { .card-grid {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
gap: 14px; gap: 10px;
} }
.opinion-card { .opinion-card {
flex: 0 0 calc((100% - 14px) / 2); flex: 0 0 calc((100% - 10px) / 2);
background: #ffffff; background: #ffffff;
border: 1px solid #e8e4de; border: 1px solid #e2e8f0;
border-radius: 2px; border-radius: 0;
padding: 14px 16px 12px; padding: 10px 14px 10px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
@@ -129,25 +126,24 @@ export default {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
margin-bottom: 10px; margin-bottom: 8px;
padding-bottom: 8px; padding-bottom: 6px;
border-bottom: 1px dashed #e0dcd6; border-bottom: 1px solid #e2e8f0;
} }
.opinion-dept { .opinion-dept {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 6px; gap: 6px;
font-family: 'Georgia', 'Times New Roman', 'Noto Serif SC', 'SimSun', serif; font-size: 13px;
font-size: 14px; font-weight: 600;
font-weight: 700; color: #1e293b;
color: #1a3c6e; letter-spacing: 0.2px;
letter-spacing: 0.3px;
} }
.opinion-dept-icon { .opinion-dept-icon {
font-size: 10px; font-size: 8px;
color: #1a3c6e; color: #475569;
} }
.opinion-card-body { .opinion-card-body {
@@ -155,11 +151,11 @@ export default {
} }
.opinion-content { .opinion-content {
font-size: 13px; font-size: 12px;
color: #3a3a3a; color: #475569;
line-height: 1.7; line-height: 1.6;
word-break: break-all; word-break: break-all;
max-height: 100px; max-height: 90px;
overflow-y: auto; overflow-y: auto;
} }
@@ -168,35 +164,31 @@ export default {
} }
.opinion-empty { .opinion-empty {
color: #bab5ae; color: #94a3b8;
font-size: 12px; font-size: 12px;
font-style: italic;
font-family: 'Georgia', 'Times New Roman', serif;
} }
.opinion-file { .opinion-file {
margin-top: 8px; margin-top: 6px;
} }
.opinion-card-footer { .opinion-card-footer {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
gap: 14px; gap: 12px;
margin-top: 10px; margin-top: 8px;
padding-top: 8px; padding-top: 6px;
border-top: 1px dashed #e0dcd6; border-top: 1px solid #e2e8f0;
} }
.opinion-footer-item { .opinion-footer-item {
font-family: 'Georgia', 'Times New Roman', serif;
font-size: 11px; font-size: 11px;
color: #8c8c8c; color: #94a3b8;
} }
.empty-data { .empty-data {
color: #8c8c8c; color: #94a3b8;
font-size: 13px; font-size: 12px;
padding: 8px 0; padding: 6px 0;
font-style: italic;
} }
</style> </style>

View File

@@ -65,55 +65,52 @@ export default {
<style scoped> <style scoped>
.section-container { .section-container {
margin-bottom: 6px; margin-bottom: 4px;
} }
.section-title { .section-title {
font-family: 'Georgia', 'Times New Roman', 'Noto Serif SC', 'SimSun', serif;
width: 100%; width: 100%;
font-size: 15px; font-size: 13px;
font-weight: 700; font-weight: 600;
color: #1a1a1a; color: #1e293b;
margin: 32px 0 16px 0; margin: 20px 0 10px 0;
padding: 0 0 10px 0; padding: 0 0 8px 0;
border-bottom: 1px solid #d4d0c8; border-bottom: 1px solid #cbd5e1;
display: flex; display: flex;
align-items: center; align-items: center;
gap: 10px; gap: 8px;
letter-spacing: 0.3px; letter-spacing: 0.2px;
} }
.section-title .en-sub { .section-title .en-sub {
font-size: 11px; font-size: 11px;
font-weight: 400; font-weight: 400;
color: #8c8c8c; color: #94a3b8;
letter-spacing: 0.5px; letter-spacing: 0.2px;
font-family: 'Georgia', 'Times New Roman', serif;
font-style: italic;
} }
.section-title i { .section-title i {
font-size: 16px; font-size: 14px;
color: #1a3c6e; color: #475569;
} }
.flow-steps { .flow-steps {
padding: 8px 0 4px; padding: 6px 0 4px;
} }
.flow-steps >>> .el-step.is-wait .el-step__icon-inner, .flow-steps >>> .el-step.is-wait .el-step__icon-inner,
.flow-steps >>> .el-step.is-wait .el-step__title { .flow-steps >>> .el-step.is-wait .el-step__title {
color: #c0c4cc; color: #94a3b8;
} }
.flow-steps >>> .el-step.is-process .el-step__icon-inner, .flow-steps >>> .el-step.is-process .el-step__icon-inner,
.flow-steps >>> .el-step.is-process .el-step__title { .flow-steps >>> .el-step.is-process .el-step__title {
color: #409eff; color: #2563eb;
} }
.flow-steps >>> .el-step.is-finish .el-step__icon-inner, .flow-steps >>> .el-step.is-finish .el-step__icon-inner,
.flow-steps >>> .el-step.is-finish .el-step__title { .flow-steps >>> .el-step.is-finish .el-step__title {
color: #67c23a; color: #52c41a;
} }
.flow-steps >>> .el-step__description { .flow-steps >>> .el-step__description {
@@ -125,15 +122,14 @@ export default {
align-items: center; align-items: center;
justify-content: flex-end; justify-content: flex-end;
gap: 6px; gap: 6px;
margin-top: 6px; margin-top: 4px;
padding-top: 8px; padding-top: 6px;
border-top: 1px dashed #e0dcd6; border-top: 1px solid #e2e8f0;
} }
.status-label { .status-label {
font-family: 'Georgia', 'Times New Roman', serif;
font-size: 11px; font-size: 11px;
color: #8c8c8c; color: #64748b;
letter-spacing: 0.3px; letter-spacing: 0.2px;
} }
</style> </style>

View File

@@ -71,19 +71,18 @@ export default {
<style scoped> <style scoped>
.section-title { .section-title {
font-family: 'Georgia', 'Times New Roman', 'Noto Serif SC', 'SimSun', serif;
width: 100%; width: 100%;
font-size: 15px; font-size: 13px;
font-weight: 700; font-weight: 600;
color: #1a1a1a; color: #1e293b;
margin: 32px 0 16px 0; margin: 20px 0 10px 0;
padding: 0 0 10px 0; padding: 0 0 8px 0;
border-bottom: 1px solid #d4d0c8; border-bottom: 1px solid #cbd5e1;
white-space: nowrap; white-space: nowrap;
display: flex; display: flex;
align-items: center; align-items: center;
gap: 10px; gap: 8px;
letter-spacing: 0.3px; letter-spacing: 0.2px;
} }
.section-title:first-child { .section-title:first-child {
margin-top: 0; margin-top: 0;
@@ -91,28 +90,25 @@ export default {
.section-title .en-sub { .section-title .en-sub {
font-size: 11px; font-size: 11px;
font-weight: 400; font-weight: 400;
color: #8c8c8c; color: #94a3b8;
letter-spacing: 0.5px; letter-spacing: 0.2px;
font-family: 'Georgia', 'Times New Roman', serif;
font-style: italic;
} }
.section-title i { .section-title i {
font-size: 16px; font-size: 14px;
color: #1a3c6e; color: #475569;
} }
.empty-data { .empty-data {
color: #8c8c8c; color: #94a3b8;
font-size: 13px; font-size: 12px;
padding: 8px 0; padding: 6px 0;
font-style: italic;
} }
.plan-content { .plan-content {
padding: 12px 16px; padding: 10px 14px;
background: #faf8f5; background: #f8fafc;
border: 1px solid #e8e4de; border: 1px solid #e2e8f0;
border-radius: 2px; border-radius: 0;
font-size: 13px; font-size: 13px;
line-height: 1.8; line-height: 1.6;
color: #1a1a1a; color: #1e293b;
} }
</style> </style>

View File

@@ -106,21 +106,21 @@ export default {
<style scoped> <style scoped>
.section-container { .section-container {
margin-bottom: 4px; margin-bottom: 2px;
} }
/* ===== 文档标题 ===== */ /* ===== 文档标题 ===== */
.doc-header { .doc-header {
margin-bottom: 24px; margin-bottom: 18px;
padding-bottom: 20px; padding-bottom: 14px;
border-bottom: 2px solid #1a3c6e; border-bottom: 2px solid #1e293b;
} }
.doc-header-top { .doc-header-top {
display: flex; display: flex;
align-items: flex-start; align-items: flex-start;
justify-content: space-between; justify-content: space-between;
gap: 16px; gap: 12px;
} }
.doc-title-group { .doc-title-group {
@@ -129,21 +129,18 @@ export default {
} }
.doc-title { .doc-title {
font-family: 'Georgia', 'Times New Roman', 'Noto Serif SC', 'SimSun', serif; font-size: 20px;
font-size: 24px;
font-weight: 700; font-weight: 700;
color: #1a1a1a; color: #1e293b;
line-height: 1.3; line-height: 1.3;
letter-spacing: 0.5px; letter-spacing: 0.2px;
} }
.doc-subtitle { .doc-subtitle {
font-family: 'Georgia', 'Times New Roman', serif; font-size: 11px;
font-size: 12px;
font-weight: 400; font-weight: 400;
color: #8c8c8c; color: #64748b;
font-style: italic; letter-spacing: 0.4px;
letter-spacing: 0.8px;
margin-top: 2px; margin-top: 2px;
} }
@@ -154,36 +151,35 @@ export default {
.doc-status-row { .doc-status-row {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 8px; gap: 6px;
margin-top: 10px; margin-top: 8px;
} }
.doc-status-label { .doc-status-label {
font-family: 'Georgia', 'Times New Roman', serif;
font-size: 11px; font-size: 11px;
color: #8c8c8c; color: #64748b;
letter-spacing: 0.3px; letter-spacing: 0.2px;
} }
/* ===== 元信息行(原始样式) ===== */ /* ===== 元信息行 ===== */
.detail-meta { .detail-meta {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
gap: 16px; gap: 14px;
font-size: 12px; font-size: 12px;
color: #909399; color: #64748b;
margin-bottom: 16px; margin-bottom: 12px;
padding-bottom: 12px; padding-bottom: 10px;
border-bottom: 1px solid #e0dcd6; border-bottom: 1px solid #e2e8f0;
} }
.detail-meta span { .detail-meta span {
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
gap: 4px; gap: 3px;
} }
.detail-meta i { .detail-meta i {
font-size: 13px; font-size: 12px;
} }
</style> </style>

View File

@@ -561,8 +561,9 @@ export default {
<style scoped> <style scoped>
.objection-container { .objection-container {
height: calc(100vh - 84px); height: calc(100vh - 84px);
} }
/* ========== 左侧面板 — 工业风格 ========== */
.left-panel { .left-panel {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@@ -639,7 +640,7 @@ export default {
min-width: 0; min-width: 0;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 3px; gap: 2px;
} }
.item-title { .item-title {
@@ -676,35 +677,34 @@ export default {
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
padding: 60px 0; padding: 48px 0;
color: #c0c4cc; color: #94a3b8;
font-size: 13px; font-size: 13px;
gap: 8px; gap: 8px;
} }
.list-empty i { .list-empty i {
font-size: 32px; font-size: 28px;
} }
.list-footer { .list-footer {
border-top: 1px solid #e4e7ed; border-top: 1px solid #cbd5e1;
padding: 2px 8px 0; padding: 0 4px;
background: #f5f7fa; background: #e8ecf1;
} }
/* ========== 右侧面板 — Word 文档风格 ========== */ /* ========== 右侧面板 ========== */
.right-panel { .right-panel {
height: 100%; height: 100%;
overflow-y: auto; overflow-y: auto;
padding: 12px 16px; padding: 0;
background: #faf8f5; /* 暖白纸张底色 */ background: #f1f5f9;
} }
.right-panel .detail-content { .right-panel .detail-content {
margin: 0 auto; margin: 0 auto;
background: #ffffff; background: #ffffff;
padding: 28px 32px 36px; padding: 20px 24px 24px;
box-shadow: 0 1px 4px rgba(0,0,0,0.06), 0 2px 12px rgba(0,0,0,0.04);
min-height: 100%; min-height: 100%;
} }
@@ -713,48 +713,46 @@ export default {
align-items: center; align-items: center;
justify-content: center; justify-content: center;
height: 100%; height: 100%;
color: #909399; color: #94a3b8;
font-size: 14px; font-size: 13px;
gap: 8px; gap: 6px;
} }
.detail-section { .detail-section {
margin-bottom: 20px; margin-bottom: 14px;
} }
.detail-section-label { .detail-section-label {
font-size: 11px; font-size: 11px;
font-weight: 600; font-weight: 600;
color: #8c8c8c; color: #64748b;
margin-bottom: 4px; margin-bottom: 4px;
letter-spacing: 0.8px; letter-spacing: 0.4px;
text-transform: uppercase; text-transform: uppercase;
font-family: 'Georgia', 'Times New Roman', serif;
} }
.detail-section-text { .detail-section-text {
font-size: 14px; font-size: 13px;
color: #1a1a1a; color: #1e293b;
line-height: 1.8; line-height: 1.6;
word-break: break-all; word-break: break-all;
padding-bottom: 12px; padding-bottom: 10px;
border-bottom: 1px solid #eeeae4; border-bottom: 1px solid #e2e8f0;
} }
/* 文档级通用 section 标题 */ /* 通用 section 标题 */
.section-title { .section-title {
font-family: 'Georgia', 'Times New Roman', 'Noto Serif SC', 'SimSun', serif;
width: 100%; width: 100%;
font-size: 15px; font-size: 13px;
font-weight: 700; font-weight: 600;
color: #1a1a1a; color: #1e293b;
margin: 22px 0 12px 0; margin: 18px 0 10px 0;
padding: 0 0 10px 0; padding: 0 0 8px 0;
border-bottom: 1px solid #d4d0c8; border-bottom: 1px solid #cbd5e1;
display: flex; display: flex;
align-items: center; align-items: center;
gap: 10px; gap: 8px;
letter-spacing: 0.3px; letter-spacing: 0.2px;
} }
.section-title:first-child { .section-title:first-child {
@@ -764,96 +762,91 @@ export default {
.section-title .en-sub { .section-title .en-sub {
font-size: 11px; font-size: 11px;
font-weight: 400; font-weight: 400;
color: #8c8c8c; color: #94a3b8;
letter-spacing: 0.5px; letter-spacing: 0.2px;
font-family: 'Georgia', 'Times New Roman', serif;
font-style: italic;
} }
.section-title i { .section-title i {
font-size: 16px; font-size: 14px;
color: #1a3c6e; color: #475569;
} }
.empty-data { .empty-data {
color: #8c8c8c; color: #94a3b8;
font-size: 13px; font-size: 12px;
padding: 8px 0; padding: 6px 0;
font-style: italic;
} }
.plan-content { .plan-content {
padding: 12px 16px; padding: 10px 14px;
background: #faf8f5; background: #f8fafc;
border: 1px solid #e8e4de; border: 1px solid #e2e8f0;
border-radius: 2px; border-radius: 0;
font-size: 13px; font-size: 13px;
line-height: 1.8; line-height: 1.6;
color: #1a1a1a; color: #1e293b;
} }
.section-gap { .section-gap {
height: 16px; height: 12px;
} }
/* 正式表格覆写 */ /* 表格覆写 */
.right-panel .el-table { .right-panel .el-table {
border: 1px solid #e8e4de !important; border: 1px solid #cbd5e1 !important;
border-radius: 2px !important; border-radius: 0 !important;
font-size: 12px !important; font-size: 12px !important;
} }
.right-panel .el-table thead th { .right-panel .el-table thead th {
background-color: #2c3e50 !important; background-color: #334155 !important;
color: #ffffff !important; color: #f1f5f9 !important;
font-weight: 600 !important; font-weight: 500 !important;
font-size: 11px !important; font-size: 11px !important;
letter-spacing: 0.5px !important; letter-spacing: 0.3px !important;
border-bottom: none !important; border-bottom: none !important;
font-family: 'Georgia', 'Times New Roman', serif;
} }
.right-panel .el-table thead th .cell { .right-panel .el-table thead th .cell {
color: #ffffff !important; color: #f1f5f9 !important;
} }
.right-panel .el-table__body tr:hover > td { .right-panel .el-table__body tr:hover > td {
background-color: #f7f5f0 !important; background-color: #f1f5f9 !important;
} }
.right-panel .el-table--border td { .right-panel .el-table--border td {
border-right: 1px solid #f0ece6 !important; border-right: 1px solid #e2e8f0 !important;
} }
.right-panel .el-table--border th { .right-panel .el-table--border th {
border-right: 1px solid #3a5166 !important; border-right: 1px solid #475569 !important;
} }
.right-panel .el-table td { .right-panel .el-table td {
padding: 6px 4px !important; padding: 5px 4px !important;
color: #3a3a3a !important; color: #1e293b !important;
} }
.right-panel .el-divider--horizontal { .right-panel .el-divider--horizontal {
margin: 8px 0 4px; margin: 6px 0 2px;
background-color: #e0dcd6; background-color: #e2e8f0;
} }
/* el-tag 文档风格微调 */ /* el-tag 工业风格 */
.right-panel .el-tag { .right-panel .el-tag {
border-radius: 2px; border-radius: 0;
font-family: 'Georgia', 'Times New Roman', serif; letter-spacing: 0.2px;
letter-spacing: 0.3px;
} }
.right-panel .el-tag--mini { .right-panel .el-tag--mini {
padding: 0 6px; padding: 0 5px;
line-height: 20px; line-height: 18px;
height: 20px; height: 18px;
} }
.right-panel .el-tag--small { .right-panel .el-tag--small {
padding: 0 8px; padding: 0 7px;
} }
/* ===== PDF 导出时隐藏操作按钮 ===== */ /* ===== PDF 导出时隐藏操作按钮 ===== */