From 1c20a331d9fc1be029fadbd3d0f7619fe6a83cd0 Mon Sep 17 00:00:00 2001
From: zhangwencui <1064582902@qq.com>
Date: 星期二, 17 三月 2026 13:32:32 +0800
Subject: [PATCH] 决策分析页面
---
src/views/reportAnalysis/productionStatistics/index.vue | 1681 ++++++++++++-----------
src/views/reportAnalysis/salesStatistics/index.vue | 1871 ++++++++++++++++----------
src/views/reportAnalysis/solidWasteConsumption/index1.vue | 623 ++++++++
3 files changed, 2,658 insertions(+), 1,517 deletions(-)
diff --git a/src/views/reportAnalysis/productionStatistics/index.vue b/src/views/reportAnalysis/productionStatistics/index.vue
index 64acd40..cf00f0f 100644
--- a/src/views/reportAnalysis/productionStatistics/index.vue
+++ b/src/views/reportAnalysis/productionStatistics/index.vue
@@ -1,866 +1,1003 @@
<template>
<div class="dashboard-container">
<div class="data-dashboard">
-
- <!-- 椤堕儴鏍囬鏍� -->
- <!-- <div class="dashboard-header">
+ <!-- 椤堕儴鏍囬鏍� -->
+ <!-- <div class="dashboard-header">
<div class="factory-name">鐢熶骇缁熻鐪嬫澘</div>
</div> -->
-
- <!-- 绛涢�夊尯鍩� -->
- <div class="filter-area">
- <div class="filter-section">
- <span class="filter-label">鏃堕棿缁村害锛�</span>
- <el-radio-group v-model="dateType" @change="handleDateTypeChange" class="radio-group">
- <el-radio-button label="month">鏈堝害</el-radio-button>
- <el-radio-button label="year">骞村害</el-radio-button>
- </el-radio-group>
+ <!-- 绛涢�夊尯鍩� -->
+ <div class="filter-area">
+ <div class="filter-section">
+ <span class="filter-label">鏃堕棿缁村害锛�</span>
+ <el-radio-group v-model="dateType"
+ @change="handleDateTypeChange"
+ class="radio-group">
+ <el-radio-button label="month">鏈堝害</el-radio-button>
+ <el-radio-button label="year">骞村害</el-radio-button>
+ </el-radio-group>
+ </div>
+ <div class="filter-section">
+ <span class="filter-label">浜у搧绫诲瀷锛�</span>
+ <el-radio-group v-model="productType"
+ @change="handleProductTypeChange"
+ class="radio-group">
+ <el-radio-button label="block">鐮屽潡</el-radio-button>
+ <el-radio-button label="plate">鏉挎潗</el-radio-button>
+ </el-radio-group>
+ </div>
</div>
- <div class="filter-section">
- <span class="filter-label">浜у搧绫诲瀷锛�</span>
- <el-radio-group v-model="productType" @change="handleProductTypeChange" class="radio-group">
- <el-radio-button label="block">鐮屽潡</el-radio-button>
- <el-radio-button label="plate">鏉挎潗</el-radio-button>
- </el-radio-group>
- </div>
- </div>
-
- <!-- 涓昏鍐呭鍖哄煙 -->
- <div class="dashboard-content">
- <!-- 绗竴琛� -->
- <div class="row row-1">
- <div class="panel-card card-1">
- <div class="panel-title">浜ч噺鎸囨爣</div>
- <div class="chart-container">
- <div ref="productionChart" style="width: 100%; height: 100%"></div>
+ <!-- 涓昏鍐呭鍖哄煙 -->
+ <div class="dashboard-content">
+ <!-- 绗竴琛� -->
+ <div class="row row-1">
+ <div class="panel-card card-1">
+ <div class="panel-title">浜ч噺鎸囨爣</div>
+ <div class="chart-container">
+ <div ref="productionChart"
+ style="width: 100%; height: 100%"></div>
+ </div>
+ </div>
+ <div class="panel-card card-2">
+ <div class="panel-title">鍥哄簾澶勭悊閲�</div>
+ <div class="chart-container">
+ <div ref="solidWasteChart"
+ style="width: 100%; height: 100%"></div>
+ </div>
+ </div>
+ <div class="panel-card card-3">
+ <div class="panel-title">缁煎悎缁熻</div>
+ <div class="stats-grid">
+ <div class="stat-item">
+ <div class="stat-label">鎬讳骇鑳�</div>
+ <div class="stat-value production-color">{{ totalProduction }}</div>
+ <div class="stat-unit">绔嬫柟绫�</div>
+ </div>
+ <div class="stat-item">
+ <div class="stat-label">鎬诲浐搴熷鐞�</div>
+ <div class="stat-value waste-color">{{ totalSolidWaste }}</div>
+ <div class="stat-unit">鍚�</div>
+ </div>
+ <div class="stat-item">
+ <div class="stat-label">骞冲潎鍗曡��</div>
+ <div class="stat-value consumption-color">{{ averageUnitConsumption }}</div>
+ <div class="stat-unit">鍚�/绔嬫柟绫�</div>
+ </div>
+ <div class="stat-item">
+ <div class="stat-label">鎬昏兘鑰�</div>
+ <div class="stat-value energy-color">{{ totalEnergy }}</div>
+ <div class="stat-unit">kWh</div>
+ </div>
+ </div>
</div>
</div>
- <div class="panel-card card-2">
- <div class="panel-title">鍥哄簾澶勭悊閲�</div>
- <div class="chart-container">
- <div ref="solidWasteChart" style="width: 100%; height: 100%"></div>
+ <!-- 绗簩琛� -->
+ <div class="row row-2">
+ <div class="panel-card card-4">
+ <div class="panel-title">鐢熶骇鎴愭湰鍗曡��</div>
+ <div class="chart-container">
+ <div ref="costChart"
+ style="width: 100%; height: 100%"></div>
+ </div>
+ </div>
+ <div class="panel-card card-5">
+ <div class="panel-title">鐢熶骇鑳借�楁暟鎹�</div>
+ <div class="chart-container">
+ <div ref="energyChart"
+ style="width: 100%; height: 100%"></div>
+ </div>
</div>
</div>
- <div class="panel-card card-3">
- <div class="panel-title">缁煎悎缁熻</div>
- <div class="stats-grid">
- <div class="stat-item">
- <div class="stat-label">鎬讳骇鑳�</div>
- <div class="stat-value">{{ totalProduction }}</div>
- <div class="stat-unit">绔嬫柟绫�</div>
- </div>
- <div class="stat-item">
- <div class="stat-label">鎬诲浐搴熷鐞�</div>
- <div class="stat-value">{{ totalSolidWaste }}</div>
- <div class="stat-unit">鍚�</div>
- </div>
- <div class="stat-item">
- <div class="stat-label">骞冲潎鍗曡��</div>
- <div class="stat-value">{{ averageUnitConsumption }}</div>
- <div class="stat-unit">鍚�/绔嬫柟绫�</div>
- </div>
- <div class="stat-item">
- <div class="stat-label">鎬昏兘鑰�</div>
- <div class="stat-value">{{ totalEnergy }}</div>
- <div class="stat-unit">kWh</div>
+ <!-- 绗笁琛� -->
+ <div class="row row-3">
+ <div class="panel-card card-6">
+ <div class="panel-title">鍗曡�楁暟鎹槑缁�</div>
+ <div class="table-container">
+ <el-table :data="costTableData"
+ style="width: 100%">
+ <el-table-column prop="material"
+ label="鐗╂枡绫诲瀷"
+ width="120"
+ align="center">
+ <template #default="scope">
+ <el-tag :type="getMaterialTypeType(scope.row.material)">
+ {{ scope.row.material }}
+ </el-tag>
+ </template>
+ </el-table-column>
+ <el-table-column prop="unit"
+ label="鍗曚綅"
+ width="100" />
+ <el-table-column prop="monthlyConsumption"
+ label="鏈堝害绱鐢ㄩ噺"
+ align="right">
+ <template #default="scope">
+ <span class="data-value">{{ scope.row.monthlyConsumption }}</span>
+ </template>
+ </el-table-column>
+ <el-table-column prop="monthlyProduction"
+ label="鏈堝害绱浜ч噺"
+ align="right">
+ <template #default="scope">
+ <span class="data-value">{{ scope.row.monthlyProduction }}</span>
+ </template>
+ </el-table-column>
+ <el-table-column prop="monthlyUnitConsumption"
+ label="鏈堝害绱鍗曡��"
+ align="right">
+ <template #default="scope">
+ <span class="data-value">{{ scope.row.monthlyUnitConsumption }}</span>
+ </template>
+ </el-table-column>
+ <el-table-column prop="yearlyConsumption"
+ label="骞村害绱鐢ㄩ噺"
+ align="right">
+ <template #default="scope">
+ <span class="data-value">{{ scope.row.yearlyConsumption }}</span>
+ </template>
+ </el-table-column>
+ <el-table-column prop="yearlyProduction"
+ label="骞村害绱浜ч噺"
+ align="right">
+ <template #default="scope">
+ <span class="data-value">{{ scope.row.yearlyProduction }}</span>
+ </template>
+ </el-table-column>
+ <el-table-column prop="yearlyUnitConsumption"
+ label="骞村害绱鍗曡��"
+ align="right">
+ <template #default="scope">
+ <span class="data-value">{{ scope.row.yearlyUnitConsumption }}</span>
+ </template>
+ </el-table-column>
+ </el-table>
</div>
</div>
</div>
</div>
-
- <!-- 绗簩琛� -->
- <div class="row row-2">
- <div class="panel-card card-4">
- <div class="panel-title">鐢熶骇鎴愭湰鍗曡��</div>
- <div class="chart-container">
- <div ref="costChart" style="width: 100%; height: 100%"></div>
- </div>
- </div>
- <div class="panel-card card-5">
- <div class="panel-title">鐢熶骇鑳借�楁暟鎹�</div>
- <div class="chart-container">
- <div ref="energyChart" style="width: 100%; height: 100%"></div>
- </div>
- </div>
- </div>
-
- <!-- 绗笁琛� -->
- <div class="row row-3">
- <div class="panel-card card-6">
- <div class="panel-title">鍗曡�楁暟鎹槑缁�</div>
- <div class="table-container">
- <el-table :data="costTableData" style="width: 100%">
- <el-table-column prop="material" label="鐗╂枡绫诲瀷" width="120" />
- <el-table-column prop="unit" label="鍗曚綅" width="100" />
- <el-table-column prop="monthlyConsumption" label="鏈堝害绱鐢ㄩ噺" />
- <el-table-column prop="monthlyProduction" label="鏈堝害绱浜ч噺" />
- <el-table-column prop="monthlyUnitConsumption" label="鏈堝害绱鍗曡��" />
- <el-table-column prop="yearlyConsumption" label="骞村害绱鐢ㄩ噺" />
- <el-table-column prop="yearlyProduction" label="骞村害绱浜ч噺" />
- <el-table-column prop="yearlyUnitConsumption" label="骞村害绱鍗曡��" />
- </el-table>
- </div>
- </div>
- </div>
- </div>
</div>
</div>
</template>
<script setup>
-import { ref, computed, onMounted, onBeforeUnmount, nextTick, watch } from 'vue'
-import * as echarts from 'echarts'
+ import {
+ ref,
+ computed,
+ onMounted,
+ onBeforeUnmount,
+ nextTick,
+ watch,
+ } from "vue";
+ import * as echarts from "echarts";
-// 绛涢�夋潯浠�
-const dateType = ref('month') // month 鎴� year
-const productType = ref('block') // block 鎴� plate
+ // 绛涢�夋潯浠�
+ const dateType = ref("month"); // month 鎴� year
+ const productType = ref("block"); // block 鎴� plate
-// 鍥捐〃寮曠敤
-const productionChart = ref(null)
-const solidWasteChart = ref(null)
-const costChart = ref(null)
-const energyChart = ref(null)
+ // 鍥捐〃寮曠敤
+ const productionChart = ref(null);
+ const solidWasteChart = ref(null);
+ const costChart = ref(null);
+ const energyChart = ref(null);
-// 鍥捐〃瀹炰緥
-let productionChartInstance = null
-let solidWasteChartInstance = null
-let costChartInstance = null
-let energyChartInstance = null
+ // 鍥捐〃瀹炰緥
+ let productionChartInstance = null;
+ let solidWasteChartInstance = null;
+ let costChartInstance = null;
+ let energyChartInstance = null;
-// 妯℃嫙鏁版嵁
-const productionData = ref({
- month: [
- { name: '1鏈�', block: 1200, plate: 800 },
- { name: '2鏈�', block: 1300, plate: 850 },
- { name: '3鏈�', block: 1100, plate: 750 },
- { name: '4鏈�', block: 1400, plate: 900 },
- { name: '5鏈�', block: 1500, plate: 950 },
- { name: '6鏈�', block: 1350, plate: 880 },
- { name: '7鏈�', block: 1450, plate: 920 },
- { name: '8鏈�', block: 1600, plate: 1000 },
- { name: '9鏈�', block: 1550, plate: 980 },
- { name: '10鏈�', block: 1700, plate: 1050 },
- { name: '11鏈�', block: 1650, plate: 1020 },
- { name: '12鏈�', block: 1800, plate: 1100 }
- ],
- year: [
- { name: '2023', block: 15000, plate: 9500 },
- { name: '2024', block: 16500, plate: 10200 },
- { name: '2025', block: 18000, plate: 11000 }
- ]
-})
+ // 妯℃嫙鏁版嵁
+ const productionData = ref({
+ month: [
+ { name: "1鏈�", block: 1200, plate: 800 },
+ { name: "2鏈�", block: 1300, plate: 850 },
+ { name: "3鏈�", block: 1100, plate: 750 },
+ { name: "4鏈�", block: 1400, plate: 900 },
+ { name: "5鏈�", block: 1500, plate: 950 },
+ { name: "6鏈�", block: 1350, plate: 880 },
+ { name: "7鏈�", block: 1450, plate: 920 },
+ { name: "8鏈�", block: 1600, plate: 1000 },
+ { name: "9鏈�", block: 1550, plate: 980 },
+ { name: "10鏈�", block: 1700, plate: 1050 },
+ { name: "11鏈�", block: 1650, plate: 1020 },
+ { name: "12鏈�", block: 1800, plate: 1100 },
+ ],
+ year: [
+ { name: "2023", block: 15000, plate: 9500 },
+ { name: "2024", block: 16500, plate: 10200 },
+ { name: "2025", block: 18000, plate: 11000 },
+ ],
+ });
-const solidWasteData = ref({
- month: [
- { name: '1鏈�', 绮夌叅鐏�: 200, 鐭宠啅: 150, 鐭崇伆: 100 },
- { name: '2鏈�', 绮夌叅鐏�: 220, 鐭宠啅: 160, 鐭崇伆: 110 },
- { name: '3鏈�', 绮夌叅鐏�: 190, 鐭宠啅: 140, 鐭崇伆: 95 },
- { name: '4鏈�', 绮夌叅鐏�: 230, 鐭宠啅: 170, 鐭崇伆: 115 },
- { name: '5鏈�', 绮夌叅鐏�: 240, 鐭宠啅: 180, 鐭崇伆: 120 },
- { name: '6鏈�', 绮夌叅鐏�: 225, 鐭宠啅: 165, 鐭崇伆: 112 }
- ],
- year: [
- { name: '2023', 绮夌叅鐏�: 2500, 鐭宠啅: 1800, 鐭崇伆: 1200 },
- { name: '2024', 绮夌叅鐏�: 2700, 鐭宠啅: 1950, 鐭崇伆: 1300 },
- { name: '2025', 绮夌叅鐏�: 2900, 鐭宠啅: 2100, 鐭崇伆: 1400 }
- ]
-})
+ const solidWasteData = ref({
+ month: [
+ { name: "1鏈�", 绮夌叅鐏�: 200, 鐭宠啅: 150, 鐭崇伆: 100 },
+ { name: "2鏈�", 绮夌叅鐏�: 220, 鐭宠啅: 160, 鐭崇伆: 110 },
+ { name: "3鏈�", 绮夌叅鐏�: 190, 鐭宠啅: 140, 鐭崇伆: 95 },
+ { name: "4鏈�", 绮夌叅鐏�: 230, 鐭宠啅: 170, 鐭崇伆: 115 },
+ { name: "5鏈�", 绮夌叅鐏�: 240, 鐭宠啅: 180, 鐭崇伆: 120 },
+ { name: "6鏈�", 绮夌叅鐏�: 225, 鐭宠啅: 165, 鐭崇伆: 112 },
+ ],
+ year: [
+ { name: "2023", 绮夌叅鐏�: 2500, 鐭宠啅: 1800, 鐭崇伆: 1200 },
+ { name: "2024", 绮夌叅鐏�: 2700, 鐭宠啅: 1950, 鐭崇伆: 1300 },
+ { name: "2025", 绮夌叅鐏�: 2900, 鐭宠啅: 2100, 鐭崇伆: 1400 },
+ ],
+ });
-const costData = ref({
- materials: ['姘存偿', '閾濈矇鑶�', '鑴辨ā鍓�', '闃茶厫鍓�', '姘寲鍓�', '鍐锋嫈涓�'],
- month: {
- consumption: [1200, 50, 80, 30, 40, 60],
- production: [12000, 12000, 12000, 8000, 8000, 8000],
- unitConsumption: [0.1, 0.0042, 0.0067, 0.0038, 0.005, 0.0075]
- },
- year: {
- consumption: [14000, 600, 950, 350, 480, 720],
- production: [140000, 140000, 140000, 95000, 95000, 95000],
- unitConsumption: [0.1, 0.0043, 0.0068, 0.0037, 0.0051, 0.0076]
- }
-})
-
-const energyData = ref({
- month: [
- { name: '1鏈�', 鐢甸噺: 12000, 姘撮噺: 8000, 姘旈噺: 5000 },
- { name: '2鏈�', 鐢甸噺: 13000, 姘撮噺: 8500, 姘旈噺: 5500 },
- { name: '3鏈�', 鐢甸噺: 11000, 姘撮噺: 7500, 姘旈噺: 4800 },
- { name: '4鏈�', 鐢甸噺: 14000, 姘撮噺: 9000, 姘旈噺: 6000 },
- { name: '5鏈�', 鐢甸噺: 15000, 姘撮噺: 9500, 姘旈噺: 6500 },
- { name: '6鏈�', 鐢甸噺: 13500, 姘撮噺: 8800, 姘旈噺: 5800 }
- ],
- year: [
- { name: '2023', 鐢甸噺: 140000, 姘撮噺: 95000, 姘旈噺: 65000 },
- { name: '2024', 鐢甸噺: 150000, 姘撮噺: 100000, 姘旈噺: 70000 },
- { name: '2025', 鐢甸噺: 160000, 姘撮噺: 105000, 姘旈噺: 75000 }
- ]
-})
-
-// 璁$畻灞炴��
-const productionChartOption = computed(() => {
- const data = productionData.value[dateType.value]
- return {
- tooltip: {
- trigger: 'axis',
- axisPointer: {
- type: 'shadow'
- }
+ const costData = ref({
+ materials: ["姘存偿", "閾濈矇鑶�", "鑴辨ā鍓�", "闃茶厫鍓�", "姘寲鍓�", "鍐锋嫈涓�"],
+ month: {
+ consumption: [1200, 50, 80, 30, 40, 60],
+ production: [12000, 12000, 12000, 8000, 8000, 8000],
+ unitConsumption: [0.1, 0.0042, 0.0067, 0.0038, 0.005, 0.0075],
},
- legend: {
- data: ['鐮屽潡', '鏉挎潗'],
- textStyle: {
- color: '#333'
- }
+ year: {
+ consumption: [14000, 600, 950, 350, 480, 720],
+ production: [140000, 140000, 140000, 95000, 95000, 95000],
+ unitConsumption: [0.1, 0.0043, 0.0068, 0.0037, 0.0051, 0.0076],
},
- grid: {
- left: '3%',
- right: '4%',
- bottom: '3%',
- containLabel: true
- },
- xAxis: {
- type: 'category',
- data: data.map(item => item.name),
- axisLabel: {
- color: '#333'
- }
- },
- yAxis: {
- type: 'value',
- name: '浜ч噺 (绔嬫柟绫�)',
- axisLabel: {
- color: '#333'
- }
- },
- series: [
- {
- name: '鐮屽潡',
- type: 'line',
- data: data.map(item => item.block),
- smooth: true,
- lineStyle: {
- width: 3
+ });
+
+ const energyData = ref({
+ month: [
+ { name: "1鏈�", 鐢甸噺: 12000, 姘撮噺: 8000, 姘旈噺: 5000 },
+ { name: "2鏈�", 鐢甸噺: 13000, 姘撮噺: 8500, 姘旈噺: 5500 },
+ { name: "3鏈�", 鐢甸噺: 11000, 姘撮噺: 7500, 姘旈噺: 4800 },
+ { name: "4鏈�", 鐢甸噺: 14000, 姘撮噺: 9000, 姘旈噺: 6000 },
+ { name: "5鏈�", 鐢甸噺: 15000, 姘撮噺: 9500, 姘旈噺: 6500 },
+ { name: "6鏈�", 鐢甸噺: 13500, 姘撮噺: 8800, 姘旈噺: 5800 },
+ ],
+ year: [
+ { name: "2023", 鐢甸噺: 140000, 姘撮噺: 95000, 姘旈噺: 65000 },
+ { name: "2024", 鐢甸噺: 150000, 姘撮噺: 100000, 姘旈噺: 70000 },
+ { name: "2025", 鐢甸噺: 160000, 姘撮噺: 105000, 姘旈噺: 75000 },
+ ],
+ });
+
+ // 璁$畻灞炴��
+ const productionChartOption = computed(() => {
+ const data = productionData.value[dateType.value];
+ return {
+ tooltip: {
+ trigger: "axis",
+ axisPointer: {
+ type: "shadow",
},
- itemStyle: {
- color: '#409EFF'
- }
},
- {
- name: '鏉挎潗',
- type: 'line',
- data: data.map(item => item.plate),
- smooth: true,
- lineStyle: {
- width: 3
+ legend: {
+ data: ["鐮屽潡", "鏉挎潗"],
+ textStyle: {
+ color: "#333",
},
- itemStyle: {
- color: '#67C23A'
- }
- }
- ]
- }
-})
-
-const solidWasteChartOption = computed(() => {
- const data = solidWasteData.value[dateType.value]
- return {
- tooltip: {
- trigger: 'axis',
- axisPointer: {
- type: 'shadow'
- }
- },
- legend: {
- data: ['绮夌叅鐏�', '鐭宠啅', '鐭崇伆'],
- textStyle: {
- color: '#333'
- }
- },
- grid: {
- left: '3%',
- right: '4%',
- bottom: '3%',
- containLabel: true
- },
- xAxis: {
- type: 'category',
- data: data.map(item => item.name),
- axisLabel: {
- color: '#333'
- }
- },
- yAxis: {
- type: 'value',
- name: '澶勭悊閲� (鍚�)',
- axisLabel: {
- color: '#333'
- }
- },
- series: [
- {
- name: '绮夌叅鐏�',
- type: 'bar',
- data: data.map(item => item.绮夌叅鐏�),
- itemStyle: {
- color: '#909399'
- }
},
- {
- name: '鐭宠啅',
- type: 'bar',
- data: data.map(item => item.鐭宠啅),
- itemStyle: {
- color: '#E6A23C'
- }
+ grid: {
+ left: "3%",
+ right: "4%",
+ bottom: "3%",
+ containLabel: true,
},
- {
- name: '鐭崇伆',
- type: 'bar',
- data: data.map(item => item.鐭崇伆),
- itemStyle: {
- color: '#F56C6C'
- }
- }
- ]
- }
-})
-
-const costChartOption = computed(() => {
- const data = costData.value
- return {
- tooltip: {
- trigger: 'axis',
- axisPointer: {
- type: 'shadow'
- }
- },
- legend: {
- data: ['鏈堝害鍗曡��', '骞村害鍗曡��'],
- textStyle: {
- color: '#333'
- }
- },
- grid: {
- left: '3%',
- right: '4%',
- bottom: '3%',
- containLabel: true
- },
- xAxis: {
- type: 'category',
- data: data.materials,
- axisLabel: {
- color: '#333',
- rotate: 45
- }
- },
- yAxis: {
- type: 'value',
- name: '鍗曡�� (鍚�/绔嬫柟绫�)',
- axisLabel: {
- color: '#333'
- }
- },
- series: [
- {
- name: '鏈堝害鍗曡��',
- type: 'bar',
- data: data.month.unitConsumption,
- itemStyle: {
- color: '#409EFF'
- }
- },
- {
- name: '骞村害鍗曡��',
- type: 'bar',
- data: data.year.unitConsumption,
- itemStyle: {
- color: '#67C23A'
- }
- }
- ]
- }
-})
-
-const energyChartOption = computed(() => {
- const data = energyData.value[dateType.value]
- return {
- tooltip: {
- trigger: 'axis',
- axisPointer: {
- type: 'shadow'
- }
- },
- legend: {
- data: ['鐢甸噺', '姘撮噺', '姘旈噺'],
- textStyle: {
- color: '#333'
- }
- },
- grid: {
- left: '3%',
- right: '4%',
- bottom: '3%',
- containLabel: true
- },
- xAxis: {
- type: 'category',
- data: data.map(item => item.name),
- axisLabel: {
- color: '#333'
- }
- },
- yAxis: {
- type: 'value',
- name: '鑳借�楅噺',
- axisLabel: {
- color: '#333'
- }
- },
- series: [
- {
- name: '鐢甸噺',
- type: 'line',
- data: data.map(item => item.鐢甸噺),
- smooth: true,
- lineStyle: {
- width: 3
+ xAxis: {
+ type: "category",
+ data: data.map(item => item.name),
+ axisLabel: {
+ color: "#333",
},
- itemStyle: {
- color: '#409EFF'
- }
},
- {
- name: '姘撮噺',
- type: 'line',
- data: data.map(item => item.姘撮噺),
- smooth: true,
- lineStyle: {
- width: 3
+ yAxis: {
+ type: "value",
+ name: "浜ч噺 (绔嬫柟绫�)",
+ axisLabel: {
+ color: "#333",
},
- itemStyle: {
- color: '#67C23A'
- }
},
- {
- name: '姘旈噺',
- type: 'line',
- data: data.map(item => item.姘旈噺),
- smooth: true,
- lineStyle: {
- width: 3
+ series: [
+ {
+ name: "鐮屽潡",
+ type: "line",
+ data: data.map(item => item.block),
+ smooth: true,
+ lineStyle: {
+ width: 3,
+ },
+ itemStyle: {
+ color: "#409EFF",
+ },
},
- itemStyle: {
- color: '#E6A23C'
- }
- }
- ]
- }
-})
+ {
+ name: "鏉挎潗",
+ type: "line",
+ data: data.map(item => item.plate),
+ smooth: true,
+ lineStyle: {
+ width: 3,
+ },
+ itemStyle: {
+ color: "#67C23A",
+ },
+ },
+ ],
+ };
+ });
-const costTableData = computed(() => {
- const data = costData.value
- const materials = data.materials
- const monthData = data.month
- const yearData = data.year
-
- return materials.map((material, index) => ({
- material,
- unit: '鍚�/绔嬫柟绫�',
- monthlyConsumption: monthData.consumption[index],
- monthlyProduction: monthData.production[index],
- monthlyUnitConsumption: monthData.unitConsumption[index].toFixed(4),
- yearlyConsumption: yearData.consumption[index],
- yearlyProduction: yearData.production[index],
- yearlyUnitConsumption: yearData.unitConsumption[index].toFixed(4)
- }))
-})
+ const solidWasteChartOption = computed(() => {
+ const data = solidWasteData.value[dateType.value];
+ return {
+ tooltip: {
+ trigger: "axis",
+ axisPointer: {
+ type: "shadow",
+ },
+ },
+ legend: {
+ data: ["绮夌叅鐏�", "鐭宠啅", "鐭崇伆"],
+ textStyle: {
+ color: "#333",
+ },
+ },
+ grid: {
+ left: "3%",
+ right: "4%",
+ bottom: "3%",
+ containLabel: true,
+ },
+ xAxis: {
+ type: "category",
+ data: data.map(item => item.name),
+ axisLabel: {
+ color: "#333",
+ },
+ },
+ yAxis: {
+ type: "value",
+ name: "澶勭悊閲� (鍚�)",
+ axisLabel: {
+ color: "#333",
+ },
+ },
+ series: [
+ {
+ name: "绮夌叅鐏�",
+ type: "bar",
+ data: data.map(item => item.绮夌叅鐏�),
+ itemStyle: {
+ color: "#909399",
+ },
+ },
+ {
+ name: "鐭宠啅",
+ type: "bar",
+ data: data.map(item => item.鐭宠啅),
+ itemStyle: {
+ color: "#E6A23C",
+ },
+ },
+ {
+ name: "鐭崇伆",
+ type: "bar",
+ data: data.map(item => item.鐭崇伆),
+ itemStyle: {
+ color: "#F56C6C",
+ },
+ },
+ ],
+ };
+ });
-const totalProduction = computed(() => {
- const data = productionData.value[dateType.value]
- if (dateType.value === 'month') {
- return data.reduce((sum, item) => sum + item[productType.value === 'block' ? 'block' : 'plate'], 0)
- } else {
- return data[data.length - 1][productType.value === 'block' ? 'block' : 'plate']
- }
-})
+ const costChartOption = computed(() => {
+ const data = costData.value;
+ return {
+ tooltip: {
+ trigger: "axis",
+ axisPointer: {
+ type: "shadow",
+ },
+ },
+ legend: {
+ data: ["鏈堝害鍗曡��", "骞村害鍗曡��"],
+ textStyle: {
+ color: "#333",
+ },
+ },
+ grid: {
+ left: "3%",
+ right: "4%",
+ bottom: "3%",
+ containLabel: true,
+ },
+ xAxis: {
+ type: "category",
+ data: data.materials,
+ axisLabel: {
+ color: "#333",
+ rotate: 45,
+ },
+ },
+ yAxis: {
+ type: "value",
+ name: "鍗曡�� (鍚�/绔嬫柟绫�)",
+ axisLabel: {
+ color: "#333",
+ },
+ },
+ series: [
+ {
+ name: "鏈堝害鍗曡��",
+ type: "bar",
+ data: data.month.unitConsumption,
+ itemStyle: {
+ color: "#409EFF",
+ },
+ },
+ {
+ name: "骞村害鍗曡��",
+ type: "bar",
+ data: data.year.unitConsumption,
+ itemStyle: {
+ color: "#67C23A",
+ },
+ },
+ ],
+ };
+ });
-const totalSolidWaste = computed(() => {
- const data = solidWasteData.value[dateType.value]
- if (dateType.value === 'month') {
- return data.reduce((sum, item) => sum + item.绮夌叅鐏� + item.鐭宠啅 + item.鐭崇伆, 0)
- } else {
- const lastItem = data[data.length - 1]
- return lastItem.绮夌叅鐏� + lastItem.鐭宠啅 + lastItem.鐭崇伆
- }
-})
+ const energyChartOption = computed(() => {
+ const data = energyData.value[dateType.value];
+ return {
+ tooltip: {
+ trigger: "axis",
+ axisPointer: {
+ type: "shadow",
+ },
+ },
+ legend: {
+ data: ["鐢甸噺", "姘撮噺", "姘旈噺"],
+ textStyle: {
+ color: "#333",
+ },
+ },
+ grid: {
+ left: "3%",
+ right: "4%",
+ bottom: "3%",
+ containLabel: true,
+ },
+ xAxis: {
+ type: "category",
+ data: data.map(item => item.name),
+ axisLabel: {
+ color: "#333",
+ },
+ },
+ yAxis: {
+ type: "value",
+ name: "鑳借�楅噺",
+ axisLabel: {
+ color: "#333",
+ },
+ },
+ series: [
+ {
+ name: "鐢甸噺",
+ type: "line",
+ data: data.map(item => item.鐢甸噺),
+ smooth: true,
+ lineStyle: {
+ width: 3,
+ },
+ itemStyle: {
+ color: "#409EFF",
+ },
+ },
+ {
+ name: "姘撮噺",
+ type: "line",
+ data: data.map(item => item.姘撮噺),
+ smooth: true,
+ lineStyle: {
+ width: 3,
+ },
+ itemStyle: {
+ color: "#67C23A",
+ },
+ },
+ {
+ name: "姘旈噺",
+ type: "line",
+ data: data.map(item => item.姘旈噺),
+ smooth: true,
+ lineStyle: {
+ width: 3,
+ },
+ itemStyle: {
+ color: "#E6A23C",
+ },
+ },
+ ],
+ };
+ });
-const averageUnitConsumption = computed(() => {
- const data = costData.value
- const unitConsumption = dateType.value === 'month' ? data.month.unitConsumption : data.year.unitConsumption
- const average = unitConsumption.reduce((sum, value) => sum + value, 0) / unitConsumption.length
- return average.toFixed(4)
-})
+ const costTableData = computed(() => {
+ const data = costData.value;
+ const materials = data.materials;
+ const monthData = data.month;
+ const yearData = data.year;
-const totalEnergy = computed(() => {
- const data = energyData.value[dateType.value]
- if (dateType.value === 'month') {
- return data.reduce((sum, item) => sum + item.鐢甸噺 + item.姘撮噺 + item.姘旈噺, 0)
- } else {
- const lastItem = data[data.length - 1]
- return lastItem.鐢甸噺 + lastItem.姘撮噺 + lastItem.姘旈噺
- }
-})
+ return materials.map((material, index) => ({
+ material,
+ unit: "鍚�/绔嬫柟绫�",
+ monthlyConsumption: monthData.consumption[index],
+ monthlyProduction: monthData.production[index],
+ monthlyUnitConsumption: monthData.unitConsumption[index].toFixed(4),
+ yearlyConsumption: yearData.consumption[index],
+ yearlyProduction: yearData.production[index],
+ yearlyUnitConsumption: yearData.unitConsumption[index].toFixed(4),
+ }));
+ });
-// 浜嬩欢澶勭悊
-const handleDateTypeChange = () => {
- updateCharts()
-}
+ const totalProduction = computed(() => {
+ const data = productionData.value[dateType.value];
+ if (dateType.value === "month") {
+ return data.reduce(
+ (sum, item) =>
+ sum + item[productType.value === "block" ? "block" : "plate"],
+ 0
+ );
+ } else {
+ return data[data.length - 1][
+ productType.value === "block" ? "block" : "plate"
+ ];
+ }
+ });
-const handleProductTypeChange = () => {
- updateCharts()
-}
+ const totalSolidWaste = computed(() => {
+ const data = solidWasteData.value[dateType.value];
+ if (dateType.value === "month") {
+ return data.reduce(
+ (sum, item) => sum + item.绮夌叅鐏� + item.鐭宠啅 + item.鐭崇伆,
+ 0
+ );
+ } else {
+ const lastItem = data[data.length - 1];
+ return lastItem.绮夌叅鐏� + lastItem.鐭宠啅 + lastItem.鐭崇伆;
+ }
+ });
-// 鍒濆鍖栧浘琛�
-const initCharts = () => {
- if (productionChart.value) {
- productionChartInstance = echarts.init(productionChart.value)
- productionChartInstance.setOption(productionChartOption.value)
- }
-
- if (solidWasteChart.value) {
- solidWasteChartInstance = echarts.init(solidWasteChart.value)
- solidWasteChartInstance.setOption(solidWasteChartOption.value)
- }
-
- if (costChart.value) {
- costChartInstance = echarts.init(costChart.value)
- costChartInstance.setOption(costChartOption.value)
- }
-
- if (energyChart.value) {
- energyChartInstance = echarts.init(energyChart.value)
- energyChartInstance.setOption(energyChartOption.value)
- }
-}
+ const averageUnitConsumption = computed(() => {
+ const data = costData.value;
+ const unitConsumption =
+ dateType.value === "month"
+ ? data.month.unitConsumption
+ : data.year.unitConsumption;
+ const average =
+ unitConsumption.reduce((sum, value) => sum + value, 0) /
+ unitConsumption.length;
+ return average.toFixed(4);
+ });
-// 鏇存柊鍥捐〃
-const updateCharts = () => {
- if (productionChartInstance) {
- productionChartInstance.setOption(productionChartOption.value)
- }
-
- if (solidWasteChartInstance) {
- solidWasteChartInstance.setOption(solidWasteChartOption.value)
- }
-
- if (costChartInstance) {
- costChartInstance.setOption(costChartOption.value)
- }
-
- if (energyChartInstance) {
- energyChartInstance.setOption(energyChartOption.value)
- }
-}
+ const totalEnergy = computed(() => {
+ const data = energyData.value[dateType.value];
+ if (dateType.value === "month") {
+ return data.reduce(
+ (sum, item) => sum + item.鐢甸噺 + item.姘撮噺 + item.姘旈噺,
+ 0
+ );
+ } else {
+ const lastItem = data[data.length - 1];
+ return lastItem.鐢甸噺 + lastItem.姘撮噺 + lastItem.姘旈噺;
+ }
+ });
-// 璋冩暣鍥捐〃澶у皬
-const resizeCharts = () => {
- productionChartInstance?.resize()
- solidWasteChartInstance?.resize()
- costChartInstance?.resize()
- energyChartInstance?.resize()
-}
+ // 浜嬩欢澶勭悊
+ const handleDateTypeChange = () => {
+ updateCharts();
+ };
-// 绐楀彛澶у皬鍙樺寲澶勭悊
-const handleResize = () => {
- // 寤惰繜鎵ц锛岀‘淇滵OM鏇存柊瀹屾垚
- setTimeout(() => {
- resizeCharts()
- }, 100)
-}
+ const handleProductTypeChange = () => {
+ updateCharts();
+ };
-// 鐢熷懡鍛ㄦ湡閽╁瓙
-onMounted(() => {
- // 浣跨敤nextTick纭繚DOM瀹屽叏娓叉煋鍚庡啀鍒濆鍖�
- nextTick(() => {
- // 鍒濆鍖栧浘琛�
- initCharts()
- })
+ // 鍒濆鍖栧浘琛�
+ const initCharts = () => {
+ if (productionChart.value) {
+ productionChartInstance = echarts.init(productionChart.value);
+ productionChartInstance.setOption(productionChartOption.value);
+ }
- window.addEventListener('resize', handleResize)
-})
+ if (solidWasteChart.value) {
+ solidWasteChartInstance = echarts.init(solidWasteChart.value);
+ solidWasteChartInstance.setOption(solidWasteChartOption.value);
+ }
-onBeforeUnmount(() => {
- window.removeEventListener('resize', handleResize)
-
- // 閿�姣佸浘琛ㄥ疄渚�
- productionChartInstance?.dispose()
- solidWasteChartInstance?.dispose()
- costChartInstance?.dispose()
- energyChartInstance?.dispose()
-})
+ if (costChart.value) {
+ costChartInstance = echarts.init(costChart.value);
+ costChartInstance.setOption(costChartOption.value);
+ }
+
+ if (energyChart.value) {
+ energyChartInstance = echarts.init(energyChart.value);
+ energyChartInstance.setOption(energyChartOption.value);
+ }
+ };
+
+ // 鏇存柊鍥捐〃
+ const updateCharts = () => {
+ if (productionChartInstance) {
+ productionChartInstance.setOption(productionChartOption.value);
+ }
+
+ if (solidWasteChartInstance) {
+ solidWasteChartInstance.setOption(solidWasteChartOption.value);
+ }
+
+ if (costChartInstance) {
+ costChartInstance.setOption(costChartOption.value);
+ }
+
+ if (energyChartInstance) {
+ energyChartInstance.setOption(energyChartOption.value);
+ }
+ };
+
+ // 璋冩暣鍥捐〃澶у皬
+ const resizeCharts = () => {
+ productionChartInstance?.resize();
+ solidWasteChartInstance?.resize();
+ costChartInstance?.resize();
+ energyChartInstance?.resize();
+ };
+
+ // 绐楀彛澶у皬鍙樺寲澶勭悊
+ const handleResize = () => {
+ // 寤惰繜鎵ц锛岀‘淇滵OM鏇存柊瀹屾垚
+ setTimeout(() => {
+ resizeCharts();
+ }, 100);
+ };
+
+ // 鑾峰彇鐗╂枡绫诲瀷鏍囩绫诲瀷
+ const getMaterialTypeType = material => {
+ const typeMap = {
+ 姘存偿: "primary",
+ 閾濈矇鑶�: "success",
+ 鑴辨ā鍓�: "warning",
+ 闃茶厫鍓�: "danger",
+ 姘寲鍓�: "info",
+ 鍐锋嫈涓�: "purple",
+ };
+ return typeMap[material] || "info";
+ };
+
+ // 鐢熷懡鍛ㄦ湡閽╁瓙
+ onMounted(() => {
+ // 浣跨敤nextTick纭繚DOM瀹屽叏娓叉煋鍚庡啀鍒濆鍖�
+ nextTick(() => {
+ // 鍒濆鍖栧浘琛�
+ initCharts();
+ });
+
+ window.addEventListener("resize", handleResize);
+ });
+
+ onBeforeUnmount(() => {
+ window.removeEventListener("resize", handleResize);
+
+ // 閿�姣佸浘琛ㄥ疄渚�
+ productionChartInstance?.dispose();
+ solidWasteChartInstance?.dispose();
+ costChartInstance?.dispose();
+ energyChartInstance?.dispose();
+ });
</script>
<style scoped>
-/* 澶栭儴瀹瑰櫒 - 鍗犳嵁鏁翠釜瑙嗗彛 */
-.dashboard-container {
- position: relative;
- width: 100%;
- /* 椤甸潰鍦ㄥ父瑙勫竷灞�涓嬶紙鏈夐《鏍忥級榛樿鍑忓幓 84px锛岄伩鍏嶅唴瀹硅瑁佸垏 */
- min-height: calc(100vh - 84px);
- background-color: #f5f7fa;
- overflow: hidden;
-}
+ /* 澶栭儴瀹瑰櫒 - 鍗犳嵁鏁翠釜瑙嗗彛 */
+ .dashboard-container {
+ position: relative;
+ width: 100%;
+ /* 椤甸潰鍦ㄥ父瑙勫竷灞�涓嬶紙鏈夐《鏍忥級榛樿鍑忓幓 84px锛岄伩鍏嶅唴瀹硅瑁佸垏 */
+ min-height: calc(100vh - 84px);
+ background-color: #f5f7fa;
+ overflow: hidden;
+ }
-/* 鍐呴儴鍐呭鍖哄煙 - 鑷�傚簲瀹藉害 */
-.data-dashboard {
- position: relative;
- width: 100%;
- min-height: 100%;
- background-color: #ffffff;
- box-shadow: 0 0 20px rgba(0, 0, 0, 0.1);
-}
+ /* 鍐呴儴鍐呭鍖哄煙 - 鑷�傚簲瀹藉害 */
+ .data-dashboard {
+ position: relative;
+ width: 100%;
+ min-height: 100%;
+ background-color: #ffffff;
+ box-shadow: 0 0 20px rgba(0, 0, 0, 0.1);
+ }
-.dashboard-header {
- position: relative;
- z-index: 1;
- height: 86px;
- background-color: #ffffff;
- border-bottom: 1px solid #e4e7ed;
- display: flex;
- align-items: center;
- justify-content: center;
-}
+ .dashboard-header {
+ position: relative;
+ z-index: 1;
+ height: 86px;
+ background-color: #ffffff;
+ border-bottom: 1px solid #e4e7ed;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
-.factory-name {
- font-weight: 600;
- font-size: 32px;
- color: #303133;
-}
+ .factory-name {
+ font-weight: 600;
+ font-size: 32px;
+ color: #303133;
+ }
-.filter-area {
- padding: 20px;
- background-color: #ffffff;
- border-bottom: 1px solid #e4e7ed;
- display: flex;
- gap: 40px;
- align-items: center;
- flex-wrap: wrap;
-}
+ .filter-area {
+ padding: 20px;
+ background-color: #ffffff;
+ border-bottom: 1px solid #e4e7ed;
+ display: flex;
+ gap: 40px;
+ align-items: center;
+ flex-wrap: wrap;
+ }
-.filter-section {
- display: flex;
- align-items: center;
- gap: 10px;
-}
+ .filter-section {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ }
-.filter-label {
- font-size: 14px;
- font-weight: 500;
- color: #303133;
- white-space: nowrap;
-}
+ .filter-label {
+ font-size: 14px;
+ font-weight: 500;
+ color: #303133;
+ white-space: nowrap;
+ }
-.radio-group {
- display: flex;
- align-items: center;
-}
+ .radio-group {
+ display: flex;
+ align-items: center;
+ }
-/* 鎸夐挳鏍峰紡 */
-:deep(.el-radio-button__inner) {
- border-radius: 4px;
- padding: 8px 20px;
- font-size: 14px;
- transition: all 0.3s ease;
-}
+ /* 鎸夐挳鏍峰紡 */
+ :deep(.el-radio-button__inner) {
+ border-radius: 4px;
+ padding: 8px 20px;
+ font-size: 14px;
+ transition: all 0.3s ease;
+ }
-:deep(.el-radio-button__orig-radio:checked + .el-radio-button__inner) {
- background-color: #409eff;
- border-color: #409eff;
- color: #ffffff;
- box-shadow: 0 2px 4px rgba(64, 158, 255, 0.3);
-}
+ :deep(.el-radio-button__orig-radio:checked + .el-radio-button__inner) {
+ background-color: #409eff;
+ border-color: #409eff;
+ color: #ffffff;
+ box-shadow: 0 2px 4px rgba(64, 158, 255, 0.3);
+ }
-:deep(.el-radio-button__inner:hover) {
- color: #409eff;
- border-color: #c6e2ff;
-}
+ :deep(.el-radio-button__inner:hover) {
+ color: #409eff;
+ border-color: #c6e2ff;
+ }
-:deep(.el-radio-button:first-child .el-radio-button__inner) {
- border-radius: 4px 0 0 4px;
-}
+ :deep(.el-radio-button:first-child .el-radio-button__inner) {
+ border-radius: 4px 0 0 4px;
+ }
-:deep(.el-radio-button:last-child .el-radio-button__inner) {
- border-radius: 0 4px 4px 0;
-}
+ :deep(.el-radio-button:last-child .el-radio-button__inner) {
+ border-radius: 0 4px 4px 0;
+ }
-.dashboard-content {
- position: relative;
- z-index: 1;
- display: flex;
- flex-direction: column;
- gap: 20px;
- padding: 20px;
- min-height: 800px;
- overflow: hidden;
-}
+ .dashboard-content {
+ position: relative;
+ z-index: 1;
+ display: flex;
+ flex-direction: column;
+ gap: 20px;
+ padding: 20px;
+ min-height: 800px;
+ overflow: hidden;
+ }
-/* 琛屽竷灞� */
-.row {
- display: flex;
- gap: 20px;
- align-items: stretch;
-}
+ /* 琛屽竷灞� */
+ .row {
+ display: flex;
+ gap: 20px;
+ align-items: stretch;
+ }
-/* 绗竴琛岋細3涓崱鐗� */
-.row-1 {
- height: 300px;
-}
+ /* 绗竴琛岋細3涓崱鐗� */
+ .row-1 {
+ height: 300px;
+ }
-/* 绗簩琛岋細2涓崱鐗� */
-.row-2 {
- height: 300px;
-}
+ /* 绗簩琛岋細2涓崱鐗� */
+ .row-2 {
+ height: 300px;
+ }
-/* 绗笁琛岋細1涓崱鐗� */
-.row-3 {
- min-height: 250px;
-}
+ /* 绗笁琛岋細1涓崱鐗� */
+ .row-3 {
+ min-height: 250px;
+ }
-/* 鍗$墖鏍峰紡 */
-.panel-card {
- background-color: #ffffff;
- border-radius: 8px;
- border: 1px solid #e4e7ed;
- overflow: hidden;
- display: flex;
- flex-direction: column;
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
- transition: all 0.3s ease;
-}
+ /* 鍗$墖鏍峰紡 */
+ .panel-card {
+ background-color: #ffffff;
+ border-radius: 8px;
+ border: 1px solid #e4e7ed;
+ overflow: hidden;
+ display: flex;
+ flex-direction: column;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
+ transition: all 0.3s ease;
+ }
-.panel-card:hover {
- box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
- transform: translateY(-2px);
-}
+ .panel-card:hover {
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
+ transform: translateY(-2px);
+ }
-/* 鍗$墖甯冨眬 */
-.card-1 {
- flex: 1;
-}
+ /* 鍗$墖甯冨眬 */
+ .card-1 {
+ flex: 1;
+ }
-.card-2 {
- flex: 1;
-}
+ .card-2 {
+ flex: 1;
+ }
-.card-3 {
- flex: 0.8;
-}
+ .card-3 {
+ flex: 0.8;
+ }
-.card-4 {
- flex: 1.2;
-}
+ .card-4 {
+ flex: 1.2;
+ }
-.card-5 {
- flex: 0.8;
-}
+ .card-5 {
+ flex: 0.8;
+ }
-.card-6 {
- flex: 1;
-}
+ .card-6 {
+ flex: 1;
+ }
-.panel-card {
- background-color: #ffffff;
- border-radius: 8px;
- border: 1px solid #e4e7ed;
- overflow: hidden;
- flex: 1;
- display: flex;
- flex-direction: column;
-}
+ .panel-card {
+ background-color: #ffffff;
+ border-radius: 8px;
+ border: 1px solid #e4e7ed;
+ overflow: hidden;
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ }
-.panel-title {
- padding: 15px 20px;
- font-size: 16px;
- font-weight: 500;
- color: #303133;
- border-bottom: 1px solid #e4e7ed;
- background-color: #fafafa;
-}
+ .panel-title {
+ padding: 15px 20px;
+ font-size: 16px;
+ font-weight: 500;
+ color: #303133;
+ border-bottom: 1px solid #e4e7ed;
+ background-color: #fafafa;
+ }
-.chart-container {
- flex: 1;
- padding: 20px;
-}
+ .card-1 .panel-title {
+ border-left: 4px solid #409eff;
+ }
-.table-container {
- flex: 1;
- padding: 20px;
- overflow: auto;
-}
+ .card-2 .panel-title {
+ border-left: 4px solid #f56c6c;
+ }
-.stats-grid {
- flex: 1;
- padding: 15px;
- display: grid;
- grid-template-columns: repeat(2, 1fr);
- grid-template-rows: repeat(2, 1fr);
- gap: 15px;
-}
+ .card-3 .panel-title {
+ border-left: 4px solid #e6a23c;
+ }
-.stat-item {
- background-color: #fafafa;
- border-radius: 8px;
- padding: 15px;
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- border: 1px solid #e4e7ed;
- min-height: 80px;
-}
+ .card-4 .panel-title {
+ border-left: 4px solid #409eff;
+ }
-.stat-label {
- font-size: 13px;
- color: #606266;
- margin-bottom: 8px;
-}
+ .card-5 .panel-title {
+ border-left: 4px solid #67c23a;
+ }
-.stat-value {
- font-size: 20px;
- font-weight: 600;
- color: #303133;
- margin-bottom: 3px;
-}
+ .card-6 .panel-title {
+ border-left: 4px solid #e6a23c;
+ }
-.stat-unit {
- font-size: 11px;
- color: #909399;
-}
+ .chart-container {
+ flex: 1;
+ padding: 20px;
+ }
-/* 琛ㄦ牸鏍峰紡 */
-:deep(.el-table) {
- border-radius: 8px;
- overflow: hidden;
-}
+ .table-container {
+ flex: 1;
+ padding: 20px;
+ overflow: auto;
+ }
-:deep(.el-table th) {
- background-color: #fafafa;
- font-weight: 500;
-}
+ .stats-grid {
+ flex: 1;
+ padding: 15px;
+ display: grid;
+ grid-template-columns: repeat(2, 1fr);
+ grid-template-rows: repeat(2, 1fr);
+ gap: 15px;
+ }
-:deep(.el-table tr:hover > td) {
- background-color: #ecf5ff;
-}
+ .stat-item {
+ background-color: #fafafa;
+ border-radius: 8px;
+ padding: 15px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ border: 1px solid #e4e7ed;
+ min-height: 80px;
+ }
-/* 鎸夐挳鏍峰紡 */
-:deep(.el-radio-button__inner) {
- border-radius: 4px;
-}
+ .stat-label {
+ font-size: 13px;
+ color: #606266;
+ margin-bottom: 8px;
+ }
-:deep(.el-radio-button__orig-radio:checked + .el-radio-button__inner) {
- background-color: #409eff;
- border-color: #409eff;
- color: #ffffff;
-}
+ .stat-value {
+ font-size: 20px;
+ font-weight: 600;
+ color: #303133;
+ margin-bottom: 3px;
+ }
+
+ .production-color {
+ color: #409eff;
+ text-shadow: 0 2px 4px rgba(64, 158, 255, 0.3);
+ }
+
+ .waste-color {
+ color: #f56c6c;
+ text-shadow: 0 2px 4px rgba(245, 108, 108, 0.3);
+ }
+
+ .consumption-color {
+ color: #e6a23c;
+ text-shadow: 0 2px 4px rgba(230, 162, 60, 0.3);
+ }
+
+ .energy-color {
+ color: #67c23a;
+ text-shadow: 0 2px 4px rgba(103, 194, 58, 0.3);
+ }
+
+ .stat-unit {
+ font-size: 11px;
+ color: #909399;
+ }
+
+ /* 琛ㄦ牸鏍峰紡 */
+ :deep(.el-table) {
+ border-radius: 8px;
+ overflow: hidden;
+ }
+
+ :deep(.el-table th) {
+ background-color: #fafafa;
+ font-weight: 500;
+ }
+
+ :deep(.el-table tr:hover > td) {
+ background-color: #ecf5ff;
+ }
+
+ .data-value {
+ font-weight: bold;
+ color: #409eff;
+ }
+
+ /* 鎸夐挳鏍峰紡 */
+ :deep(.el-radio-button__inner) {
+ border-radius: 4px;
+ }
+
+ :deep(.el-radio-button__orig-radio:checked + .el-radio-button__inner) {
+ background-color: #409eff;
+ border-color: #409eff;
+ color: #ffffff;
+ }
</style>
\ No newline at end of file
diff --git a/src/views/reportAnalysis/salesStatistics/index.vue b/src/views/reportAnalysis/salesStatistics/index.vue
index 8dc1a6a..d1c76d4 100644
--- a/src/views/reportAnalysis/salesStatistics/index.vue
+++ b/src/views/reportAnalysis/salesStatistics/index.vue
@@ -5,51 +5,68 @@
<!-- <div class="dashboard-header">
<div class="factory-name">閿�鍞粺璁$湅鏉�</div>
</div> -->
-
<!-- 绛涢�夋潯浠� -->
<div class="filter-area">
<div class="filter-section">
<span class="filter-label">鏃堕棿鑼冨洿锛�</span>
- <el-date-picker
- v-model="dateRange"
- type="daterange"
- range-separator="鑷�"
- start-placeholder="寮�濮嬫棩鏈�"
- end-placeholder="缁撴潫鏃ユ湡"
- value-format="YYYY-MM-DD"
- @change="handleDateChange"
- style="width: 240px;"
- />
+ <el-date-picker v-model="dateRange"
+ type="daterange"
+ range-separator="鑷�"
+ start-placeholder="寮�濮嬫棩鏈�"
+ end-placeholder="缁撴潫鏃ユ湡"
+ value-format="YYYY-MM-DD"
+ @change="handleDateChange"
+ style="width: 240px;" />
</div>
<div class="filter-section">
<span class="filter-label">浜у搧绫诲瀷锛�</span>
- <el-select v-model="productType" placeholder="璇烽�夋嫨浜у搧绫诲瀷" @change="handleFilterChange" style="width: 160px;">
- <el-option label="鍏ㄩ儴" value="" />
- <el-option label="鐮屽潡" value="block" />
- <el-option label="鏉挎潗" value="board" />
- <el-option label="鍨嬫潗" value="profile" />
+ <el-select v-model="productType"
+ placeholder="璇烽�夋嫨浜у搧绫诲瀷"
+ @change="handleFilterChange"
+ style="width: 160px;">
+ <el-option label="鍏ㄩ儴"
+ value="" />
+ <el-option label="鐮屽潡"
+ value="block" />
+ <el-option label="鏉挎潗"
+ value="board" />
+ <el-option label="鍨嬫潗"
+ value="profile" />
</el-select>
</div>
<div class="filter-section">
<span class="filter-label">閿�鍞尯鍩燂細</span>
- <el-select v-model="salesArea" placeholder="璇烽�夋嫨閿�鍞尯鍩�" @change="handleFilterChange" style="width: 160px;">
- <el-option label="鍏ㄩ儴" value="" />
- <el-option label="鍗庝笢" value="east" />
- <el-option label="鍗庡寳" value="north" />
- <el-option label="鍗庡崡" value="south" />
- <el-option label="瑗垮崡" value="southwest" />
- <el-option label="瑗垮寳" value="northwest" />
+ <el-select v-model="salesArea"
+ placeholder="璇烽�夋嫨閿�鍞尯鍩�"
+ @change="handleFilterChange"
+ style="width: 160px;">
+ <el-option label="鍏ㄩ儴"
+ value="" />
+ <el-option label="鍗庝笢"
+ value="east" />
+ <el-option label="鍗庡寳"
+ value="north" />
+ <el-option label="鍗庡崡"
+ value="south" />
+ <el-option label="瑗垮崡"
+ value="southwest" />
+ <el-option label="瑗垮寳"
+ value="northwest" />
</el-select>
</div>
<div class="filter-section">
<span class="filter-label">缁熻缁村害锛�</span>
- <el-select v-model="statDimension" placeholder="璇烽�夋嫨缁熻缁村害" @change="handleFilterChange" style="width: 160px;">
- <el-option label="鏈堝害" value="month" />
- <el-option label="骞村害" value="year" />
+ <el-select v-model="statDimension"
+ placeholder="璇烽�夋嫨缁熻缁村害"
+ @change="handleFilterChange"
+ style="width: 160px;">
+ <el-option label="鏈堝害"
+ value="month" />
+ <el-option label="骞村害"
+ value="year" />
</el-select>
</div>
</div>
-
<div class="dashboard-content">
<!-- 鏍稿績鎸囨爣鍗$墖 -->
<div class="row row-1">
@@ -57,7 +74,7 @@
<div class="panel-title">鍚堣閿�閲�</div>
<div class="stats-grid">
<div class="stat-item">
- <div class="stat-value">{{ totalSalesVolume }}</div>
+ <div class="stat-value sales-volume-color">{{ totalSalesVolume }}</div>
<div class="stat-unit">绔嬫柟绫�</div>
<div class="stat-change">{{ salesVolumeChange }}%</div>
</div>
@@ -67,7 +84,7 @@
<div class="panel-title">閿�鍞噾棰�</div>
<div class="stats-grid">
<div class="stat-item">
- <div class="stat-value">{{ totalSalesAmount }}</div>
+ <div class="stat-value sales-amount-color">{{ totalSalesAmount }}</div>
<div class="stat-unit">涓囧厓</div>
<div class="stat-change">{{ salesAmountChange }}%</div>
</div>
@@ -77,7 +94,7 @@
<div class="panel-title">鏂板瀹㈡埛</div>
<div class="stats-grid">
<div class="stat-item">
- <div class="stat-value">{{ newCustomerCount }}</div>
+ <div class="stat-value new-customer-color">{{ newCustomerCount }}</div>
<div class="stat-unit">涓�</div>
<div class="stat-change">{{ customerCountChange }}%</div>
</div>
@@ -87,76 +104,129 @@
<div class="panel-title">鍚堣瀹㈡埛</div>
<div class="stats-grid">
<div class="stat-item">
- <div class="stat-value">{{ totalCustomerCount }}</div>
+ <div class="stat-value total-customer-color">{{ totalCustomerCount }}</div>
<div class="stat-unit">涓�</div>
<div class="stat-change">{{ totalCustomerChange }}%</div>
</div>
</div>
</div>
</div>
-
<!-- 閿�閲忓拰閿�鍞噾棰濊秼鍔� -->
<div class="row row-2">
<div class="panel-card card-5">
<div class="panel-title">閿�閲忚秼鍔�</div>
<div class="chart-container">
- <div ref="salesVolumeChart" style="width: 100%; height: 100%;"></div>
+ <div ref="salesVolumeChart"
+ style="width: 100%; height: 100%;"></div>
</div>
</div>
<div class="panel-card card-6">
<div class="panel-title">閿�鍞噾棰濊秼鍔�</div>
<div class="chart-container">
- <div ref="salesAmountChart" style="width: 100%; height: 100%;"></div>
+ <div ref="salesAmountChart"
+ style="width: 100%; height: 100%;"></div>
</div>
</div>
</div>
-
<!-- 绱鏁版嵁瓒嬪娍 -->
- <div class="row row-3">
+ <!-- <div class="row row-3">
<div class="panel-card card-10">
<div class="panel-title">绱閿�閲忚秼鍔�</div>
<div class="chart-container">
- <div ref="cumulativeSalesVolumeChart" style="width: 100%; height: 100%;"></div>
+ <div ref="cumulativeSalesVolumeChart"
+ style="width: 100%; height: 100%;"></div>
</div>
</div>
<div class="panel-card card-11">
<div class="panel-title">绱閿�鍞噾棰濊秼鍔�</div>
<div class="chart-container">
- <div ref="cumulativeSalesAmountChart" style="width: 100%; height: 100%;"></div>
+ <div ref="cumulativeSalesAmountChart"
+ style="width: 100%; height: 100%;"></div>
</div>
</div>
- </div>
-
+ </div> -->
<!-- 鍥捐〃鍖哄煙鍜岃〃鏍� -->
<div class="row row-4">
<!-- 宸﹁竟锛氳缁嗘暟鎹〃鏍� -->
- <div class="panel-card card-9" style="flex: 2;">
+ <div class="panel-card card-9"
+ style="flex: 2;">
<div class="panel-title">閿�鍞粺璁¤缁嗘暟鎹�</div>
<div class="table-container">
- <el-table :data="tableData" style="width: 100%">
- <el-table-column prop="productType" label="浜у搧绫诲瀷" width="120" />
- <el-table-column prop="salesArea" label="閿�鍞尯鍩�" width="120" />
- <el-table-column prop="period" label="缁熻鍛ㄦ湡" width="120" />
- <el-table-column prop="salesVolume" label="閿�閲�(绔嬫柟绫�)" />
- <el-table-column prop="salesAmount" label="閿�鍞噾棰�(涓囧厓)" />
- <el-table-column prop="newCustomers" label="鏂板瀹㈡埛(涓�)" width="150" />
- <el-table-column prop="totalCustomers" label="鍚堣瀹㈡埛(涓�)" width="150" />
+ <el-table :data="tableData"
+ style="width: 100%">
+ <el-table-column prop="productType"
+ label="浜у搧绫诲瀷"
+ width="120"
+ align="center">
+ <template #default="scope">
+ <el-tag :type="getProductTypeType(scope.row.productType)">
+ {{ scope.row.productType }}
+ </el-tag>
+ </template>
+ </el-table-column>
+ <el-table-column prop="salesArea"
+ label="閿�鍞尯鍩�"
+ width="120"
+ align="center">
+ <template #default="scope">
+ <el-tag :type="getSalesAreaType(scope.row.salesArea)">
+ {{ scope.row.salesArea }}
+ </el-tag>
+ </template>
+ </el-table-column>
+ <el-table-column prop="period"
+ label="缁熻鍛ㄦ湡"
+ width="120" />
+ <el-table-column prop="salesVolume"
+ label="閿�閲�(绔嬫柟绫�)"
+ align="right">
+ <template #default="scope">
+ <span class="data-value">{{ scope.row.salesVolume }}</span>
+ </template>
+ </el-table-column>
+ <el-table-column prop="salesAmount"
+ label="閿�鍞噾棰�(涓囧厓)"
+ align="right">
+ <template #default="scope">
+ <span class="data-value">{{ scope.row.salesAmount }}</span>
+ </template>
+ </el-table-column>
+ <el-table-column prop="newCustomers"
+ label="鏂板瀹㈡埛(涓�)"
+ width="150"
+ align="right">
+ <template #default="scope">
+ <span class="data-value">{{ scope.row.newCustomers }}</span>
+ </template>
+ </el-table-column>
+ <el-table-column prop="totalCustomers"
+ label="鍚堣瀹㈡埛(涓�)"
+ width="150"
+ align="right">
+ <template #default="scope">
+ <span class="data-value">{{ scope.row.totalCustomers }}</span>
+ </template>
+ </el-table-column>
</el-table>
</div>
</div>
-
<!-- 鍙宠竟锛氫骇鍝佺被鍨嬪垎甯冨拰閿�鍞尯鍩熷垎甯� -->
- <div class="chart-column" style="flex: 1; display: flex; flex-direction: column; gap: 20px;">
- <div class="panel-card card-7" style="flex: 1;">
+ <div class="chart-column"
+ style="flex: 1; display: flex; flex-direction: column; gap: 20px;">
+ <div class="panel-card card-7"
+ style="flex: 1;">
<div class="panel-title">浜у搧绫诲瀷鍒嗗竷</div>
<div class="chart-container">
- <div ref="productTypeChart" style="width: 100%; height: 100%;"></div>
+ <div ref="productTypeChart"
+ style="width: 100%; height: 100%;"></div>
</div>
</div>
- <div class="panel-card card-8" style="flex: 1;">
+ <div class="panel-card card-8"
+ style="flex: 1;">
<div class="panel-title">閿�鍞尯鍩熷垎甯�</div>
<div class="chart-container">
- <div ref="salesAreaChart" style="width: 100%; height: 100%;"></div>
+ <div ref="salesAreaChart"
+ style="width: 100%; height: 100%;"></div>
</div>
</div>
</div>
@@ -167,757 +237,1068 @@
</template>
<script setup>
-import { ref, computed, onMounted, onBeforeUnmount, watch, nextTick } from 'vue';
-import { useRouter } from 'vue-router';
-import * as echarts from 'echarts';
-import dayjs from 'dayjs';
+ import {
+ ref,
+ computed,
+ onMounted,
+ onBeforeUnmount,
+ watch,
+ nextTick,
+ } from "vue";
+ import { useRouter } from "vue-router";
+ import * as echarts from "echarts";
+ import dayjs from "dayjs";
-const router = useRouter();
+ const router = useRouter();
-// 绛涢�夋潯浠�
-const dateRange = ref([]);
-const productType = ref('');
-const salesArea = ref('');
-const statDimension = ref('month');
+ // 绛涢�夋潯浠�
+ const dateRange = ref([]);
+ const productType = ref("");
+ const salesArea = ref("");
+ const statDimension = ref("month");
-// 鍥捐〃寮曠敤
-const salesVolumeChart = ref(null);
-const salesAmountChart = ref(null);
-const productTypeChart = ref(null);
-const salesAreaChart = ref(null);
-const cumulativeSalesVolumeChart = ref(null);
-const cumulativeSalesAmountChart = ref(null);
+ // 鍥捐〃寮曠敤
+ const salesVolumeChart = ref(null);
+ const salesAmountChart = ref(null);
+ const productTypeChart = ref(null);
+ const salesAreaChart = ref(null);
+ const cumulativeSalesVolumeChart = ref(null);
+ const cumulativeSalesAmountChart = ref(null);
-// 鍥捐〃瀹炰緥
-let salesVolumeChartInstance = null;
-let salesAmountChartInstance = null;
-let productTypeChartInstance = null;
-let salesAreaChartInstance = null;
-let cumulativeSalesVolumeChartInstance = null;
-let cumulativeSalesAmountChartInstance = null;
+ // 鍥捐〃瀹炰緥
+ let salesVolumeChartInstance = null;
+ let salesAmountChartInstance = null;
+ let productTypeChartInstance = null;
+ let salesAreaChartInstance = null;
+ let cumulativeSalesVolumeChartInstance = null;
+ let cumulativeSalesAmountChartInstance = null;
-// 妯℃嫙鏁版嵁
-const mockData = [
- // 2026骞�1鏈堟暟鎹�
- { productType: '鐮屽潡', salesArea: '鍗庝笢', period: '2026-01', salesVolume: 1200, salesAmount: 180, newCustomers: 5, totalCustomers: 120 },
- { productType: '鐮屽潡', salesArea: '鍗庡寳', period: '2026-01', salesVolume: 800, salesAmount: 120, newCustomers: 3, totalCustomers: 80 },
- { productType: '鐮屽潡', salesArea: '鍗庡崡', period: '2026-01', salesVolume: 600, salesAmount: 90, newCustomers: 2, totalCustomers: 60 },
- { productType: '鏉挎潗', salesArea: '鍗庝笢', period: '2026-01', salesVolume: 900, salesAmount: 270, newCustomers: 4, totalCustomers: 100 },
- { productType: '鏉挎潗', salesArea: '鍗庡寳', period: '2026-01', salesVolume: 500, salesAmount: 150, newCustomers: 2, totalCustomers: 70 },
- { productType: '鍨嬫潗', salesArea: '鍗庝笢', period: '2026-01', salesVolume: 400, salesAmount: 200, newCustomers: 3, totalCustomers: 50 },
- // 2026骞�2鏈堟暟鎹�
- { productType: '鐮屽潡', salesArea: '鍗庝笢', period: '2026-02', salesVolume: 1300, salesAmount: 195, newCustomers: 4, totalCustomers: 124 },
- { productType: '鐮屽潡', salesArea: '鍗庡寳', period: '2026-02', salesVolume: 850, salesAmount: 127.5, newCustomers: 2, totalCustomers: 82 },
- { productType: '鐮屽潡', salesArea: '鍗庡崡', period: '2026-02', salesVolume: 650, salesAmount: 97.5, newCustomers: 1, totalCustomers: 61 },
- { productType: '鏉挎潗', salesArea: '鍗庝笢', period: '2026-02', salesVolume: 950, salesAmount: 285, newCustomers: 3, totalCustomers: 103 },
- { productType: '鏉挎潗', salesArea: '鍗庡寳', period: '2026-02', salesVolume: 550, salesAmount: 165, newCustomers: 1, totalCustomers: 71 },
- { productType: '鍨嬫潗', salesArea: '鍗庝笢', period: '2026-02', salesVolume: 450, salesAmount: 225, newCustomers: 2, totalCustomers: 52 },
- // 2026骞�3鏈堟暟鎹�
- { productType: '鐮屽潡', salesArea: '鍗庝笢', period: '2026-03', salesVolume: 1400, salesAmount: 210, newCustomers: 6, totalCustomers: 130 },
- { productType: '鐮屽潡', salesArea: '鍗庡寳', period: '2026-03', salesVolume: 900, salesAmount: 135, newCustomers: 3, totalCustomers: 85 },
- { productType: '鐮屽潡', salesArea: '鍗庡崡', period: '2026-03', salesVolume: 700, salesAmount: 105, newCustomers: 2, totalCustomers: 63 },
- { productType: '鏉挎潗', salesArea: '鍗庝笢', period: '2026-03', salesVolume: 1000, salesAmount: 300, newCustomers: 5, totalCustomers: 108 },
- { productType: '鏉挎潗', salesArea: '鍗庡寳', period: '2026-03', salesVolume: 600, salesAmount: 180, newCustomers: 2, totalCustomers: 73 },
- { productType: '鍨嬫潗', salesArea: '鍗庝笢', period: '2026-03', salesVolume: 500, salesAmount: 250, newCustomers: 3, totalCustomers: 55 },
- // 瑗垮崡鍜岃タ鍖楀湴鍖烘暟鎹�
- { productType: '鐮屽潡', salesArea: '瑗垮崡', period: '2026-03', salesVolume: 500, salesAmount: 75, newCustomers: 2, totalCustomers: 40 },
- { productType: '鏉挎潗', salesArea: '瑗垮崡', period: '2026-03', salesVolume: 300, salesAmount: 90, newCustomers: 1, totalCustomers: 30 },
- { productType: '鐮屽潡', salesArea: '瑗垮寳', period: '2026-03', salesVolume: 400, salesAmount: 60, newCustomers: 1, totalCustomers: 35 },
- { productType: '鏉挎潗', salesArea: '瑗垮寳', period: '2026-03', salesVolume: 200, salesAmount: 60, newCustomers: 1, totalCustomers: 25 },
-];
+ // 妯℃嫙鏁版嵁
+ const mockData = [
+ // 2026骞�1鏈堟暟鎹�
+ {
+ productType: "鐮屽潡",
+ salesArea: "鍗庝笢",
+ period: "2026-01",
+ salesVolume: 1200,
+ salesAmount: 180,
+ newCustomers: 5,
+ totalCustomers: 120,
+ },
+ {
+ productType: "鐮屽潡",
+ salesArea: "鍗庡寳",
+ period: "2026-01",
+ salesVolume: 800,
+ salesAmount: 120,
+ newCustomers: 3,
+ totalCustomers: 80,
+ },
+ {
+ productType: "鐮屽潡",
+ salesArea: "鍗庡崡",
+ period: "2026-01",
+ salesVolume: 600,
+ salesAmount: 90,
+ newCustomers: 2,
+ totalCustomers: 60,
+ },
+ {
+ productType: "鏉挎潗",
+ salesArea: "鍗庝笢",
+ period: "2026-01",
+ salesVolume: 900,
+ salesAmount: 270,
+ newCustomers: 4,
+ totalCustomers: 100,
+ },
+ {
+ productType: "鏉挎潗",
+ salesArea: "鍗庡寳",
+ period: "2026-01",
+ salesVolume: 500,
+ salesAmount: 150,
+ newCustomers: 2,
+ totalCustomers: 70,
+ },
+ {
+ productType: "鍨嬫潗",
+ salesArea: "鍗庝笢",
+ period: "2026-01",
+ salesVolume: 400,
+ salesAmount: 200,
+ newCustomers: 3,
+ totalCustomers: 50,
+ },
+ // 2026骞�2鏈堟暟鎹�
+ {
+ productType: "鐮屽潡",
+ salesArea: "鍗庝笢",
+ period: "2026-02",
+ salesVolume: 1300,
+ salesAmount: 195,
+ newCustomers: 4,
+ totalCustomers: 124,
+ },
+ {
+ productType: "鐮屽潡",
+ salesArea: "鍗庡寳",
+ period: "2026-02",
+ salesVolume: 850,
+ salesAmount: 127.5,
+ newCustomers: 2,
+ totalCustomers: 82,
+ },
+ {
+ productType: "鐮屽潡",
+ salesArea: "鍗庡崡",
+ period: "2026-02",
+ salesVolume: 650,
+ salesAmount: 97.5,
+ newCustomers: 1,
+ totalCustomers: 61,
+ },
+ {
+ productType: "鏉挎潗",
+ salesArea: "鍗庝笢",
+ period: "2026-02",
+ salesVolume: 950,
+ salesAmount: 285,
+ newCustomers: 3,
+ totalCustomers: 103,
+ },
+ {
+ productType: "鏉挎潗",
+ salesArea: "鍗庡寳",
+ period: "2026-02",
+ salesVolume: 550,
+ salesAmount: 165,
+ newCustomers: 1,
+ totalCustomers: 71,
+ },
+ {
+ productType: "鍨嬫潗",
+ salesArea: "鍗庝笢",
+ period: "2026-02",
+ salesVolume: 450,
+ salesAmount: 225,
+ newCustomers: 2,
+ totalCustomers: 52,
+ },
+ // 2026骞�3鏈堟暟鎹�
+ {
+ productType: "鐮屽潡",
+ salesArea: "鍗庝笢",
+ period: "2026-03",
+ salesVolume: 1400,
+ salesAmount: 210,
+ newCustomers: 6,
+ totalCustomers: 130,
+ },
+ {
+ productType: "鐮屽潡",
+ salesArea: "鍗庡寳",
+ period: "2026-03",
+ salesVolume: 900,
+ salesAmount: 135,
+ newCustomers: 3,
+ totalCustomers: 85,
+ },
+ {
+ productType: "鐮屽潡",
+ salesArea: "鍗庡崡",
+ period: "2026-03",
+ salesVolume: 700,
+ salesAmount: 105,
+ newCustomers: 2,
+ totalCustomers: 63,
+ },
+ {
+ productType: "鏉挎潗",
+ salesArea: "鍗庝笢",
+ period: "2026-03",
+ salesVolume: 1000,
+ salesAmount: 300,
+ newCustomers: 5,
+ totalCustomers: 108,
+ },
+ {
+ productType: "鏉挎潗",
+ salesArea: "鍗庡寳",
+ period: "2026-03",
+ salesVolume: 600,
+ salesAmount: 180,
+ newCustomers: 2,
+ totalCustomers: 73,
+ },
+ {
+ productType: "鍨嬫潗",
+ salesArea: "鍗庝笢",
+ period: "2026-03",
+ salesVolume: 500,
+ salesAmount: 250,
+ newCustomers: 3,
+ totalCustomers: 55,
+ },
+ // 瑗垮崡鍜岃タ鍖楀湴鍖烘暟鎹�
+ {
+ productType: "鐮屽潡",
+ salesArea: "瑗垮崡",
+ period: "2026-03",
+ salesVolume: 500,
+ salesAmount: 75,
+ newCustomers: 2,
+ totalCustomers: 40,
+ },
+ {
+ productType: "鏉挎潗",
+ salesArea: "瑗垮崡",
+ period: "2026-03",
+ salesVolume: 300,
+ salesAmount: 90,
+ newCustomers: 1,
+ totalCustomers: 30,
+ },
+ {
+ productType: "鐮屽潡",
+ salesArea: "瑗垮寳",
+ period: "2026-03",
+ salesVolume: 400,
+ salesAmount: 60,
+ newCustomers: 1,
+ totalCustomers: 35,
+ },
+ {
+ productType: "鏉挎潗",
+ salesArea: "瑗垮寳",
+ period: "2026-03",
+ salesVolume: 200,
+ salesAmount: 60,
+ newCustomers: 1,
+ totalCustomers: 25,
+ },
+ ];
+ // 璁$畻灞炴��
+ const filteredData = computed(() => {
+ let result = [...mockData];
-// 璁$畻灞炴��
-const filteredData = computed(() => {
- let result = [...mockData];
-
- // 鎸変骇鍝佺被鍨嬬瓫閫�
- if (productType.value) {
- result = result.filter(item => {
- const typeMap = { block: '鐮屽潡', board: '鏉挎潗', profile: '鍨嬫潗' };
- return item.productType === typeMap[productType.value];
- });
- }
-
- // 鎸夐攢鍞尯鍩熺瓫閫�
- if (salesArea.value) {
- result = result.filter(item => {
- const areaMap = { east: '鍗庝笢', north: '鍗庡寳', south: '鍗庡崡', southwest: '瑗垮崡', northwest: '瑗垮寳' };
- return item.salesArea === areaMap[salesArea.value];
- });
- }
-
- // 鎸夋椂闂磋寖鍥寸瓫閫�
- if (dateRange.value && dateRange.value.length === 2) {
- const startDate = dayjs(dateRange.value[0]);
- const endDate = dayjs(dateRange.value[1]);
-
- result = result.filter(item => {
- const itemDate = dayjs(item.period);
- return itemDate.isAfter(startDate.subtract(1, 'day')) && itemDate.isBefore(endDate.add(1, 'day'));
- });
- }
-
- return result;
-});
-
-// 鏍稿績鎸囨爣璁$畻
-const totalSalesVolume = computed(() => {
- return filteredData.value.reduce((sum, item) => sum + item.salesVolume, 0);
-});
-
-const totalSalesAmount = computed(() => {
- return filteredData.value.reduce((sum, item) => sum + item.salesAmount, 0).toFixed(2);
-});
-
-const newCustomerCount = computed(() => {
- return filteredData.value.reduce((sum, item) => sum + item.newCustomers, 0);
-});
-
-const totalCustomerCount = computed(() => {
- // 璁$畻姣忎釜鍖哄煙鍜屼骇鍝佺被鍨嬬殑鏈�澶у鎴锋暟
- const customerMap = {};
- filteredData.value.forEach(item => {
- const key = `${item.productType}-${item.salesArea}`;
- if (!customerMap[key] || item.totalCustomers > customerMap[key]) {
- customerMap[key] = item.totalCustomers;
+ // 鎸変骇鍝佺被鍨嬬瓫閫�
+ if (productType.value) {
+ result = result.filter(item => {
+ const typeMap = { block: "鐮屽潡", board: "鏉挎潗", profile: "鍨嬫潗" };
+ return item.productType === typeMap[productType.value];
+ });
}
+
+ // 鎸夐攢鍞尯鍩熺瓫閫�
+ if (salesArea.value) {
+ result = result.filter(item => {
+ const areaMap = {
+ east: "鍗庝笢",
+ north: "鍗庡寳",
+ south: "鍗庡崡",
+ southwest: "瑗垮崡",
+ northwest: "瑗垮寳",
+ };
+ return item.salesArea === areaMap[salesArea.value];
+ });
+ }
+
+ // 鎸夋椂闂磋寖鍥寸瓫閫�
+ if (dateRange.value && dateRange.value.length === 2) {
+ const startDate = dayjs(dateRange.value[0]);
+ const endDate = dayjs(dateRange.value[1]);
+
+ result = result.filter(item => {
+ const itemDate = dayjs(item.period);
+ return (
+ itemDate.isAfter(startDate.subtract(1, "day")) &&
+ itemDate.isBefore(endDate.add(1, "day"))
+ );
+ });
+ }
+
+ return result;
});
- return Object.values(customerMap).reduce((sum, count) => sum + count, 0);
-});
-// 鍙樺寲鐜囪绠楋紙妯℃嫙锛�
-const salesVolumeChange = ref('+5.2');
-const salesAmountChange = ref('+7.8');
-const customerCountChange = ref('+3.5');
-const totalCustomerChange = ref('+2.1');
+ // 鏍稿績鎸囨爣璁$畻
+ const totalSalesVolume = computed(() => {
+ return filteredData.value.reduce((sum, item) => sum + item.salesVolume, 0);
+ });
-// 琛ㄦ牸鏁版嵁
-const tableData = computed(() => {
- return filteredData.value.map(item => {
- // 璁$畻绱鍊硷紙妯℃嫙锛�
- const cumulativeSalesVolume = item.salesVolume * 1.5;
- const cumulativeSalesAmount = item.salesAmount * 1.5;
- const cumulativeNewCustomers = item.newCustomers * 2;
-
+ const totalSalesAmount = computed(() => {
+ return filteredData.value
+ .reduce((sum, item) => sum + item.salesAmount, 0)
+ .toFixed(2);
+ });
+
+ const newCustomerCount = computed(() => {
+ return filteredData.value.reduce((sum, item) => sum + item.newCustomers, 0);
+ });
+
+ const totalCustomerCount = computed(() => {
+ // 璁$畻姣忎釜鍖哄煙鍜屼骇鍝佺被鍨嬬殑鏈�澶у鎴锋暟
+ const customerMap = {};
+ filteredData.value.forEach(item => {
+ const key = `${item.productType}-${item.salesArea}`;
+ if (!customerMap[key] || item.totalCustomers > customerMap[key]) {
+ customerMap[key] = item.totalCustomers;
+ }
+ });
+ return Object.values(customerMap).reduce((sum, count) => sum + count, 0);
+ });
+
+ // 鍙樺寲鐜囪绠楋紙妯℃嫙锛�
+ const salesVolumeChange = ref("+5.2");
+ const salesAmountChange = ref("+7.8");
+ const customerCountChange = ref("+3.5");
+ const totalCustomerChange = ref("+2.1");
+
+ // 琛ㄦ牸鏁版嵁
+ const tableData = computed(() => {
+ return filteredData.value.map(item => {
+ // 璁$畻绱鍊硷紙妯℃嫙锛�
+ const cumulativeSalesVolume = item.salesVolume * 1.5;
+ const cumulativeSalesAmount = item.salesAmount * 1.5;
+ const cumulativeNewCustomers = item.newCustomers * 2;
+
+ return {
+ ...item,
+ cumulativeSalesVolume,
+ cumulativeSalesAmount,
+ cumulativeNewCustomers,
+ };
+ });
+ });
+
+ // 閿�閲忚秼鍔垮浘琛ㄩ厤缃�
+ const salesVolumeChartOption = computed(() => {
+ // 鎸夊懆鏈熷垎缁�
+ const periodMap = {};
+ filteredData.value.forEach(item => {
+ if (!periodMap[item.period]) {
+ periodMap[item.period] = 0;
+ }
+ periodMap[item.period] += item.salesVolume;
+ });
+
+ const periods = Object.keys(periodMap).sort();
+ const values = periods.map(period => periodMap[period]);
+
return {
- ...item,
- cumulativeSalesVolume,
- cumulativeSalesAmount,
- cumulativeNewCustomers
+ tooltip: {
+ trigger: "axis",
+ formatter: "{b}: {c} 绔嬫柟绫�",
+ },
+ xAxis: {
+ type: "category",
+ data: periods,
+ },
+ yAxis: {
+ type: "value",
+ name: "閿�閲忥紙绔嬫柟绫筹級",
+ },
+ series: [
+ {
+ data: values,
+ type: "line",
+ smooth: true,
+ lineStyle: {
+ width: 3,
+ },
+ itemStyle: {
+ color: "#409EFF",
+ },
+ },
+ ],
};
});
-});
-// 閿�閲忚秼鍔垮浘琛ㄩ厤缃�
-const salesVolumeChartOption = computed(() => {
- // 鎸夊懆鏈熷垎缁�
- const periodMap = {};
- filteredData.value.forEach(item => {
- if (!periodMap[item.period]) {
- periodMap[item.period] = 0;
- }
- periodMap[item.period] += item.salesVolume;
- });
-
- const periods = Object.keys(periodMap).sort();
- const values = periods.map(period => periodMap[period]);
-
- return {
- tooltip: {
- trigger: 'axis',
- formatter: '{b}: {c} 绔嬫柟绫�'
- },
- xAxis: {
- type: 'category',
- data: periods
- },
- yAxis: {
- type: 'value',
- name: '閿�閲忥紙绔嬫柟绫筹級'
- },
- series: [{
- data: values,
- type: 'line',
- smooth: true,
- lineStyle: {
- width: 3
+ // 閿�鍞噾棰濊秼鍔垮浘琛ㄩ厤缃�
+ const salesAmountChartOption = computed(() => {
+ // 鎸夊懆鏈熷垎缁�
+ const periodMap = {};
+ filteredData.value.forEach(item => {
+ if (!periodMap[item.period]) {
+ periodMap[item.period] = 0;
+ }
+ periodMap[item.period] += item.salesAmount;
+ });
+
+ const periods = Object.keys(periodMap).sort();
+ const values = periods.map(period => periodMap[period]);
+
+ return {
+ tooltip: {
+ trigger: "axis",
+ formatter: "{b}: {c} 涓囧厓",
},
- itemStyle: {
- color: '#409EFF'
- }
- }]
- };
-});
-
-// 閿�鍞噾棰濊秼鍔垮浘琛ㄩ厤缃�
-const salesAmountChartOption = computed(() => {
- // 鎸夊懆鏈熷垎缁�
- const periodMap = {};
- filteredData.value.forEach(item => {
- if (!periodMap[item.period]) {
- periodMap[item.period] = 0;
- }
- periodMap[item.period] += item.salesAmount;
- });
-
- const periods = Object.keys(periodMap).sort();
- const values = periods.map(period => periodMap[period]);
-
- return {
- tooltip: {
- trigger: 'axis',
- formatter: '{b}: {c} 涓囧厓'
- },
- xAxis: {
- type: 'category',
- data: periods
- },
- yAxis: {
- type: 'value',
- name: '閿�鍞噾棰濓紙涓囧厓锛�'
- },
- series: [{
- data: values,
- type: 'bar',
- itemStyle: {
- color: '#67C23A'
- }
- }]
- };
-});
-
-// 浜у搧绫诲瀷鍒嗗竷鍥捐〃閰嶇疆
-const productTypeChartOption = computed(() => {
- // 鎸変骇鍝佺被鍨嬪垎缁�
- const typeMap = {};
- filteredData.value.forEach(item => {
- if (!typeMap[item.productType]) {
- typeMap[item.productType] = 0;
- }
- typeMap[item.productType] += item.salesVolume;
- });
-
- const types = Object.keys(typeMap);
- const values = types.map(type => typeMap[type]);
-
- return {
- tooltip: {
- trigger: 'item',
- formatter: '{b}: {c} 绔嬫柟绫� ({d}%)'
- },
- series: [{
- type: 'pie',
- radius: '60%',
- data: types.map((type, index) => ({
- name: type,
- value: values[index]
- })),
- emphasis: {
- itemStyle: {
- shadowBlur: 10,
- shadowOffsetX: 0,
- shadowColor: 'rgba(0, 0, 0, 0.5)'
- }
- }
- }]
- };
-});
-
-// 閿�鍞尯鍩熷垎甯冨浘琛ㄩ厤缃�
-const salesAreaChartOption = computed(() => {
- // 鎸夐攢鍞尯鍩熷垎缁�
- const areaMap = {};
- filteredData.value.forEach(item => {
- if (!areaMap[item.salesArea]) {
- areaMap[item.salesArea] = 0;
- }
- areaMap[item.salesArea] += item.salesVolume;
- });
-
- const areas = Object.keys(areaMap);
- const values = areas.map(area => areaMap[area]);
-
- return {
- tooltip: {
- trigger: 'item',
- formatter: '{b}: {c} 绔嬫柟绫� ({d}%)'
- },
- series: [{
- type: 'pie',
- radius: '60%',
- data: areas.map((area, index) => ({
- name: area,
- value: values[index]
- })),
- emphasis: {
- itemStyle: {
- shadowBlur: 10,
- shadowOffsetX: 0,
- shadowColor: 'rgba(0, 0, 0, 0.5)'
- }
- }
- }]
- };
-});
-
-// 绱閿�閲忚秼鍔垮浘琛ㄩ厤缃�
-const cumulativeSalesVolumeChartOption = computed(() => {
- // 鎸夊懆鏈熷垎缁�
- const periodMap = {};
- let cumulativeValue = 0;
-
- // 鎸夊懆鏈熸帓搴�
- const sortedData = [...filteredData.value].sort((a, b) => a.period.localeCompare(b.period));
-
- sortedData.forEach(item => {
- cumulativeValue += item.salesVolume;
- periodMap[item.period] = cumulativeValue;
- });
-
- const periods = Object.keys(periodMap).sort();
- const values = periods.map(period => periodMap[period]);
-
- return {
- tooltip: {
- trigger: 'axis',
- formatter: '{b}: {c} 绔嬫柟绫�'
- },
- xAxis: {
- type: 'category',
- data: periods
- },
- yAxis: {
- type: 'value',
- name: '绱閿�閲忥紙绔嬫柟绫筹級'
- },
- series: [{
- data: values,
- type: 'line',
- smooth: true,
- areaStyle: {
- opacity: 0.3
+ xAxis: {
+ type: "category",
+ data: periods,
},
- itemStyle: {
- color: '#E6A23C'
+ yAxis: {
+ type: "value",
+ name: "閿�鍞噾棰濓紙涓囧厓锛�",
},
- lineStyle: {
- width: 3
- }
- }]
- };
-});
-
-// 绱閿�鍞噾棰濊秼鍔垮浘琛ㄩ厤缃�
-const cumulativeSalesAmountChartOption = computed(() => {
- // 鎸夊懆鏈熷垎缁�
- const periodMap = {};
- let cumulativeValue = 0;
-
- // 鎸夊懆鏈熸帓搴�
- const sortedData = [...filteredData.value].sort((a, b) => a.period.localeCompare(b.period));
-
- sortedData.forEach(item => {
- cumulativeValue += item.salesAmount;
- periodMap[item.period] = cumulativeValue;
+ series: [
+ {
+ data: values,
+ type: "bar",
+ itemStyle: {
+ color: "#67C23A",
+ },
+ },
+ ],
+ };
});
-
- const periods = Object.keys(periodMap).sort();
- const values = periods.map(period => periodMap[period]);
-
- return {
- tooltip: {
- trigger: 'axis',
- formatter: '{b}: {c} 涓囧厓'
- },
- xAxis: {
- type: 'category',
- data: periods
- },
- yAxis: {
- type: 'value',
- name: '绱閿�鍞噾棰濓紙涓囧厓锛�'
- },
- series: [{
- data: values,
- type: 'bar',
- itemStyle: {
- color: '#F56C6C'
+
+ // 浜у搧绫诲瀷鍒嗗竷鍥捐〃閰嶇疆
+ const productTypeChartOption = computed(() => {
+ // 鎸変骇鍝佺被鍨嬪垎缁�
+ const typeMap = {};
+ filteredData.value.forEach(item => {
+ if (!typeMap[item.productType]) {
+ typeMap[item.productType] = 0;
}
- }]
- };
-});
+ typeMap[item.productType] += item.salesVolume;
+ });
-// 鏂规硶
-const goBack = () => {
- router.back();
-};
+ const types = Object.keys(typeMap);
+ const values = types.map(type => typeMap[type]);
-const handleDateChange = () => {
- // 澶勭悊鏃ユ湡鍙樺寲
- updateCharts();
-};
-
-const handleFilterChange = () => {
- // 澶勭悊绛涢�夋潯浠跺彉鍖�
- updateCharts();
-};
-
-// 鍒濆鍖栧浘琛�
-const initCharts = () => {
- // 鍒濆鍖栭攢閲忚秼鍔垮浘琛�
- if (salesVolumeChart.value && !salesVolumeChartInstance) {
- salesVolumeChartInstance = echarts.init(salesVolumeChart.value);
- }
-
- // 鍒濆鍖栭攢鍞噾棰濊秼鍔垮浘琛�
- if (salesAmountChart.value && !salesAmountChartInstance) {
- salesAmountChartInstance = echarts.init(salesAmountChart.value);
- }
-
- // 鍒濆鍖栦骇鍝佺被鍨嬪垎甯冨浘琛�
- if (productTypeChart.value && !productTypeChartInstance) {
- productTypeChartInstance = echarts.init(productTypeChart.value);
- }
-
- // 鍒濆鍖栭攢鍞尯鍩熷垎甯冨浘琛�
- if (salesAreaChart.value && !salesAreaChartInstance) {
- salesAreaChartInstance = echarts.init(salesAreaChart.value);
- }
-
- // 鍒濆鍖栫疮璁¢攢閲忚秼鍔垮浘琛�
- if (cumulativeSalesVolumeChart.value && !cumulativeSalesVolumeChartInstance) {
- cumulativeSalesVolumeChartInstance = echarts.init(cumulativeSalesVolumeChart.value);
- }
-
- // 鍒濆鍖栫疮璁¢攢鍞噾棰濊秼鍔垮浘琛�
- if (cumulativeSalesAmountChart.value && !cumulativeSalesAmountChartInstance) {
- cumulativeSalesAmountChartInstance = echarts.init(cumulativeSalesAmountChart.value);
- }
-
- updateCharts();
-};
-
-// 鏇存柊鍥捐〃
-const updateCharts = () => {
- // 鏇存柊閿�閲忚秼鍔垮浘琛�
- if (salesVolumeChartInstance) {
- salesVolumeChartInstance.setOption(salesVolumeChartOption.value);
- }
-
- // 鏇存柊閿�鍞噾棰濊秼鍔垮浘琛�
- if (salesAmountChartInstance) {
- salesAmountChartInstance.setOption(salesAmountChartOption.value);
- }
-
- // 鏇存柊浜у搧绫诲瀷鍒嗗竷鍥捐〃
- if (productTypeChartInstance) {
- productTypeChartInstance.setOption(productTypeChartOption.value);
- }
-
- // 鏇存柊閿�鍞尯鍩熷垎甯冨浘琛�
- if (salesAreaChartInstance) {
- salesAreaChartInstance.setOption(salesAreaChartOption.value);
- }
-
- // 鏇存柊绱閿�閲忚秼鍔垮浘琛�
- if (cumulativeSalesVolumeChartInstance) {
- cumulativeSalesVolumeChartInstance.setOption(cumulativeSalesVolumeChartOption.value);
- }
-
- // 鏇存柊绱閿�鍞噾棰濊秼鍔垮浘琛�
- if (cumulativeSalesAmountChartInstance) {
- cumulativeSalesAmountChartInstance.setOption(cumulativeSalesAmountChartOption.value);
- }
-};
-
-// 鐩戝惉绐楀彛澶у皬鍙樺寲
-const handleResize = () => {
- if (salesVolumeChartInstance) {
- salesVolumeChartInstance.resize();
- }
- if (salesAmountChartInstance) {
- salesAmountChartInstance.resize();
- }
- if (productTypeChartInstance) {
- productTypeChartInstance.resize();
- }
- if (salesAreaChartInstance) {
- salesAreaChartInstance.resize();
- }
- if (cumulativeSalesVolumeChartInstance) {
- cumulativeSalesVolumeChartInstance.resize();
- }
- if (cumulativeSalesAmountChartInstance) {
- cumulativeSalesAmountChartInstance.resize();
- }
-};
-
-// 鐢熷懡鍛ㄦ湡
-onMounted(() => {
- // 璁剧疆榛樿鏃ユ湡鑼冨洿涓烘渶杩�3涓湀
- const endDate = dayjs();
- const startDate = endDate.subtract(3, 'month');
- dateRange.value = [startDate.format('YYYY-MM-DD'), endDate.format('YYYY-MM-DD')];
-
- // 绛夊緟DOM鏇存柊鍚庡垵濮嬪寲鍥捐〃
- nextTick(() => {
- initCharts();
+ return {
+ tooltip: {
+ trigger: "item",
+ formatter: "{b}: {c} 绔嬫柟绫� ({d}%)",
+ },
+ series: [
+ {
+ type: "pie",
+ radius: "60%",
+ data: types.map((type, index) => ({
+ name: type,
+ value: values[index],
+ })),
+ emphasis: {
+ itemStyle: {
+ shadowBlur: 10,
+ shadowOffsetX: 0,
+ shadowColor: "rgba(0, 0, 0, 0.5)",
+ },
+ },
+ },
+ ],
+ };
});
-
- // 娣诲姞绐楀彛澶у皬鍙樺寲鐩戝惉
- window.addEventListener('resize', handleResize);
-});
-// 缁勪欢鍗歌浇鏃堕攢姣佸浘琛ㄥ疄渚�
-onBeforeUnmount(() => {
- if (salesVolumeChartInstance) {
- salesVolumeChartInstance.dispose();
- }
- if (salesAmountChartInstance) {
- salesAmountChartInstance.dispose();
- }
- if (productTypeChartInstance) {
- productTypeChartInstance.dispose();
- }
- if (salesAreaChartInstance) {
- salesAreaChartInstance.dispose();
- }
- if (cumulativeSalesVolumeChartInstance) {
- cumulativeSalesVolumeChartInstance.dispose();
- }
- if (cumulativeSalesAmountChartInstance) {
- cumulativeSalesAmountChartInstance.dispose();
- }
-
- // 绉婚櫎绐楀彛澶у皬鍙樺寲鐩戝惉
- window.removeEventListener('resize', handleResize);
-});
+ // 閿�鍞尯鍩熷垎甯冨浘琛ㄩ厤缃�
+ const salesAreaChartOption = computed(() => {
+ // 鎸夐攢鍞尯鍩熷垎缁�
+ const areaMap = {};
+ filteredData.value.forEach(item => {
+ if (!areaMap[item.salesArea]) {
+ areaMap[item.salesArea] = 0;
+ }
+ areaMap[item.salesArea] += item.salesVolume;
+ });
+
+ const areas = Object.keys(areaMap);
+ const values = areas.map(area => areaMap[area]);
+
+ return {
+ tooltip: {
+ trigger: "item",
+ formatter: "{b}: {c} 绔嬫柟绫� ({d}%)",
+ },
+ series: [
+ {
+ type: "pie",
+ radius: "60%",
+ data: areas.map((area, index) => ({
+ name: area,
+ value: values[index],
+ })),
+ emphasis: {
+ itemStyle: {
+ shadowBlur: 10,
+ shadowOffsetX: 0,
+ shadowColor: "rgba(0, 0, 0, 0.5)",
+ },
+ },
+ },
+ ],
+ };
+ });
+
+ // 绱閿�閲忚秼鍔垮浘琛ㄩ厤缃�
+ const cumulativeSalesVolumeChartOption = computed(() => {
+ // 鎸夊懆鏈熷垎缁�
+ const periodMap = {};
+ let cumulativeValue = 0;
+
+ // 鎸夊懆鏈熸帓搴�
+ const sortedData = [...filteredData.value].sort((a, b) =>
+ a.period.localeCompare(b.period)
+ );
+
+ sortedData.forEach(item => {
+ cumulativeValue += item.salesVolume;
+ periodMap[item.period] = cumulativeValue;
+ });
+
+ const periods = Object.keys(periodMap).sort();
+ const values = periods.map(period => periodMap[period]);
+
+ return {
+ tooltip: {
+ trigger: "axis",
+ formatter: "{b}: {c} 绔嬫柟绫�",
+ },
+ xAxis: {
+ type: "category",
+ data: periods,
+ },
+ yAxis: {
+ type: "value",
+ name: "绱閿�閲忥紙绔嬫柟绫筹級",
+ },
+ series: [
+ {
+ data: values,
+ type: "line",
+ smooth: true,
+ areaStyle: {
+ opacity: 0.3,
+ },
+ itemStyle: {
+ color: "#E6A23C",
+ },
+ lineStyle: {
+ width: 3,
+ },
+ },
+ ],
+ };
+ });
+
+ // 绱閿�鍞噾棰濊秼鍔垮浘琛ㄩ厤缃�
+ const cumulativeSalesAmountChartOption = computed(() => {
+ // 鎸夊懆鏈熷垎缁�
+ const periodMap = {};
+ let cumulativeValue = 0;
+
+ // 鎸夊懆鏈熸帓搴�
+ const sortedData = [...filteredData.value].sort((a, b) =>
+ a.period.localeCompare(b.period)
+ );
+
+ sortedData.forEach(item => {
+ cumulativeValue += item.salesAmount;
+ periodMap[item.period] = cumulativeValue;
+ });
+
+ const periods = Object.keys(periodMap).sort();
+ const values = periods.map(period => periodMap[period]);
+
+ return {
+ tooltip: {
+ trigger: "axis",
+ formatter: "{b}: {c} 涓囧厓",
+ },
+ xAxis: {
+ type: "category",
+ data: periods,
+ },
+ yAxis: {
+ type: "value",
+ name: "绱閿�鍞噾棰濓紙涓囧厓锛�",
+ },
+ series: [
+ {
+ data: values,
+ type: "bar",
+ itemStyle: {
+ color: "#F56C6C",
+ },
+ },
+ ],
+ };
+ });
+
+ // 鏂规硶
+ const goBack = () => {
+ router.back();
+ };
+
+ const handleDateChange = () => {
+ // 澶勭悊鏃ユ湡鍙樺寲
+ updateCharts();
+ };
+
+ const handleFilterChange = () => {
+ // 澶勭悊绛涢�夋潯浠跺彉鍖�
+ updateCharts();
+ };
+
+ // 鍒濆鍖栧浘琛�
+ const initCharts = () => {
+ // 鍒濆鍖栭攢閲忚秼鍔垮浘琛�
+ if (salesVolumeChart.value && !salesVolumeChartInstance) {
+ salesVolumeChartInstance = echarts.init(salesVolumeChart.value);
+ }
+
+ // 鍒濆鍖栭攢鍞噾棰濊秼鍔垮浘琛�
+ if (salesAmountChart.value && !salesAmountChartInstance) {
+ salesAmountChartInstance = echarts.init(salesAmountChart.value);
+ }
+
+ // 鍒濆鍖栦骇鍝佺被鍨嬪垎甯冨浘琛�
+ if (productTypeChart.value && !productTypeChartInstance) {
+ productTypeChartInstance = echarts.init(productTypeChart.value);
+ }
+
+ // 鍒濆鍖栭攢鍞尯鍩熷垎甯冨浘琛�
+ if (salesAreaChart.value && !salesAreaChartInstance) {
+ salesAreaChartInstance = echarts.init(salesAreaChart.value);
+ }
+
+ // 鍒濆鍖栫疮璁¢攢閲忚秼鍔垮浘琛�
+ if (cumulativeSalesVolumeChart.value && !cumulativeSalesVolumeChartInstance) {
+ cumulativeSalesVolumeChartInstance = echarts.init(
+ cumulativeSalesVolumeChart.value
+ );
+ }
+
+ // 鍒濆鍖栫疮璁¢攢鍞噾棰濊秼鍔垮浘琛�
+ if (cumulativeSalesAmountChart.value && !cumulativeSalesAmountChartInstance) {
+ cumulativeSalesAmountChartInstance = echarts.init(
+ cumulativeSalesAmountChart.value
+ );
+ }
+
+ updateCharts();
+ };
+
+ // 鏇存柊鍥捐〃
+ const updateCharts = () => {
+ // 鏇存柊閿�閲忚秼鍔垮浘琛�
+ if (salesVolumeChartInstance) {
+ salesVolumeChartInstance.setOption(salesVolumeChartOption.value);
+ }
+
+ // 鏇存柊閿�鍞噾棰濊秼鍔垮浘琛�
+ if (salesAmountChartInstance) {
+ salesAmountChartInstance.setOption(salesAmountChartOption.value);
+ }
+
+ // 鏇存柊浜у搧绫诲瀷鍒嗗竷鍥捐〃
+ if (productTypeChartInstance) {
+ productTypeChartInstance.setOption(productTypeChartOption.value);
+ }
+
+ // 鏇存柊閿�鍞尯鍩熷垎甯冨浘琛�
+ if (salesAreaChartInstance) {
+ salesAreaChartInstance.setOption(salesAreaChartOption.value);
+ }
+
+ // 鏇存柊绱閿�閲忚秼鍔垮浘琛�
+ if (cumulativeSalesVolumeChartInstance) {
+ cumulativeSalesVolumeChartInstance.setOption(
+ cumulativeSalesVolumeChartOption.value
+ );
+ }
+
+ // 鏇存柊绱閿�鍞噾棰濊秼鍔垮浘琛�
+ if (cumulativeSalesAmountChartInstance) {
+ cumulativeSalesAmountChartInstance.setOption(
+ cumulativeSalesAmountChartOption.value
+ );
+ }
+ };
+
+ // 鐩戝惉绐楀彛澶у皬鍙樺寲
+ const handleResize = () => {
+ if (salesVolumeChartInstance) {
+ salesVolumeChartInstance.resize();
+ }
+ if (salesAmountChartInstance) {
+ salesAmountChartInstance.resize();
+ }
+ if (productTypeChartInstance) {
+ productTypeChartInstance.resize();
+ }
+ if (salesAreaChartInstance) {
+ salesAreaChartInstance.resize();
+ }
+ if (cumulativeSalesVolumeChartInstance) {
+ cumulativeSalesVolumeChartInstance.resize();
+ }
+ if (cumulativeSalesAmountChartInstance) {
+ cumulativeSalesAmountChartInstance.resize();
+ }
+ };
+
+ // 鐢熷懡鍛ㄦ湡
+ onMounted(() => {
+ // 璁剧疆榛樿鏃ユ湡鑼冨洿涓烘渶杩�3涓湀
+ const endDate = dayjs();
+ const startDate = endDate.subtract(3, "month");
+ dateRange.value = [
+ startDate.format("YYYY-MM-DD"),
+ endDate.format("YYYY-MM-DD"),
+ ];
+
+ // 绛夊緟DOM鏇存柊鍚庡垵濮嬪寲鍥捐〃
+ nextTick(() => {
+ initCharts();
+ });
+
+ // 娣诲姞绐楀彛澶у皬鍙樺寲鐩戝惉
+ window.addEventListener("resize", handleResize);
+ });
+
+ // 鑾峰彇浜у搧绫诲瀷鏍囩绫诲瀷
+ const getProductTypeType = type => {
+ const typeMap = {
+ 鐮屽潡: "primary",
+ 鏉挎潗: "success",
+ 鍨嬫潗: "warning",
+ };
+ return typeMap[type] || "info";
+ };
+
+ // 鑾峰彇閿�鍞尯鍩熸爣绛剧被鍨�
+ const getSalesAreaType = area => {
+ const typeMap = {
+ 鍗庝笢: "primary",
+ 鍗庡寳: "success",
+ 鍗庡崡: "warning",
+ 瑗垮崡: "danger",
+ 瑗垮寳: "info",
+ };
+ return typeMap[area] || "info";
+ };
+
+ // 缁勪欢鍗歌浇鏃堕攢姣佸浘琛ㄥ疄渚�
+ onBeforeUnmount(() => {
+ if (salesVolumeChartInstance) {
+ salesVolumeChartInstance.dispose();
+ }
+ if (salesAmountChartInstance) {
+ salesAmountChartInstance.dispose();
+ }
+ if (productTypeChartInstance) {
+ productTypeChartInstance.dispose();
+ }
+ if (salesAreaChartInstance) {
+ salesAreaChartInstance.dispose();
+ }
+ if (cumulativeSalesVolumeChartInstance) {
+ cumulativeSalesVolumeChartInstance.dispose();
+ }
+ if (cumulativeSalesAmountChartInstance) {
+ cumulativeSalesAmountChartInstance.dispose();
+ }
+
+ // 绉婚櫎绐楀彛澶у皬鍙樺寲鐩戝惉
+ window.removeEventListener("resize", handleResize);
+ });
</script>
<style scoped>
-/* 澶栭儴瀹瑰櫒 - 鍗犳嵁鏁翠釜瑙嗗彛 */
-.sales-statistics-container {
- position: relative;
- width: 100%;
- /* 椤甸潰鍦ㄥ父瑙勫竷灞�涓嬶紙鏈夐《鏍忥級榛樿鍑忓幓 84px锛岄伩鍏嶅唴瀹硅瑁佸垏 */
- min-height: calc(100vh - 84px);
- background-color: #f5f7fa;
- overflow: hidden;
-}
+ /* 澶栭儴瀹瑰櫒 - 鍗犳嵁鏁翠釜瑙嗗彛 */
+ .sales-statistics-container {
+ position: relative;
+ width: 100%;
+ /* 椤甸潰鍦ㄥ父瑙勫竷灞�涓嬶紙鏈夐《鏍忥級榛樿鍑忓幓 84px锛岄伩鍏嶅唴瀹硅瑁佸垏 */
+ min-height: calc(100vh - 84px);
+ background-color: #f5f7fa;
+ overflow: hidden;
+ }
-/* 鍐呴儴鍐呭鍖哄煙 - 鑷�傚簲瀹藉害 */
-.data-dashboard {
- position: relative;
- width: 100%;
- min-height: 100%;
- background-color: #ffffff;
- box-shadow: 0 0 20px rgba(0, 0, 0, 0.1);
-}
+ /* 鍐呴儴鍐呭鍖哄煙 - 鑷�傚簲瀹藉害 */
+ .data-dashboard {
+ position: relative;
+ width: 100%;
+ min-height: 100%;
+ background-color: #ffffff;
+ box-shadow: 0 0 20px rgba(0, 0, 0, 0.1);
+ }
-.filter-area {
- padding: 20px;
- background-color: #ffffff;
- border-bottom: 1px solid #e4e7ed;
- display: flex;
- gap: 40px;
- align-items: center;
- flex-wrap: wrap;
-}
+ .filter-area {
+ padding: 20px;
+ background-color: #ffffff;
+ border-bottom: 1px solid #e4e7ed;
+ display: flex;
+ gap: 40px;
+ align-items: center;
+ flex-wrap: wrap;
+ }
-.filter-section {
- display: flex;
- align-items: center;
- gap: 10px;
-}
+ .filter-section {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ }
-.filter-label {
- font-size: 14px;
- font-weight: 500;
- color: #303133;
- white-space: nowrap;
-}
+ .filter-label {
+ font-size: 14px;
+ font-weight: 500;
+ color: #303133;
+ white-space: nowrap;
+ }
-.dashboard-content {
- position: relative;
- z-index: 1;
- display: flex;
- flex-direction: column;
- gap: 20px;
- padding: 20px;
- min-height: 800px;
- overflow: hidden;
-}
+ .dashboard-content {
+ position: relative;
+ z-index: 1;
+ display: flex;
+ flex-direction: column;
+ gap: 20px;
+ padding: 20px;
+ min-height: 800px;
+ overflow: hidden;
+ }
-/* 琛屽竷灞� */
-.row {
- display: flex;
- gap: 20px;
- align-items: stretch;
-}
+ /* 琛屽竷灞� */
+ .row {
+ display: flex;
+ gap: 20px;
+ align-items: stretch;
+ }
-/* 绗竴琛岋細4涓寚鏍囧崱鐗� */
-.row-1 {
- height: 180px;
-}
+ /* 绗竴琛岋細4涓寚鏍囧崱鐗� */
+ .row-1 {
+ height: 180px;
+ }
-/* 绗簩琛岋細2涓秼鍔垮浘琛� */
-.row-2 {
- height: 350px;
-}
+ /* 绗簩琛岋細2涓秼鍔垮浘琛� */
+ .row-2 {
+ height: 350px;
+ }
-/* 绗笁琛岋細绱鏁版嵁瓒嬪娍 */
-.row-3 {
- height: 350px;
-}
+ /* 绗笁琛岋細绱鏁版嵁瓒嬪娍 */
+ .row-3 {
+ height: 350px;
+ }
-/* 绗洓琛岋細琛ㄦ牸鍜屽浘琛� */
-.row-4 {
- height: 600px;
-}
+ /* 绗洓琛岋細琛ㄦ牸鍜屽浘琛� */
+ .row-4 {
+ height: 600px;
+ }
-/* 鍗$墖鏍峰紡 */
-.panel-card {
- background-color: #ffffff;
- border-radius: 8px;
- border: 1px solid #e4e7ed;
- overflow: hidden;
- display: flex;
- flex-direction: column;
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
- transition: all 0.3s ease;
-}
+ /* 鍗$墖鏍峰紡 */
+ .panel-card {
+ background-color: #ffffff;
+ border-radius: 8px;
+ border: 1px solid #e4e7ed;
+ overflow: hidden;
+ display: flex;
+ flex-direction: column;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
+ transition: all 0.3s ease;
+ }
-.panel-card:hover {
- box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
- transform: translateY(-2px);
-}
+ .panel-card:hover {
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
+ transform: translateY(-2px);
+ }
-/* 鍗$墖甯冨眬 */
-.card-1 {
- flex: 1;
-}
+ /* 鍗$墖甯冨眬 */
+ .card-1 {
+ flex: 1;
+ }
-.card-2 {
- flex: 1;
-}
+ .card-2 {
+ flex: 1;
+ }
-.card-3 {
- flex: 1;
-}
+ .card-3 {
+ flex: 1;
+ }
-.card-4 {
- flex: 1;
-}
+ .card-4 {
+ flex: 1;
+ }
-.card-5 {
- flex: 1;
-}
+ .card-5 {
+ flex: 1;
+ }
-.card-6 {
- flex: 1;
-}
+ .card-6 {
+ flex: 1;
+ }
-.card-7 {
- flex: 1;
-}
+ .card-7 {
+ flex: 1;
+ }
-.card-8 {
- flex: 1;
-}
+ .card-8 {
+ flex: 1;
+ }
-.card-9 {
- flex: 1;
-}
+ .card-9 {
+ flex: 1;
+ }
-.card-10 {
- flex: 1;
-}
+ .card-10 {
+ flex: 1;
+ }
-.card-11 {
- flex: 1;
-}
+ .card-11 {
+ flex: 1;
+ }
-.panel-title {
- padding: 15px 20px;
- font-size: 16px;
- font-weight: 500;
- color: #303133;
- border-bottom: 1px solid #e4e7ed;
- background-color: #fafafa;
-}
+ .panel-title {
+ padding: 15px 20px;
+ font-size: 16px;
+ font-weight: 500;
+ color: #303133;
+ border-bottom: 1px solid #e4e7ed;
+ background-color: #fafafa;
+ }
-.chart-container {
- flex: 1;
- padding: 20px;
-}
+ .card-1 .panel-title {
+ border-left: 4px solid #409eff;
+ }
-.table-container {
- flex: 1;
- padding: 20px;
- overflow: auto;
-}
+ .card-2 .panel-title {
+ border-left: 4px solid #67c23a;
+ }
-.stats-grid {
- flex: 1;
- padding: 15px;
- display: flex;
- align-items: center;
- justify-content: center;
-}
+ .card-3 .panel-title {
+ border-left: 4px solid #e6a23c;
+ }
-.stat-item {
- background-color: #fafafa;
- border-radius: 8px;
- padding: 15px;
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- border: 1px solid #e4e7ed;
- min-height: 80px;
- width: 100%;
-}
+ .card-4 .panel-title {
+ border-left: 4px solid #f56c6c;
+ }
-.stat-value {
- font-size: 24px;
- font-weight: 600;
- color: #303133;
- margin-bottom: 5px;
-}
+ .card-5 .panel-title {
+ border-left: 4px solid #409eff;
+ }
-.stat-unit {
- font-size: 12px;
- color: #909399;
- margin-bottom: 3px;
-}
+ .card-6 .panel-title {
+ border-left: 4px solid #67c23a;
+ }
-.stat-change {
- font-size: 12px;
- color: #67c23a;
-}
+ .card-7 .panel-title {
+ border-left: 4px solid #e6a23c;
+ }
-/* 琛ㄦ牸鏍峰紡 */
-:deep(.el-table) {
- border-radius: 8px;
- overflow: hidden;
-}
+ .card-8 .panel-title {
+ border-left: 4px solid #f56c6c;
+ }
-:deep(.el-table th) {
- background-color: #fafafa;
- font-weight: 500;
-}
+ .card-9 .panel-title {
+ border-left: 4px solid #409eff;
+ }
-:deep(.el-table tr:hover > td) {
- background-color: #ecf5ff;
-}
+ .card-10 .panel-title {
+ border-left: 4px solid #67c23a;
+ }
-/* 涓嬫媺閫夋嫨妗嗘牱寮� */
-:deep(.el-select) {
- width: 100%;
-}
+ .card-11 .panel-title {
+ border-left: 4px solid #e6a23c;
+ }
-:deep(.el-date-picker) {
- width: 100%;
-}
+ .chart-container {
+ flex: 1;
+ padding: 20px;
+ }
+
+ .table-container {
+ flex: 1;
+ padding: 20px;
+ overflow: auto;
+ }
+
+ .stats-grid {
+ flex: 1;
+ padding: 15px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+
+ .stat-item {
+ background-color: #fafafa;
+ border-radius: 8px;
+ padding: 15px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ border: 1px solid #e4e7ed;
+ min-height: 80px;
+ width: 100%;
+ }
+
+ .stat-value {
+ font-size: 24px;
+ font-weight: 600;
+ color: #303133;
+ margin-bottom: 5px;
+ }
+
+ .sales-volume-color {
+ color: #409eff;
+ text-shadow: 0 2px 4px rgba(64, 158, 255, 0.3);
+ }
+
+ .sales-amount-color {
+ color: #67c23a;
+ text-shadow: 0 2px 4px rgba(103, 194, 58, 0.3);
+ }
+
+ .new-customer-color {
+ color: #e6a23c;
+ text-shadow: 0 2px 4px rgba(230, 162, 60, 0.3);
+ }
+
+ .total-customer-color {
+ color: #f56c6c;
+ text-shadow: 0 2px 4px rgba(245, 108, 108, 0.3);
+ }
+
+ .stat-unit {
+ font-size: 12px;
+ color: #909399;
+ margin-bottom: 3px;
+ }
+
+ .stat-change {
+ font-size: 12px;
+ color: #67c23a;
+ }
+
+ /* 琛ㄦ牸鏍峰紡 */
+ :deep(.el-table) {
+ border-radius: 8px;
+ overflow: hidden;
+ }
+
+ :deep(.el-table th) {
+ background-color: #fafafa;
+ font-weight: 500;
+ }
+
+ :deep(.el-table tr:hover > td) {
+ background-color: #ecf5ff;
+ }
+
+ .data-value {
+ font-weight: bold;
+ color: #409eff;
+ }
+
+ /* 涓嬫媺閫夋嫨妗嗘牱寮� */
+ :deep(.el-select) {
+ width: 100%;
+ }
+
+ :deep(.el-date-picker) {
+ width: 100%;
+ }
</style>
\ No newline at end of file
diff --git a/src/views/reportAnalysis/solidWasteConsumption/index1.vue b/src/views/reportAnalysis/solidWasteConsumption/index1.vue
new file mode 100644
index 0000000..6af1d80
--- /dev/null
+++ b/src/views/reportAnalysis/solidWasteConsumption/index1.vue
@@ -0,0 +1,623 @@
+<template>
+ <div class="dashboard-container">
+ <div class="data-dashboard">
+ <!-- 绛涢�夊尯鍩� -->
+ <div class="filter-area">
+ <div class="filter-section">
+ <span class="filter-label">鏃堕棿缁村害锛�</span>
+ <el-radio-group v-model="dateType"
+ @change="handleDateTypeChange"
+ class="radio-group">
+ <el-radio-button label="month">鏈堝害</el-radio-button>
+ <el-radio-button label="year">骞村害</el-radio-button>
+ </el-radio-group>
+ </div>
+ </div>
+ <!-- 涓昏鍐呭鍖哄煙 -->
+ <div class="dashboard-content">
+ <!-- 绗竴琛岋細鏍稿績鎸囨爣 -->
+ <div class="row row-1">
+ <div class="panel-card card-1">
+ <div class="panel-title">鏍稿績鎸囨爣</div>
+ <div class="stats-grid">
+ <div class="stat-item">
+ <div class="stat-label">鍚堣閲�</div>
+ <div class="stat-value">{{ totalSolidWaste }}</div>
+ <div class="stat-unit">鍚�</div>
+ </div>
+ <div class="stat-item">
+ <div class="stat-label">2022骞磋嚦浠婄疮璁℃秷绾抽噺</div>
+ <div class="stat-value">{{ totalSolidWasteSince2022 }}</div>
+ <div class="stat-unit">鍚�</div>
+ </div>
+ </div>
+ </div>
+ </div>
+ <!-- 绗簩琛岋細鍥哄簾娑堢撼瓒嬪娍 -->
+ <div class="row row-2">
+ <div class="panel-card card-2">
+ <div class="panel-title">鍥哄簾娑堢撼瓒嬪娍</div>
+ <div class="chart-container">
+ <div ref="trendChart"
+ style="width: 100%; height: 100%"></div>
+ </div>
+ </div>
+ </div>
+ <!-- 绗笁琛岋細鍥哄簾绫诲瀷鍒嗗竷 -->
+ <div class="row row-3">
+ <div class="panel-card card-3">
+ <div class="panel-title">鍥哄簾绫诲瀷鍒嗗竷</div>
+ <div class="chart-container">
+ <div ref="distributionChart"
+ style="width: 100%; height: 100%"></div>
+ </div>
+ </div>
+ </div>
+ <!-- 绗洓琛岋細娑堢撼閲忔槑缁� -->
+ <div class="row row-4">
+ <div class="panel-card card-4">
+ <div class="panel-title">娑堢撼閲忔槑缁�</div>
+ <div class="table-container">
+ <el-table :data="wasteTableData"
+ style="width: 100%">
+ <el-table-column prop="time"
+ label="鏃堕棿"
+ width="120" />
+ <el-table-column prop="type"
+ label="鍥哄簾绫诲瀷"
+ width="120"
+ align="center">
+ <template #default="scope">
+ <el-tag :type="getWasteTypeType(scope.row.type)">
+ {{ scope.row.type }}
+ </el-tag>
+ </template>
+ </el-table-column>
+ <el-table-column prop="quantity"
+ label="娑堢撼閲�"
+ align="right">
+ <template #default="scope">
+ <span class="data-value">{{ scope.row.quantity }}</span>
+ </template>
+ </el-table-column>
+ <el-table-column prop="unit"
+ label="鍗曚綅"
+ width="80" />
+ <el-table-column prop="source"
+ label="鏉ユ簮" />
+ </el-table>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+</template>
+
+<script setup>
+ import { ref, computed, onMounted, onBeforeUnmount, nextTick } from "vue";
+ import * as echarts from "echarts";
+
+ // 绛涢�夋潯浠�
+ const dateType = ref("month"); // month 鎴� year
+
+ // 鍥捐〃寮曠敤
+ const trendChart = ref(null);
+ const distributionChart = ref(null);
+
+ // 鍥捐〃瀹炰緥
+ let trendChartInstance = null;
+ let distributionChartInstance = null;
+
+ // 妯℃嫙鏁版嵁
+ const solidWasteData = ref({
+ month: [
+ { name: "1鏈�", 绮夌叅鐏�: 200, 鐭宠啅: 150, 鐭崇伆: 100 },
+ { name: "2鏈�", 绮夌叅鐏�: 220, 鐭宠啅: 160, 鐭崇伆: 110 },
+ { name: "3鏈�", 绮夌叅鐏�: 190, 鐭宠啅: 140, 鐭崇伆: 95 },
+ { name: "4鏈�", 绮夌叅鐏�: 230, 鐭宠啅: 170, 鐭崇伆: 115 },
+ { name: "5鏈�", 绮夌叅鐏�: 240, 鐭宠啅: 180, 鐭崇伆: 120 },
+ { name: "6鏈�", 绮夌叅鐏�: 225, 鐭宠啅: 165, 鐭崇伆: 112 },
+ ],
+ year: [
+ { name: "2022", 绮夌叅鐏�: 2300, 鐭宠啅: 1700, 鐭崇伆: 1100 },
+ { name: "2023", 绮夌叅鐏�: 2500, 鐭宠啅: 1800, 鐭崇伆: 1200 },
+ { name: "2024", 绮夌叅鐏�: 2700, 鐭宠啅: 1950, 鐭崇伆: 1300 },
+ { name: "2025", 绮夌叅鐏�: 2900, 鐭宠啅: 2100, 鐭崇伆: 1400 },
+ ],
+ });
+
+ // 璁$畻灞炴��
+ const totalSolidWaste = computed(() => {
+ const data = solidWasteData.value[dateType.value];
+ if (dateType.value === "month") {
+ return data.reduce(
+ (sum, item) => sum + item.绮夌叅鐏� + item.鐭宠啅 + item.鐭崇伆,
+ 0
+ );
+ } else {
+ const lastItem = data[data.length - 1];
+ return lastItem.绮夌叅鐏� + lastItem.鐭宠啅 + lastItem.鐭崇伆;
+ }
+ });
+
+ const totalSolidWasteSince2022 = computed(() => {
+ const data = solidWasteData.value.year;
+ return data.reduce(
+ (sum, item) => sum + item.绮夌叅鐏� + item.鐭宠啅 + item.鐭崇伆,
+ 0
+ );
+ });
+
+ const wasteTableData = computed(() => {
+ const data = solidWasteData.value[dateType.value];
+ const result = [];
+
+ data.forEach(item => {
+ result.push({
+ time: item.name,
+ type: "绮夌叅鐏�",
+ quantity: item.绮夌叅鐏�,
+ unit: "鍚�",
+ source: "鐢熶骇杩囩▼",
+ });
+ result.push({
+ time: item.name,
+ type: "鐭宠啅",
+ quantity: item.鐭宠啅,
+ unit: "鍚�",
+ source: "鐢熶骇杩囩▼",
+ });
+ result.push({
+ time: item.name,
+ type: "鐭崇伆",
+ quantity: item.鐭崇伆,
+ unit: "鍚�",
+ source: "鐢熶骇杩囩▼",
+ });
+ });
+
+ return result;
+ });
+
+ // 鍥捐〃閰嶇疆
+ const trendChartOption = computed(() => {
+ const data = solidWasteData.value[dateType.value];
+ return {
+ tooltip: {
+ trigger: "axis",
+ axisPointer: {
+ type: "shadow",
+ },
+ },
+ legend: {
+ data: ["绮夌叅鐏�", "鐭宠啅", "鐭崇伆"],
+ textStyle: {
+ color: "#333",
+ },
+ },
+ grid: {
+ left: "3%",
+ right: "4%",
+ bottom: "3%",
+ containLabel: true,
+ },
+ xAxis: {
+ type: "category",
+ data: data.map(item => item.name),
+ axisLabel: {
+ color: "#333",
+ },
+ },
+ yAxis: {
+ type: "value",
+ name: "娑堢撼閲� (鍚�)",
+ axisLabel: {
+ color: "#333",
+ },
+ },
+ series: [
+ {
+ name: "绮夌叅鐏�",
+ type: "bar",
+ data: data.map(item => item.绮夌叅鐏�),
+ itemStyle: {
+ color: "#909399",
+ },
+ },
+ {
+ name: "鐭宠啅",
+ type: "bar",
+ data: data.map(item => item.鐭宠啅),
+ itemStyle: {
+ color: "#E6A23C",
+ },
+ },
+ {
+ name: "鐭崇伆",
+ type: "bar",
+ data: data.map(item => item.鐭崇伆),
+ itemStyle: {
+ color: "#F56C6C",
+ },
+ },
+ ],
+ };
+ });
+
+ const distributionChartOption = computed(() => {
+ const data = solidWasteData.value[dateType.value];
+ const lastItem = data[data.length - 1];
+
+ return {
+ tooltip: {
+ trigger: "item",
+ formatter: "{a} <br/>{b}: {c} ({d}%)",
+ },
+ legend: {
+ orient: "vertical",
+ left: "left",
+ textStyle: {
+ color: "#333",
+ },
+ },
+ series: [
+ {
+ name: "鍥哄簾绫诲瀷",
+ type: "pie",
+ radius: "60%",
+ center: ["50%", "50%"],
+ data: [
+ { value: lastItem.绮夌叅鐏�, name: "绮夌叅鐏�" },
+ { value: lastItem.鐭宠啅, name: "鐭宠啅" },
+ { value: lastItem.鐭崇伆, name: "鐭崇伆" },
+ ],
+ emphasis: {
+ itemStyle: {
+ shadowBlur: 10,
+ shadowOffsetX: 0,
+ shadowColor: "rgba(0, 0, 0, 0.5)",
+ },
+ },
+ itemStyle: {
+ color: function (params) {
+ const colors = ["#909399", "#E6A23C", "#F56C6C"];
+ return colors[params.dataIndex];
+ },
+ },
+ },
+ ],
+ };
+ });
+
+ // 浜嬩欢澶勭悊
+ const handleDateTypeChange = () => {
+ updateCharts();
+ };
+
+ // 鍒濆鍖栧浘琛�
+ const initCharts = () => {
+ if (trendChart.value) {
+ trendChartInstance = echarts.init(trendChart.value);
+ trendChartInstance.setOption(trendChartOption.value);
+ }
+
+ if (distributionChart.value) {
+ distributionChartInstance = echarts.init(distributionChart.value);
+ distributionChartInstance.setOption(distributionChartOption.value);
+ }
+ };
+
+ // 鏇存柊鍥捐〃
+ const updateCharts = () => {
+ if (trendChartInstance) {
+ trendChartInstance.setOption(trendChartOption.value);
+ }
+
+ if (distributionChartInstance) {
+ distributionChartInstance.setOption(distributionChartOption.value);
+ }
+ };
+
+ // 璋冩暣鍥捐〃澶у皬
+ const resizeCharts = () => {
+ trendChartInstance?.resize();
+ distributionChartInstance?.resize();
+ };
+
+ // 绐楀彛澶у皬鍙樺寲澶勭悊
+ const handleResize = () => {
+ // 寤惰繜鎵ц锛岀‘淇滵OM鏇存柊瀹屾垚
+ setTimeout(() => {
+ resizeCharts();
+ }, 100);
+ };
+
+ // 鑾峰彇鍥哄簾绫诲瀷鏍囩绫诲瀷
+ const getWasteTypeType = type => {
+ const typeMap = {
+ 绮夌叅鐏�: "info",
+ 鐭宠啅: "warning",
+ 鐭崇伆: "danger",
+ };
+ return typeMap[type] || "info";
+ };
+
+ // 鐢熷懡鍛ㄦ湡閽╁瓙
+ onMounted(() => {
+ // 浣跨敤nextTick纭繚DOM瀹屽叏娓叉煋鍚庡啀鍒濆鍖�
+ nextTick(() => {
+ // 鍒濆鍖栧浘琛�
+ initCharts();
+ });
+
+ window.addEventListener("resize", handleResize);
+ });
+
+ onBeforeUnmount(() => {
+ window.removeEventListener("resize", handleResize);
+
+ // 閿�姣佸浘琛ㄥ疄渚�
+ trendChartInstance?.dispose();
+ distributionChartInstance?.dispose();
+ });
+</script>
+
+<style scoped>
+ /* 澶栭儴瀹瑰櫒 - 鍗犳嵁鏁翠釜瑙嗗彛 */
+ .dashboard-container {
+ position: relative;
+ width: 100%;
+ /* 椤甸潰鍦ㄥ父瑙勫竷灞�涓嬶紙鏈夐《鏍忥級榛樿鍑忓幓 84px锛岄伩鍏嶅唴瀹硅瑁佸垏 */
+ min-height: calc(100vh - 84px);
+ background-color: #f5f7fa;
+ overflow: hidden;
+ }
+
+ /* 鍐呴儴鍐呭鍖哄煙 - 鑷�傚簲瀹藉害 */
+ .data-dashboard {
+ position: relative;
+ width: 100%;
+ min-height: 100%;
+ background-color: #ffffff;
+ box-shadow: 0 0 20px rgba(0, 0, 0, 0.1);
+ }
+
+ .filter-area {
+ padding: 20px;
+ background-color: #ffffff;
+ border-bottom: 1px solid #e4e7ed;
+ display: flex;
+ gap: 40px;
+ align-items: center;
+ flex-wrap: wrap;
+ }
+
+ .filter-section {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ }
+
+ .filter-label {
+ font-size: 14px;
+ font-weight: 500;
+ color: #303133;
+ white-space: nowrap;
+ }
+
+ .radio-group {
+ display: flex;
+ align-items: center;
+ }
+
+ /* 鎸夐挳鏍峰紡 */
+ :deep(.el-radio-button__inner) {
+ border-radius: 4px;
+ padding: 8px 20px;
+ font-size: 14px;
+ transition: all 0.3s ease;
+ }
+
+ :deep(.el-radio-button__orig-radio:checked + .el-radio-button__inner) {
+ background-color: #409eff;
+ border-color: #409eff;
+ color: #ffffff;
+ box-shadow: 0 2px 4px rgba(64, 158, 255, 0.3);
+ }
+
+ :deep(.el-radio-button__inner:hover) {
+ color: #409eff;
+ border-color: #c6e2ff;
+ }
+
+ :deep(.el-radio-button:first-child .el-radio-button__inner) {
+ border-radius: 4px 0 0 4px;
+ }
+
+ :deep(.el-radio-button:last-child .el-radio-button__inner) {
+ border-radius: 0 4px 4px 0;
+ }
+
+ .dashboard-content {
+ position: relative;
+ z-index: 1;
+ display: flex;
+ flex-direction: column;
+ gap: 20px;
+ padding: 20px;
+ min-height: 800px;
+ overflow: hidden;
+ }
+
+ /* 琛屽竷灞� */
+ .row {
+ display: flex;
+ gap: 20px;
+ align-items: stretch;
+ }
+
+ /* 绗竴琛岋細鏍稿績鎸囨爣 */
+ .row-1 {
+ height: 250px;
+ }
+
+ /* 绗簩琛岋細鍥哄簾娑堢撼瓒嬪娍 */
+ .row-2 {
+ height: 300px;
+ }
+
+ /* 绗笁琛岋細鍥哄簾绫诲瀷鍒嗗竷 */
+ .row-3 {
+ height: 300px;
+ }
+
+ /* 绗洓琛岋細娑堢撼閲忔槑缁� */
+ .row-4 {
+ min-height: 250px;
+ }
+
+ /* 鍗$墖鏍峰紡 */
+ .panel-card {
+ background-color: #ffffff;
+ border-radius: 8px;
+ border: 1px solid #e4e7ed;
+ overflow: hidden;
+ display: flex;
+ flex-direction: column;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
+ transition: all 0.3s ease;
+ }
+
+ .panel-card:hover {
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
+ transform: translateY(-2px);
+ }
+
+ /* 鍗$墖甯冨眬 */
+ .card-1 {
+ flex: 1;
+ }
+
+ .card-2 {
+ flex: 1;
+ }
+
+ .card-3 {
+ flex: 1;
+ }
+
+ .card-4 {
+ flex: 1;
+ }
+
+ .panel-title {
+ padding: 15px 20px;
+ font-size: 16px;
+ font-weight: 500;
+ color: #303133;
+ border-bottom: 1px solid #e4e7ed;
+ background-color: #fafafa;
+ }
+
+ .card-1 .panel-title {
+ border-left: 4px solid #409eff;
+ }
+
+ .card-2 .panel-title {
+ border-left: 4px solid #f56c6c;
+ }
+
+ .card-3 .panel-title {
+ border-left: 4px solid #e6a23c;
+ }
+
+ .card-4 .panel-title {
+ border-left: 4px solid #67c23a;
+ }
+
+ .chart-container {
+ flex: 1;
+ padding: 20px;
+ }
+
+ .table-container {
+ flex: 1;
+ padding: 20px;
+ overflow: auto;
+ }
+
+ .stats-grid {
+ flex: 1;
+ padding: 15px;
+ display: grid;
+ grid-template-columns: repeat(2, 1fr);
+ gap: 15px;
+ }
+
+ .stat-item {
+ background-color: #ffffff;
+ border-radius: 12px;
+ padding: 25px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ border: 2px solid #e4e7ed;
+ min-height: 120px;
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
+ transition: all 0.3s ease;
+ }
+
+ .stat-item:hover {
+ box-shadow: 0 8px 24px rgba(64, 158, 255, 0.2);
+ border-color: #409eff;
+ transform: translateY(-4px);
+ }
+
+ .stat-label {
+ font-size: 14px;
+ font-weight: 500;
+ color: #303133;
+ margin-bottom: 10px;
+ }
+
+ .stat-value {
+ font-size: 32px;
+ font-weight: 700;
+ color: #409eff;
+ margin-bottom: 5px;
+ text-shadow: 0 2px 4px rgba(64, 158, 255, 0.3);
+ transition: all 0.3s ease;
+ }
+
+ .stat-value:hover {
+ transform: scale(1.05);
+ }
+
+ .stat-unit {
+ font-size: 12px;
+ font-weight: 500;
+ color: #606266;
+ }
+
+ /* 琛ㄦ牸鏍峰紡 */
+ :deep(.el-table) {
+ border-radius: 8px;
+ overflow: hidden;
+ }
+
+ :deep(.el-table th) {
+ background-color: #fafafa;
+ font-weight: 500;
+ }
+
+ :deep(.el-table tr:hover > td) {
+ background-color: #ecf5ff;
+ }
+
+ .data-value {
+ font-weight: bold;
+ color: #409eff;
+ }
+</style>
\ No newline at end of file
--
Gitblit v1.9.3