<template>
|
<div class="screen-page">
|
<el-row :gutter="10" class="kpi-row">
|
<el-col v-for="item in kpis" :key="item.label" :lg="4" :sm="12" :xs="24">
|
<kpi-card v-bind="item" />
|
</el-col>
|
</el-row>
|
|
<el-row :gutter="10" class="mid-row">
|
<el-col :lg="14" :xs="24">
|
<panel-card title="碳减排趋势" sub="今日看近 7 日;年视图按月,其余按日">
|
<v-chart :option="trendOption" autoresize class="chart" />
|
</panel-card>
|
</el-col>
|
<el-col :lg="10" :xs="24">
|
<panel-card title="碳减排来源" sub="按可回收子类拆分">
|
<v-chart :option="sourceOption" autoresize class="chart" />
|
</panel-card>
|
</el-col>
|
</el-row>
|
|
<el-row :gutter="10">
|
<el-col :lg="16" :xs="24">
|
<panel-card title="本年度月度碳减排" sub="日表 carbonTotal 单位 kgCO₂e,展示时 ÷1000 为吨">
|
<v-chart :option="yearOption" autoresize class="chart" />
|
</panel-card>
|
</el-col>
|
<el-col :lg="8" :xs="24">
|
<panel-card title="口径说明" sub="大屏只展示 KPI,不直接绑表">
|
<ul class="note">
|
<li>碳减排 = Σ 分类重量 × 碳减因数 × 方向</li>
|
<li>因数来自垃圾种类 carbonFactor</li>
|
<li>日表字段单位为 kgCO₂e,大屏吨数已除以 1000</li>
|
<li>本页给学校双碳、ESG、绿色教育汇报,不展示分拣点明细</li>
|
</ul>
|
</panel-card>
|
</el-col>
|
</el-row>
|
</div>
|
</template>
|
|
<script lang="ts" setup>
|
defineOptions({
|
name: 'report-screen-carbon'
|
});
|
|
import { computed } from 'vue';
|
import KpiCard from '../../components/kpi-card.vue';
|
import PanelCard from '../../components/panel-card.vue';
|
import { useChartTheme, useScreenData } from '../../hooks/use-screen';
|
|
const { data, timeRange } = useScreenData();
|
const { textColor, mutedColor, splitColor, primary, baseGrid, axisStyle, tooltip } = useChartTheme();
|
|
const kpis = computed(() => [
|
{ label: '累计碳减排', value: data.value.kpis.totalCarbonTon, suffix: '吨CO₂e', fixed: 1 },
|
{ label: '本年度碳减排', value: data.value.kpis.yearCarbonTon, suffix: '吨CO₂e', fixed: 1 },
|
{ label: '本区间碳减排', value: data.value.kpis.periodCarbonTon, suffix: '吨CO₂e', fixed: 2 },
|
{ label: '累计资源回收', value: data.value.kpis.totalWeightTon, suffix: '吨', fixed: 1 },
|
{ label: '累计参与师生', value: data.value.kpis.totalParticipants, suffix: '人', fixed: 0 },
|
{ label: '累计环保行为', value: data.value.kpis.greenActions, suffix: '次', fixed: 0 }
|
]);
|
|
const trendOption = computed(() => {
|
const isYear = timeRange.value === 'year';
|
return {
|
grid: baseGrid(),
|
tooltip: { trigger: 'axis', ...tooltip() },
|
xAxis: {
|
type: 'category',
|
data: isYear ? Array.from({ length: 12 }, (_, i) => `${i + 1}月`) : data.value.axis,
|
...axisStyle()
|
},
|
yAxis: {
|
type: 'value',
|
name: '吨CO₂e',
|
nameTextStyle: { color: mutedColor.value },
|
splitLine: { lineStyle: { color: splitColor.value, type: 'dashed' } },
|
axisLabel: { color: mutedColor.value },
|
axisLine: { show: false },
|
axisTick: { show: false }
|
},
|
series: [
|
{
|
type: 'line',
|
smooth: true,
|
showSymbol: true,
|
symbolSize: 8,
|
data: isYear ? data.value.yearCarbon : data.value.trend.carbon.map(v => Number((v / 1000).toFixed(3))),
|
itemStyle: { color: primary.value },
|
areaStyle: { color: primary.value, opacity: 0.12 }
|
}
|
]
|
};
|
});
|
|
const yearOption = computed(() => ({
|
grid: baseGrid(),
|
tooltip: { trigger: 'axis', ...tooltip() },
|
xAxis: {
|
type: 'category',
|
data: Array.from({ length: 12 }, (_, i) => `${i + 1}月`),
|
...axisStyle()
|
},
|
yAxis: {
|
type: 'value',
|
name: '吨CO₂e',
|
nameTextStyle: { color: mutedColor.value },
|
splitLine: { lineStyle: { color: splitColor.value, type: 'dashed' } },
|
axisLabel: { color: mutedColor.value },
|
axisLine: { show: false },
|
axisTick: { show: false }
|
},
|
series: [
|
{
|
type: 'bar',
|
barWidth: 16,
|
data: data.value.yearCarbon,
|
itemStyle: { color: primary.value, borderRadius: [6, 6, 0, 0] }
|
}
|
]
|
}));
|
|
const sourceOption = computed(() => ({
|
tooltip: { trigger: 'item', formatter: '{b}<br/>{c} kgCO₂e ({d}%)', ...tooltip() },
|
legend: { bottom: 0, textStyle: { color: mutedColor.value } },
|
series: [
|
{
|
type: 'pie',
|
radius: ['36%', '60%'],
|
center: ['50%', '46%'],
|
padAngle: 3,
|
itemStyle: { borderRadius: 6 },
|
label: { color: textColor.value, formatter: '{b}\n{d}%' },
|
data: data.value.recycleItems.map(e => ({
|
name: e.name + '回收',
|
value: e.carbon,
|
itemStyle: { color: e.color }
|
}))
|
}
|
]
|
}));
|
</script>
|
|
<style lang="scss" scoped>
|
.screen-page {
|
.kpi-row,
|
.mid-row {
|
margin-bottom: 10px;
|
}
|
|
.kpi-row {
|
:deep(.el-col) {
|
margin-bottom: 10px;
|
}
|
}
|
|
.mid-row {
|
:deep(.panel-card) {
|
min-height: 360px;
|
}
|
}
|
|
.chart {
|
height: 300px;
|
width: 100%;
|
}
|
|
.note {
|
margin: 8px 12px 12px;
|
padding-left: 18px;
|
color: var(--el-text-color-regular);
|
line-height: 1.9;
|
font-size: 13px;
|
}
|
}
|
</style>
|