| | |
| | | <template #extra> |
| | | <cl-select-button v-model="mixMetric" :options="mixOptions" small /> |
| | | </template> |
| | | <v-chart :option="mixOption" autoresize class="chart" /> |
| | | <screen-drill-chart |
| | | class="chart" |
| | | type="pie" |
| | | :source="data.wasteMix" |
| | | :metric="mixMetric" |
| | | :unit="mixUnit" |
| | | :center="['50%', '50%']" |
| | | :radius="['38%', '62%']" |
| | | /> |
| | | </panel-card> |
| | | |
| | | <panel-card |
| | |
| | | :demo="isDemoSection('recycleItems')" |
| | | class="dash-card dash-card--flex" |
| | | > |
| | | <v-chart :option="carbonOption" autoresize class="chart" /> |
| | | <screen-drill-chart |
| | | class="chart" |
| | | type="pie" |
| | | :source="data.recycleItems" |
| | | metric="carbon" |
| | | unit="kgCO₂e" |
| | | name-suffix="回收" |
| | | :center="['50%', '50%']" |
| | | :radius="['36%', '60%']" |
| | | /> |
| | | </panel-card> |
| | | </div> |
| | | |
| | |
| | | <template #extra> |
| | | <cl-select-button v-model="itemMetric" :options="itemOptions" small /> |
| | | </template> |
| | | <v-chart :option="itemOption" autoresize class="chart chart--items" /> |
| | | <screen-drill-chart |
| | | class="chart chart--items" |
| | | type="bar" |
| | | :source="data.recycleItems" |
| | | :metric="itemMetric" |
| | | :unit="itemUnit" |
| | | :even-split="false" |
| | | /> |
| | | </panel-card> |
| | | </div> |
| | | </div> |
| | |
| | | import ScreenMapPanel from '../../components/screen-map-panel.vue'; |
| | | import CameraMonitor from '../../../monitor/views/cameras.vue'; |
| | | import { TIME_RANGE_OPTIONS } from '../../data/screen'; |
| | | import { chartSeries, pieTooltipFormatter, toPieData } from '../../data/screen-chart'; |
| | | import ScreenDrillChart from '../../components/screen-drill-chart.vue'; |
| | | import { useChartTheme, useScreenData, useScreenFieldSource } from '../../hooks/use-screen'; |
| | | |
| | | const { data, timeRange } = useScreenData(); |
| | | const { isDemoSection } = useScreenFieldSource(); |
| | | const { textColor, mutedColor, splitColor, primary, baseGrid, axisStyle, tooltip } = useChartTheme(); |
| | | const { mutedColor, splitColor, primary, baseGrid, axisStyle, tooltip } = useChartTheme(); |
| | | |
| | | const mixMetric = ref<'weight' | 'value' | 'count'>('weight'); |
| | | const trendMetric = ref<'weight' | 'value' | 'carbon'>('weight'); |
| | |
| | | return 'kg'; |
| | | }); |
| | | |
| | | /** 垃圾分类结构(饼) */ |
| | | const mixOption = computed(() => ({ |
| | | tooltip: { trigger: 'item', ...tooltip(), formatter: pieTooltipFormatter() }, |
| | | series: [ |
| | | { |
| | | type: 'pie', |
| | | radius: ['38%', '62%'], |
| | | center: ['50%', '50%'], |
| | | padAngle: 3, |
| | | itemStyle: { borderRadius: 6 }, |
| | | label: { color: textColor.value, formatter: '{b}\n{d}%' }, |
| | | data: toPieData( |
| | | chartSeries(data.value.wasteMix, e => e[mixMetric.value]), |
| | | e => e.name, |
| | | e => e.color |
| | | ) |
| | | } |
| | | ] |
| | | })); |
| | | |
| | | /** 碳减排来源(饼):碳值可为负,按绝对值展示减排量 */ |
| | | const carbonOption = computed(() => ({ |
| | | tooltip: { trigger: 'item', ...tooltip(), formatter: pieTooltipFormatter('kgCO₂e') }, |
| | | series: [ |
| | | { |
| | | type: 'pie', |
| | | radius: ['36%', '60%'], |
| | | center: ['50%', '50%'], |
| | | padAngle: 3, |
| | | itemStyle: { borderRadius: 6 }, |
| | | label: { color: textColor.value, formatter: '{b}\n{d}%' }, |
| | | data: toPieData( |
| | | chartSeries(data.value.recycleItems, e => e.carbon, { carbon: true }), |
| | | e => e.name + '回收', |
| | | e => e.color |
| | | ) |
| | | } |
| | | ] |
| | | })); |
| | | const mixUnit = computed(() => { |
| | | if (mixMetric.value === 'value') return '元'; |
| | | if (mixMetric.value === 'count') return '次'; |
| | | return 'kg'; |
| | | }); |
| | | |
| | | /** 回收趋势(折线) */ |
| | | const trendOption = computed(() => ({ |
| | |
| | | ] |
| | | })); |
| | | |
| | | /** 各类回收量(横向条形) */ |
| | | const itemOption = computed(() => { |
| | | const carbon = itemMetric.value === 'carbon'; |
| | | const rows = chartSeries( |
| | | data.value.recycleItems, |
| | | e => Number(e[itemMetric.value] || 0), |
| | | { carbon, evenSplit: false } |
| | | ).reverse(); |
| | | return { |
| | | grid: { containLabel: true, left: 8, right: 24, top: 12, bottom: 8 }, |
| | | tooltip: { |
| | | trigger: 'axis', |
| | | axisPointer: { type: 'shadow' }, |
| | | valueFormatter: (v: number) => `${Number(v || 0).toLocaleString()} ${itemUnit.value}`, |
| | | ...tooltip() |
| | | }, |
| | | xAxis: { |
| | | type: 'value', |
| | | name: itemUnit.value, |
| | | nameTextStyle: { color: mutedColor.value }, |
| | | splitLine: { lineStyle: { color: splitColor.value, type: 'dashed' } }, |
| | | axisLabel: { color: mutedColor.value }, |
| | | axisLine: { show: false }, |
| | | axisTick: { show: false } |
| | | }, |
| | | yAxis: { |
| | | type: 'category', |
| | | data: rows.map(e => e.item.name), |
| | | axisLabel: { color: textColor.value }, |
| | | axisLine: { show: false }, |
| | | axisTick: { show: false } |
| | | }, |
| | | series: [ |
| | | { |
| | | type: 'bar', |
| | | barWidth: 14, |
| | | data: rows.map(e => e.value), |
| | | itemStyle: { |
| | | borderRadius: [0, 8, 8, 0], |
| | | color: (params: any) => rows[params.dataIndex]?.item.color || primary.value |
| | | } |
| | | } |
| | | ] |
| | | }; |
| | | }); |
| | | </script> |
| | | |
| | | <style lang="scss" scoped> |