本次提交新增了完整的投标报表统计分析功能,包括: 添加用于数据检查与菜单初始化的 SQL 脚本 实现采购概览仪表板、采购成本分析及供应商绩效报告的后端服务、Mapper、Controller 及 VO 类 添加前端 API、路由配置以及使用 ECharts 可视化图表的页面组件 为仪表板添加通用的 KPI 卡片组件
105 lines
2.6 KiB
Vue
105 lines
2.6 KiB
Vue
<template>
|
|
<el-card shadow="hover" class="kpi-card" :style="{ '--kpi-accent': accentColor }">
|
|
<div class="kpi-label">{{ label }}</div>
|
|
<div class="kpi-value">
|
|
<span class="kpi-number">{{ displayValue }}</span>
|
|
<span class="kpi-unit" v-if="unit">{{ unit }}</span>
|
|
</div>
|
|
<div class="kpi-trend" :class="trendClass" v-if="changeRate > 0">
|
|
<i :class="trendIcon"></i>
|
|
{{ changeRateText }}
|
|
<span class="trend-label">环比上月</span>
|
|
</div>
|
|
<div class="kpi-trend no-change" v-else>
|
|
<i class="el-icon-minus"></i> 持平
|
|
</div>
|
|
</el-card>
|
|
</template>
|
|
|
|
<script>
|
|
const COLORS = ['#409EFF', '#67C23A', '#E6A23C', '#F56C6C', '#909399']
|
|
const CARD_NAMES = ['采购总额', 'RFQ总数', '采购单数', '活跃供应商']
|
|
|
|
export default {
|
|
name: 'KpiCard',
|
|
props: {
|
|
label: { type: String, required: true },
|
|
value: { type: [Number, String], default: 0 },
|
|
unit: { type: String, default: '' },
|
|
changeRate: { type: Number, default: 0 },
|
|
trend: { type: String, default: 'up' }
|
|
},
|
|
computed: {
|
|
safeValue() {
|
|
const v = Number(this.value)
|
|
return isNaN(v) ? 0 : v
|
|
},
|
|
displayValue() {
|
|
const v = this.safeValue
|
|
if (this.label === '采购总额') {
|
|
if (v >= 100000000) return '¥' + (v / 100000000).toFixed(2) + '亿'
|
|
if (v >= 10000) return '¥' + (v / 10000).toFixed(2) + '万'
|
|
return '¥' + v.toLocaleString()
|
|
}
|
|
return v.toLocaleString()
|
|
},
|
|
trendClass() { return this.trend === 'up' ? 'trend-up' : 'trend-down' },
|
|
trendIcon() { return this.trend === 'up' ? 'el-icon-top' : 'el-icon-bottom' },
|
|
changeRateText() {
|
|
const rate = Number(this.changeRate) || 0
|
|
return rate.toFixed(1) + '%'
|
|
},
|
|
accentColor() {
|
|
const idx = CARD_NAMES.indexOf(this.label)
|
|
return COLORS[idx >= 0 ? idx : 4]
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style scoped>
|
|
.kpi-card {
|
|
border-left: 4px solid var(--kpi-accent, #409EFF);
|
|
border-radius: 6px;
|
|
transition: transform .2s;
|
|
}
|
|
.kpi-card:hover {
|
|
transform: translateY(-2px);
|
|
}
|
|
.kpi-label {
|
|
font-size: 14px;
|
|
color: #909399;
|
|
margin-bottom: 8px;
|
|
}
|
|
.kpi-value {
|
|
margin-bottom: 8px;
|
|
display: flex;
|
|
align-items: baseline;
|
|
}
|
|
.kpi-number {
|
|
font-size: 28px;
|
|
font-weight: 700;
|
|
color: #303133;
|
|
line-height: 1.2;
|
|
}
|
|
.kpi-unit {
|
|
font-size: 14px;
|
|
color: #909399;
|
|
margin-left: 4px;
|
|
}
|
|
.kpi-trend {
|
|
font-size: 13px;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 4px;
|
|
}
|
|
.trend-up { color: #67C23A; }
|
|
.trend-down { color: #F56C6C; }
|
|
.no-change { color: #C0C4CC; }
|
|
.trend-label {
|
|
color: #C0C4CC;
|
|
margin-left: 4px;
|
|
font-size: 12px;
|
|
}
|
|
</style>
|