zhangwencui
2 天以前 1c20a331d9fc1be029fadbd3d0f7619fe6a83cd0
决策分析页面
已添加1个文件
已修改2个文件
4175 ■■■■■ 文件已修改
src/views/reportAnalysis/productionStatistics/index.vue 1681 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/reportAnalysis/salesStatistics/index.vue 1871 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/reportAnalysis/solidWasteConsumption/index1.vue 623 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
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 = () => {
  // å»¶è¿Ÿæ‰§è¡Œï¼Œç¡®ä¿DOM更新完成
  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 = () => {
    // å»¶è¿Ÿæ‰§è¡Œï¼Œç¡®ä¿DOM更新完成
    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>
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>
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 = () => {
    // å»¶è¿Ÿæ‰§è¡Œï¼Œç¡®ä¿DOM更新完成
    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>