zhangwencui
11 小时以前 b9c361da3b0613c22f1d167c418d700254d5d209
生产统计看板(部分开发)
已添加1个文件
已修改2个文件
3437 ■■■■ 文件已修改
src/views/reportAnalysis/productionStatistics/index copy.vue 1003 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/reportAnalysis/productionStatistics/index.vue 2420 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/reportAnalysis/salesStatistics/index.vue 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/reportAnalysis/productionStatistics/index copy.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,1003 @@
<template>
  <div class="dashboard-container">
    <div class="data-dashboard">
      <!-- é¡¶éƒ¨æ ‡é¢˜æ  -->
      <!-- <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>
        <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>
          </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="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"
                                 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>
  </div>
</template>
<script setup>
  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 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;
  // æ¨¡æ‹Ÿæ•°æ®
  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 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",
        },
      },
      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.block),
          smooth: true,
          lineStyle: {
            width: 3,
          },
          itemStyle: {
            color: "#409EFF",
          },
        },
        {
          name: "板材",
          type: "line",
          data: data.map(item => item.plate),
          smooth: true,
          lineStyle: {
            width: 3,
          },
          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",
          },
        },
        {
          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,
          },
          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 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 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 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 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 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 handleDateTypeChange = () => {
    updateCharts();
  };
  const handleProductTypeChange = () => {
    updateCharts();
  };
  // åˆå§‹åŒ–图表
  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 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;
  }
  /* å†…部内容区域 - è‡ªé€‚应宽度 */
  .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;
  }
  .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-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;
  }
  /* ç¬¬ä¸€è¡Œï¼š3个卡片 */
  .row-1 {
    height: 300px;
  }
  /* ç¬¬äºŒè¡Œï¼š2个卡片 */
  .row-2 {
    height: 300px;
  }
  /* ç¬¬ä¸‰è¡Œï¼š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: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: 0.8;
  }
  .card-4 {
    flex: 1.2;
  }
  .card-5 {
    flex: 0.8;
  }
  .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-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 #409eff;
  }
  .card-5 .panel-title {
    border-left: 4px solid #67c23a;
  }
  .card-6 .panel-title {
    border-left: 4px solid #e6a23c;
  }
  .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);
    grid-template-rows: repeat(2, 1fr);
    gap: 15px;
  }
  .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;
  }
  .stat-label {
    font-size: 13px;
    color: #606266;
    margin-bottom: 8px;
  }
  .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/productionStatistics/index.vue
@@ -1,157 +1,233 @@
<template>
  <div class="dashboard-container">
    <div class="data-dashboard">
      <!-- é¡¶éƒ¨æ ‡é¢˜æ  -->
      <!-- <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 ref="screenRoot"
       class="sales-statistics-container"
       :class="{ 'is-fullscreen': isFullscreen }">
    <div class="bi-bg"></div>
    <div class="bi-topbar">
      <img class="bi-topbar-title-bg"
           src="@/assets/BI/biaoti.png"
           alt="生产看板统计" />
      <div class="bi-topbar-content">
        <div class="bi-topbar-left">
          <button class="fullscreen-btn"
                  @click="toggleFullscreen"
                  :title="isFullscreen ? '退出全屏' : '全屏显示'">
            <svg v-if="!isFullscreen"
                 width="1.6vh"
                 height="1.6vh"
                 viewBox="0 0 24 24"
                 fill="none"
                 stroke="currentColor"
                 stroke-width="2">
              <path d="M8 3v3a2 2 0 0 1-2 2H3m18 0h-3a2 2 0 0 1-2-2V3m0 18v-3a2 2 0 0 1 2-2h3M3 16h3a2 2 0 0 1 2 2v3" />
            </svg>
            <svg v-else
                 width="1.6vh"
                 height="1.6vh"
                 viewBox="0 0 24 24"
                 fill="none"
                 stroke="currentColor"
                 stroke-width="2">
              <path d="M8 3H5a2 2 0 0 0-2 2v3m18 0V5a2 2 0 0 0-2-2h-3m0 18h3a2 2 0 0 0 2-2v-3M3 16v3a2 2 0 0 0 2 2h3" />
            </svg>
          </button>
        </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 class="bi-topbar-title">生产看板统计</div>
        <div class="bi-topbar-meta">
          <span class="bi-topbar-time">{{ currentTime }}</span>
          <span class="bi-topbar-sep">|</span>
          <span class="bi-topbar-date">{{ currentDateText }}</span>
        </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>
          </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="bi-dashboard-grid">
      <!-- å·¦ä¸Šï¼šç”Ÿäº§æˆæœ¬å•耗统计(砌块) -->
      <div class="bi-panel bi-panel-top-left">
        <PanelHeader :isFullscreen="true"
                     title="生产成本单耗统计(砌块)" />
        <div class="panel-tabs">
          <span class="tab-item"
                :class="{ active: blockTimeDimension === 'year' }"
                @click="handleBlockTimeDimensionChange('year')">å¹´</span>
          <span class="tab-item"
                :class="{ active: blockTimeDimension === 'month' }"
                @click="handleBlockTimeDimensionChange('month')">月</span>
        </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 class="bi-panel-body">
            <div class="chart-filter-tabs">
            <span v-for="area in salesAreas"
                  :key="area"
                  class="cf-tab"
                  :class="{ active: blockSelectedArea === area }"
                  @click="handleBlockAreaChange(area)">{{ area }}</span>
          </div>
          <div class="material-info-card">
            <div class="material-icon">
              <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
                <path d="M20 7h-4V4c0-1.1-.9-2-2-2h-4c-1.1 0-2 .9-2 2v3H4c-1.1 0-2 .9-2 2v11c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V9c0-1.1-.9-2-2-2z" />
                <polyline points="22,7 12,13 2,7" />
              </svg>
            </div>
            <div class="material-details">
              <div class="material-name">{{ blockMaterialType }}AAA</div>
              <div class="material-stats">
                <div class="stat-item">
                  <span class="stat-label">月累计单耗</span>
                  <span class="stat-value">78/12</span>
                  <span class="stat-unit">吨</span>
                </div>
                <div class="stat-item">
                  <span class="stat-label">年累计单耗</span>
                  <span class="stat-value">78/12</span>
                  <span class="stat-unit">吨</span>
                </div>
              </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 class="chart-unit-row">
            <span>单位:立方米</span>
          </div> -->
          <div ref="blockCostChart"
               class="echart-fill"></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"
                                 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 class="bi-panel bi-panel-top-right">
        <PanelHeader :isFullscreen="true"
                     title="物料生产量分析" />
        <div class="panel-tabs">
          <span class="tab-item"
                :class="{ active: productionTimeDimension === 'year' }"
                @click="handleProductionTimeDimensionChange('year')">å¹´</span>
          <span class="tab-item"
                :class="{ active: productionTimeDimension === 'month' }"
                @click="handleProductionTimeDimensionChange('month')">月</span>
        </div>
        <div class="bi-panel-body">
          <div class="chart-unit-row">
            <span>单位:件</span>
          </div>
          <div ref="productionChart"
               class="echart-fill"></div>
        </div>
      </div>
      <!-- ä¸­é—´ä¸­å¿ƒçޝ -->
      <div class="center-ring">
        <!-- <div class="center-ring-box">
          <div class="center-metric m1">
            <div class="center-metric-label">项目产量</div>
            <div class="center-metric-value">{{ projectProduction }}</div>
            <div class="center-metric-unit">ä»¶</div>
          </div>
          <div class="center-metric m2">
            <div class="center-metric-label">固体处理量</div>
            <div class="center-metric-value">{{ solidWaste处理量 }}</div>
            <div class="center-metric-unit">吨</div>
          </div>
          <div class="center-metric m3">
            <div class="center-metric-label">砌块产量</div>
            <div class="center-metric-value">{{ blockProduction }}</div>
            <div class="center-metric-unit">ä»¶</div>
          </div>
          <div class="center-metric m4">
            <div class="center-metric-label">板材产量</div>
            <div class="center-metric-value">{{ boardProduction }}</div>
            <div class="center-metric-unit">ä»¶</div>
          </div>
        </div> -->
      </div>
      <!-- å·¦ä¸‹ï¼šç”Ÿäº§æˆæœ¬å•耗统计(板材) -->
      <div class="bi-panel bi-panel-bottom-left">
        <PanelHeader :isFullscreen="true"
                     title="生产成本单耗统计(板材)" />
        <div class="panel-tabs">
          <span class="tab-item"
                :class="{ active: boardTimeDimension === 'year' }"
                @click="handleBoardTimeDimensionChange('year')">å¹´</span>
          <span class="tab-item"
                :class="{ active: boardTimeDimension === 'month' }"
                @click="handleBoardTimeDimensionChange('month')">月</span>
        </div>
        <div class="bi-panel-body">
            <div class="chart-filter-tabs">
            <span v-for="area in salesAreas"
                  :key="area"
                  class="cf-tab"
                  :class="{ active: blockSelectedArea === area }"
                  @click="handleBlockAreaChange(area)">{{ area }}</span>
          </div>
          <div class="material-info-card">
            <div class="material-icon">
              <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
                <path d="M20 7h-4V4c0-1.1-.9-2-2-2h-4c-1.1 0-2 .9-2 2v3H4c-1.1 0-2 .9-2 2v11c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V9c0-1.1-.9-2-2-2z" />
                <polyline points="22,7 12,13 2,7" />
              </svg>
            </div>
            <div class="material-details">
              <div class="material-name">{{ boardMaterialType }}AAA</div>
              <div class="material-stats">
                <div class="stat-item">
                  <span class="stat-label">月累计单耗</span>
                  <span class="stat-value">78/12</span>
                  <span class="stat-unit">吨</span>
                </div>
                <div class="stat-item">
                  <span class="stat-label">年累计单耗</span>
                  <span class="stat-value">78/12</span>
                  <span class="stat-unit">吨</span>
                </div>
              </div>
            </div>
          </div>
          <!-- <div class="chart-unit-row">
            <span>单位:立方米</span>
          </div> -->
          <div ref="boardCostChart"
               class="echart-fill"></div>
        </div>
      </div>
      <!-- ä¸­ä¸‹ï¼šæ–°å¢žå®¢æˆ·è¶‹åŠ¿åˆ†æž -->
      <div class="bi-panel bi-panel-bottom-center">
        <PanelHeader :isFullscreen="true"
                     title="固废处理量" />
        <div class="panel-tabs">
          <span class="tab-item"
                :class="{ active: customerTimeDimension === 'year' }"
                @click="handleCustomerTimeDimensionChange('year')">å¹´</span>
          <span class="tab-item"
                :class="{ active: customerTimeDimension === 'month' }"
                @click="handleCustomerTimeDimensionChange('month')">月</span>
        </div>
        <!-- <div class="bi-panel-body">
          <div class="chart-unit-row chart-unit-single">
            <span>单位:家</span>
          </div>
          <div ref="customerTrendChart"
               class="echart-fill"></div>
        </div> -->
      </div>
      <!-- å³ä¸‹ï¼šé”€é‡æŽ’名分析 -->
      <div class="bi-panel bi-panel-bottom-right">
        <PanelHeader :isFullscreen="true"
                     title="物料生产量统计" />
        <div class="panel-tabs">
          <span class="tab-item"
                :class="{ active: salesTimeDimension === 'year' }"
                @click="handleSalesTimeDimensionChange('year')">å¹´</span>
          <span class="tab-item"
                :class="{ active: salesTimeDimension === 'month' }"
                @click="handleSalesTimeDimensionChange('month')">月</span>
        </div>
        <div class="bi-panel-body">
          <!-- <div class="chart-filter-tabs">
            <span v-for="area in salesAreas"
                  :key="area"
                  class="cf-tab"
                  :class="{ active: selectedArea === area }"
                  @click="handleAreaChange(area)">{{ area }}</span>
          </div>
          <div ref="salesRankingChart"
               class="echart-fill"></div> -->
        </div>
      </div>
    </div>
@@ -164,840 +240,1456 @@
    computed,
    onMounted,
    onBeforeUnmount,
    nextTick,
    watch,
    nextTick,
  } from "vue";
  import * as echarts from "echarts";
  import dayjs from "dayjs";
  import PanelHeader from "@/views/reportAnalysis/PSIDataAnalysis/components/PanelHeader.vue";
  // ç­›é€‰æ¡ä»¶
  const dateType = ref("month"); // month æˆ– year
  const productType = ref("block"); // block æˆ– plate
  const screenRoot = ref(null);
  const isFullscreen = ref(false);
  // å›¾è¡¨å¼•用
  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;
  // æ¨¡æ‹Ÿæ•°æ®
  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 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",
        },
      },
      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.block),
          smooth: true,
          lineStyle: {
            width: 3,
          },
          itemStyle: {
            color: "#409EFF",
          },
        },
        {
          name: "板材",
          type: "line",
          data: data.map(item => item.plate),
          smooth: true,
          lineStyle: {
            width: 3,
          },
          itemStyle: {
            color: "#67C23A",
          },
        },
      ],
  // é¡¶éƒ¨æ æ—¶é—´
  const now = ref(dayjs());
  const currentTime = computed(() => now.value.format("HH:mm:ss"));
  const currentDateText = computed(() => {
    const weekMap = {
      0: "星期日",
      1: "星期一",
      2: "星期二",
      3: "星期三",
      4: "星期四",
      5: "星期五",
      6: "星期六",
    };
    return `${now.value.format("YYYY-MM-DD")} ${weekMap[now.value.day()] || ""}`;
  });
  let timeTicker = null;
  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 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,
          },
          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 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 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 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 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 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 handleDateTypeChange = () => {
    updateCharts();
  const handleFullscreenChange = () => {
    isFullscreen.value = !!document.fullscreenElement;
    nextTick(() => {
      handleResize();
    });
  };
  const handleProductTypeChange = () => {
    updateCharts();
  const toggleFullscreen = async () => {
    const rootEl = screenRoot.value;
    if (!rootEl) return;
    try {
      if (!document.fullscreenElement) {
        await rootEl.requestFullscreen();
      } else {
        await document.exitFullscreen();
      }
    } catch (error) {
      console.error("全屏切换失败:", error);
    }
  };
  // å›¾è¡¨å¼•用
  const blockCostChart = ref(null);
  const boardCostChart = ref(null);
  const productionChart = ref(null);
  const customerTrendChart = ref(null);
  const salesRankingChart = ref(null);
  // é€‰æ‹©å™¨æ•°æ®
  const blockTimeDimension = ref("year");
  const blockMaterialType = ref("石灰");
  const boardTimeDimension = ref("year");
  const boardMaterialType = ref("石灰");
  const productionTimeDimension = ref("year");
  const customerTimeDimension = ref("year");
  const salesTimeDimension = ref("year");
  const selectedArea = ref("全部");
  const salesAreas = [
    "全部",
    "石灰",
    "æ°´æ³¥",
    "铝粉膏",
    "脱模剂",
    "防腐剂",
    "氧化镁",
    "冷拔丝",
  ];
  // ä¸­å¿ƒçŽ¯æ•°æ®
  const projectProduction = ref(12345);
  const solidWaste处理量 = ref(6789);
  const blockProduction = ref(7812);
  const boardProduction = ref(7812);
  // å›¾è¡¨å®žä¾‹
  let blockCostChartInstance = null;
  let boardCostChartInstance = null;
  let productionChartInstance = null;
  let customerTrendChartInstance = null;
  let salesRankingChartInstance = null;
  // ç”Ÿäº§å•耗图表配置
  const blockCostChartOption = computed(() => {
    const materials = ["消耗量"];
    const colors = ["#8A6BFF"];
    const year = 2024;
    const periodType = blockTimeDimension.value;
    // ç”Ÿæˆæ—¶é—´æ®µ
    let periods = [];
    if (periodType === "year") {
      // å¹´åº¦æ•°æ®ï¼š6个月
      for (let month = 9; month <= 12; month++) {
        periods.push(`${month}/${year.toString().slice(2)}`);
      }
      for (let month = 1; month <= 3; month++) {
        periods.push(`${month}/${(year + 1).toString().slice(2)}`);
      }
    } else {
      // æœˆåº¦æ•°æ®ï¼š30天
      const month = 1;
      for (let day = 1; day <= 30; day++) {
        periods.push(`${month}/${day}`);
      }
    }
    // ä¸ºæ¯ç§ææ–™ç”Ÿæˆæ•°æ®
    const series = materials.map((material, index) => {
      const data = periods.map(() => {
        return periodType === "year"
          ? Math.floor(Math.random() * 50) + 150
          : Math.floor(Math.random() * 5) + 15;
      });
      return {
        name: material,
        data: data,
        type: "bar",
        itemStyle: { color: colors[index] },
      };
    });
    return {
      backgroundColor: "transparent",
      tooltip: {
        trigger: "axis",
        backgroundColor: "rgba(0,0,0,0.55)",
        borderColor: "rgba(64,158,255,0.25)",
        borderWidth: getResponsiveValue(1),
        textStyle: { color: "#B8C8E0", fontSize: getResponsiveValue(11) },
      },
      // legend: {
      //   data: materials,
      //   top: "10%",
      //   right: "1%",
      //   textStyle: {
      //     color: "#B8C8E0",
      //     fontSize: getResponsiveValue(9),
      //   },
      //   itemWidth: getResponsiveValue(10),
      //   itemHeight: getResponsiveValue(10),
      // },
      grid: {
        left: "1%",
        right: "1%",
        bottom: "1%",
        top: "8%",
        containLabel: true,
      },
      xAxis: {
        type: "category",
        data: periods,
        axisLine: { lineStyle: { color: "rgba(184,200,224,0.25)" } },
        axisTick: { show: false },
        axisLabel: {
          color: "#B8C8E0",
          fontSize: getResponsiveValue(11),
          margin: getResponsiveValue(10),
        },
        splitLine: { show: false },
      },
      yAxis: {
        type: "value",
        axisLine: { lineStyle: { color: "rgba(184,200,224,0.25)" } },
        axisLabel: {
          color: "#B8C8E0",
          fontSize: getResponsiveValue(11),
          margin: getResponsiveValue(8),
        },
        splitLine: { lineStyle: { color: "rgba(184,200,224,0.12)" } },
      },
      series: series,
    };
  });
  // æ¿æå•耗图表配置
  const boardCostChartOption = computed(() => {
    const materials = ["消耗量"];
    const colors = ["#00A4ED", "#34D8F7", "#4A8BFF", "#8A6BFF", "#C8C447", "#FF6B6B"];
    const year = 2024;
    const periodType = boardTimeDimension.value;
    // ç”Ÿæˆæ—¶é—´æ®µ
    let periods = [];
    if (periodType === "year") {
      // å¹´åº¦æ•°æ®ï¼š6个月
      for (let month = 9; month <= 12; month++) {
        periods.push(`${month}/${year.toString().slice(2)}`);
      }
      for (let month = 1; month <= 3; month++) {
        periods.push(`${month}/${(year + 1).toString().slice(2)}`);
      }
    } else {
      // æœˆåº¦æ•°æ®ï¼š30天
      const month = 1;
      for (let day = 1; day <= 30; day++) {
        periods.push(`${month}/${day}`);
      }
    }
    // ä¸ºæ¯ç§ææ–™ç”Ÿæˆæ•°æ®
    const series = materials.map((material, index) => {
      const data = periods.map(() => {
        return periodType === "year"
          ? Math.floor(Math.random() * 50) + 150
          : Math.floor(Math.random() * 5) + 15;
      });
      return {
        name: material,
        data: data,
        type: "bar",
        itemStyle: { color: colors[index] },
      };
    });
    return {
      backgroundColor: "transparent",
      tooltip: {
        trigger: "axis",
        backgroundColor: "rgba(0,0,0,0.55)",
        borderColor: "rgba(64,158,255,0.25)",
        borderWidth: getResponsiveValue(1),
        textStyle: { color: "#B8C8E0", fontSize: getResponsiveValue(11) },
      },
      // legend: {
      //   data: materials,
      //   top: "10%",
      //   right: "1%",
      //   textStyle: {
      //     color: "#B8C8E0",
      //     fontSize: getResponsiveValue(9),
      //   },
      //   itemWidth: getResponsiveValue(10),
      //   itemHeight: getResponsiveValue(10),
      // },
      grid: {
        left: "1%",
        right: "1%",
        bottom: "1%",
        top: "8%",
        containLabel: true,
      },
      xAxis: {
        type: "category",
        data: periods,
        axisLine: { lineStyle: { color: "rgba(184,200,224,0.25)" } },
        axisTick: { show: false },
        axisLabel: {
          color: "#B8C8E0",
          fontSize: getResponsiveValue(11),
          margin: getResponsiveValue(10),
        },
        splitLine: { show: false },
      },
      yAxis: {
        type: "value",
        axisLine: { lineStyle: { color: "rgba(184,200,224,0.25)" } },
        axisLabel: {
          color: "#B8C8E0",
          fontSize: getResponsiveValue(11),
          margin: getResponsiveValue(8),
        },
        splitLine: { lineStyle: { color: "rgba(184,200,224,0.12)" } },
      },
      series: series,
    };
  });
  // äº§é‡åˆ†æžå›¾è¡¨é…ç½®
  const productionChartOption = computed(() => {
    const salesAreas = ["全部", "砌块", "板材"];
    const colors = ["#00A4ED", "#34D8F7", "#4A8BFF", "#8A6BFF", "#C8C447", "#FF6B6B"];
    const year = 2024;
    const periodType = productionTimeDimension.value;
    // ç”Ÿæˆæ—¶é—´æ®µ
    let periods = [];
    if (periodType === "year") {
      // å¹´åº¦æ•°æ®ï¼š6个月
      for (let month = 9; month <= 12; month++) {
        periods.push(`${month}/${year.toString().slice(2)}`);
      }
      for (let month = 1; month <= 3; month++) {
        periods.push(`${month}/${(year + 1).toString().slice(2)}`);
      }
    } else {
      // æœˆåº¦æ•°æ®ï¼š30天
      const month = 1;
      for (let day = 1; day <= 30; day++) {
        periods.push(`${month}/${day}`);
      }
    }
    // ä¸ºæ¯ä¸ªé”€å”®åŒºç”Ÿæˆæ•°æ®
    const series = salesAreas.map((area, index) => {
      const data = periods.map(() => {
        return periodType === "year"
          ? Math.floor(Math.random() * 50) + 150
          : Math.floor(Math.random() * 5) + 15;
      });
      return {
        name: area,
        data: data,
        type: "line",
        smooth: true,
        lineStyle: { width: getResponsiveValue(2), color: colors[index] },
        itemStyle: { color: colors[index] },
        areaStyle: {
          opacity: 0.3,
          color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
            { offset: 0, color: colors[index] + "80" },
            { offset: 1, color: colors[index] + "00" },
          ]),
        },
      };
    });
    return {
      backgroundColor: "transparent",
      tooltip: {
        trigger: "axis",
        backgroundColor: "rgba(0,0,0,0.55)",
        borderColor: "rgba(64,158,255,0.25)",
        borderWidth: getResponsiveValue(1),
        textStyle: { color: "#B8C8E0", fontSize: getResponsiveValue(11) },
      },
      legend: {
        data: salesAreas,
        top: "10%",
        right: "1%",
        textStyle: {
          color: "#B8C8E0",
          fontSize: getResponsiveValue(9),
        },
        itemWidth: getResponsiveValue(10),
        itemHeight: getResponsiveValue(10),
      },
      grid: {
        left: "1%",
        right: "1%",
        bottom: "1%",
        top: "28%",
        containLabel: true,
      },
      xAxis: {
        type: "category",
        data: periods,
        axisLine: { lineStyle: { color: "rgba(184,200,224,0.25)" } },
        axisTick: { show: false },
        axisLabel: {
          color: "#B8C8E0",
          fontSize: getResponsiveValue(11),
          margin: getResponsiveValue(10),
        },
        splitLine: { show: false },
      },
      yAxis: {
        type: "value",
        axisLine: { lineStyle: { color: "rgba(184,200,224,0.25)" } },
        axisLabel: {
          color: "#B8C8E0",
          fontSize: getResponsiveValue(11),
          margin: getResponsiveValue(8),
        },
        splitLine: { lineStyle: { color: "rgba(184,200,224,0.12)" } },
      },
      series: series,
    };
  });
  // æ–°å¢žå®¢æˆ·è¶‹åŠ¿å›¾è¡¨é…ç½®
  const customerTrendChartOption = computed(() => {
    const customerTypes = ["全部", "石灰", "æ°´æ³¥", "铝粉膏", "脱模剂"];
    const colors = ["#00A4ED", "#34D8F7", "#4A8BFF", "#8A6BFF", "#C8C447"];
    const year = 2024;
    const periodType = customerTimeDimension.value;
    // ç”Ÿæˆæ—¶é—´æ®µ
    let periods = [];
    if (periodType === "year") {
      // å¹´åº¦æ•°æ®ï¼š6个月
      for (let month = 9; month <= 12; month++) {
        periods.push(`${month}/${year.toString().slice(2)}`);
      }
      for (let month = 1; month <= 5; month++) {
        periods.push(`${month}/${(year + 1).toString().slice(2)}`);
      }
    } else {
      // æœˆåº¦æ•°æ®ï¼š30天
      const month = 1;
      for (let day = 1; day <= 30; day++) {
        periods.push(`${month}/${day}`);
      }
    }
    // ä¸ºæ¯ç§å®¢æˆ·ç±»åž‹ç”Ÿæˆæ•°æ®
    const series = customerTypes.map((type, index) => {
      const data = periods.map(() => {
        return periodType === "year"
          ? Math.floor(Math.random() * 10) + 5
          : Math.floor(Math.random() * 3) + 1;
      });
      return {
        name: type,
        data: data,
        type: "line",
        smooth: true,
        lineStyle: { width: getResponsiveValue(2), color: colors[index] },
        itemStyle: { color: colors[index] },
        areaStyle: {
          opacity: 0.3,
          color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
            { offset: 0, color: colors[index] + "80" },
            { offset: 1, color: colors[index] + "00" },
          ]),
        },
      };
    });
    return {
      backgroundColor: "transparent",
      tooltip: {
        trigger: "axis",
        backgroundColor: "rgba(0,0,0,0.55)",
        borderColor: "rgba(64,158,255,0.25)",
        borderWidth: getResponsiveValue(1),
        textStyle: { color: "#B8C8E0", fontSize: getResponsiveValue(11) },
      },
      legend: {
        data: customerTypes,
        top: "10%",
        right: "1%",
        textStyle: {
          color: "#B8C8E0",
          fontSize: getResponsiveValue(9),
        },
        itemWidth: getResponsiveValue(10),
        itemHeight: getResponsiveValue(10),
      },
      grid: {
        left: "1%",
        right: "1%",
        bottom: "1%",
        top: "28%",
        containLabel: true,
      },
      xAxis: {
        type: "category",
        data: periods,
        axisLine: { lineStyle: { color: "rgba(184,200,224,0.25)" } },
        axisTick: { show: false },
        axisLabel: {
          color: "#B8C8E0",
          fontSize: getResponsiveValue(11),
          margin: getResponsiveValue(10),
        },
        splitLine: { show: false },
      },
      yAxis: {
        type: "value",
        axisLine: { lineStyle: { color: "rgba(184,200,224,0.25)" } },
        axisLabel: {
          color: "#B8C8E0",
          fontSize: getResponsiveValue(11),
          margin: getResponsiveValue(8),
        },
        splitLine: { lineStyle: { color: "rgba(184,200,224,0.12)" } },
      },
      series: series,
    };
  });
  // é”€é‡æŽ’名分析图表配置
  const salesRankingChartOption = computed(() => {
    const customers = ["客户BB", "客户AA", "客户CC", "客户DD", "客户DD", "客户DD"];
    const values = [130, 120, 102, 90, 90, 70];
    const barColors = [
      "#34D8F7",
      "#4A8BFF",
      "#8A6BFF",
      "#C8C447",
      "#C8C447",
      "#C8C447",
    ];
    return {
      backgroundColor: "transparent",
      tooltip: {
        trigger: "axis",
        axisPointer: { type: "shadow" },
        backgroundColor: "rgba(0,0,0,0.55)",
        borderColor: "rgba(64,158,255,0.25)",
        borderWidth: getResponsiveValue(1),
        textStyle: { color: "#B8C8E0", fontSize: getResponsiveValue(11) },
        formatter: "{b}: {c} ç«‹æ–¹ç±³",
      },
      grid: {
        left: "14%",
        right: "6%",
        top: "16%",
        bottom: "8%",
        containLabel: true,
      },
      xAxis: {
        type: "value",
        axisLine: { show: false },
        axisLabel: { color: "#B8C8E0", fontSize: getResponsiveValue(11) },
        splitLine: { lineStyle: { color: "rgba(184,200,224,0.12)" } },
      },
      yAxis: {
        type: "category",
        data: customers,
        axisTick: { show: false },
        axisLine: { show: false },
        axisLabel: {
          color: "#B8C8E0",
          fontSize: getResponsiveValue(11),
          margin: getResponsiveValue(8),
        },
      },
      series: [
        {
          name: "销量(立方米)",
          type: "bar",
          barWidth: getResponsiveValue(14),
          data: values,
          itemStyle: {
            color: params => barColors[params.dataIndex] || "#00A4ED",
            borderRadius: [
              getResponsiveValue(6),
              getResponsiveValue(6),
              getResponsiveValue(6),
              getResponsiveValue(6),
            ],
          },
        },
      ],
    };
  });
  const baseWidth = ref(1650);
  // è®¡ç®—响应式值
  const getResponsiveValue = baseValue => {
    return Math.round((baseValue * window.innerWidth) / baseWidth.value);
  };
  // åˆå§‹åŒ–图表
  const initCharts = () => {
    if (productionChart.value) {
    // åˆå§‹åŒ–砌块成本图表
    if (blockCostChart.value && !blockCostChartInstance) {
      blockCostChartInstance = echarts.init(blockCostChart.value);
    }
    // åˆå§‹åŒ–板材成本图表
    if (boardCostChart.value && !boardCostChartInstance) {
      boardCostChartInstance = echarts.init(boardCostChart.value);
    }
    // åˆå§‹åŒ–产量分析图表
    if (productionChart.value && !productionChartInstance) {
      productionChartInstance = echarts.init(productionChart.value);
      productionChartInstance.setOption(productionChartOption.value);
    }
    if (solidWasteChart.value) {
      solidWasteChartInstance = echarts.init(solidWasteChart.value);
      solidWasteChartInstance.setOption(solidWasteChartOption.value);
    // åˆå§‹åŒ–新增客户趋势图表
    if (customerTrendChart.value && !customerTrendChartInstance) {
      customerTrendChartInstance = echarts.init(customerTrendChart.value);
    }
    if (costChart.value) {
      costChartInstance = echarts.init(costChart.value);
      costChartInstance.setOption(costChartOption.value);
    // åˆå§‹åŒ–销量排名分析图表
    if (salesRankingChart.value && !salesRankingChartInstance) {
      salesRankingChartInstance = echarts.init(salesRankingChart.value);
    }
    if (energyChart.value) {
      energyChartInstance = echarts.init(energyChart.value);
      energyChartInstance.setOption(energyChartOption.value);
    }
    updateCharts();
  };
  // æ›´æ–°å›¾è¡¨
  const updateCharts = () => {
    // æ›´æ–°ç Œå—成本图表
    if (blockCostChartInstance) {
      blockCostChartInstance.setOption(blockCostChartOption.value);
    }
    // æ›´æ–°æ¿ææˆæœ¬å›¾è¡¨
    if (boardCostChartInstance) {
      boardCostChartInstance.setOption(boardCostChartOption.value);
    }
    // æ›´æ–°äº§é‡åˆ†æžå›¾è¡¨
    if (productionChartInstance) {
      productionChartInstance.setOption(productionChartOption.value);
    }
    if (solidWasteChartInstance) {
      solidWasteChartInstance.setOption(solidWasteChartOption.value);
    // æ›´æ–°æ–°å¢žå®¢æˆ·è¶‹åŠ¿å›¾è¡¨
    if (customerTrendChartInstance) {
      customerTrendChartInstance.setOption(customerTrendChartOption.value);
    }
    if (costChartInstance) {
      costChartInstance.setOption(costChartOption.value);
    }
    if (energyChartInstance) {
      energyChartInstance.setOption(energyChartOption.value);
    // æ›´æ–°é”€é‡æŽ’名分析图表
    if (salesRankingChartInstance) {
      salesRankingChartInstance.setOption(salesRankingChartOption.value);
    }
  };
  // è°ƒæ•´å›¾è¡¨å¤§å°
  const resizeCharts = () => {
    productionChartInstance?.resize();
    solidWasteChartInstance?.resize();
    costChartInstance?.resize();
    energyChartInstance?.resize();
  // å¤„理时间维度选择
  const handleBlockTimeDimensionChange = dimension => {
    blockTimeDimension.value = dimension;
    updateCharts();
  };
  // çª—口大小变化处理
  const handleBoardTimeDimensionChange = dimension => {
    boardTimeDimension.value = dimension;
    updateCharts();
  };
  const handleProductionTimeDimensionChange = dimension => {
    productionTimeDimension.value = dimension;
    updateCharts();
  };
  const handleCustomerTimeDimensionChange = dimension => {
    customerTimeDimension.value = dimension;
    updateCharts();
  };
  const handleSalesTimeDimensionChange = dimension => {
    salesTimeDimension.value = dimension;
    updateCharts();
  };
  // å¤„理材料类型选择
  const handleBlockMaterialTypeChange = type => {
    blockMaterialType.value = type;
    updateCharts();
  };
  const handleBoardMaterialTypeChange = type => {
    boardMaterialType.value = type;
    updateCharts();
  };
  // å¤„理销售区选择
  const handleAreaChange = area => {
    selectedArea.value = area;
    updateCharts();
  };
  // ç›‘听窗口大小变化
  const handleResize = () => {
    // å»¶è¿Ÿæ‰§è¡Œï¼Œç¡®ä¿DOM更新完成
    setTimeout(() => {
      resizeCharts();
    }, 100);
    // å…ˆæ›´æ–°å›¾è¡¨é€‰é¡¹ï¼Œé‡æ–°è®¡ç®—响应式值
    updateCharts();
    // ç„¶åŽè°ƒæ•´å›¾è¡¨å¤§å°
    if (blockCostChartInstance) {
      blockCostChartInstance.resize();
    }
    if (boardCostChartInstance) {
      boardCostChartInstance.resize();
    }
    if (productionChartInstance) {
      productionChartInstance.resize();
    }
    if (customerTrendChartInstance) {
      customerTrendChartInstance.resize();
    }
    if (salesRankingChartInstance) {
      salesRankingChartInstance.resize();
    }
  };
  // èŽ·å–ç‰©æ–™ç±»åž‹æ ‡ç­¾ç±»åž‹
  const getMaterialTypeType = material => {
    const typeMap = {
      æ°´æ³¥: "primary",
      é“ç²‰è†: "success",
      è„±æ¨¡å‰‚: "warning",
      é˜²è…å‰‚: "danger",
      æ°¯åŒ–剂: "info",
      å†·æ‹”丝: "purple",
    };
    return typeMap[material] || "info";
  };
  // ç”Ÿå‘½å‘¨æœŸé’©å­
  // ç”Ÿå‘½å‘¨æœŸ
  onMounted(() => {
    // ä½¿ç”¨nextTick确保DOM完全渲染后再初始化
    // å¯åŠ¨é¡¶éƒ¨æ æ—¶é—´åˆ·æ–°
    if (!timeTicker) {
      timeTicker = setInterval(() => {
        now.value = dayjs();
      }, 1000);
    }
    // ç­‰å¾…DOM更新后初始化图表
    nextTick(() => {
      // åˆå§‹åŒ–图表
      initCharts();
    });
    // æ·»åŠ çª—å£å¤§å°å˜åŒ–ç›‘å¬
    window.addEventListener("resize", handleResize);
    document.addEventListener("fullscreenchange", handleFullscreenChange);
  });
  // ç»„件卸载时销毁图表实例
  onBeforeUnmount(() => {
    window.removeEventListener("resize", handleResize);
    if (timeTicker) {
      clearInterval(timeTicker);
      timeTicker = null;
    }
    // é”€æ¯å›¾è¡¨å®žä¾‹
    productionChartInstance?.dispose();
    solidWasteChartInstance?.dispose();
    costChartInstance?.dispose();
    energyChartInstance?.dispose();
    if (blockCostChartInstance) {
      blockCostChartInstance.dispose();
    }
    if (boardCostChartInstance) {
      boardCostChartInstance.dispose();
    }
    if (productionChartInstance) {
      productionChartInstance.dispose();
    }
    if (customerTrendChartInstance) {
      customerTrendChartInstance.dispose();
    }
    if (salesRankingChartInstance) {
      salesRankingChartInstance.dispose();
    }
    // ç§»é™¤çª—口大小变化监听
    window.removeEventListener("resize", handleResize);
    document.removeEventListener("fullscreenchange", handleFullscreenChange);
  });
</script>
<style scoped>
  /* å¤–部容器 - å æ®æ•´ä¸ªè§†å£ */
  .dashboard-container {
  .sales-statistics-container {
    position: relative;
    width: 100%;
    /* é¡µé¢åœ¨å¸¸è§„布局下(有顶栏)默认减去 84px,避免内容被裁切 */
    min-height: calc(100vh - 84px);
    background-color: #f5f7fa;
    min-height: calc(100vh - 8.4vh);
    overflow: hidden;
    color: #b8c8e0;
    background: #041026;
  }
  /* å†…部内容区域 - è‡ªé€‚应宽度 */
  .data-dashboard {
    position: relative;
    width: 100%;
    min-height: 100%;
    background-color: #ffffff;
    box-shadow: 0 0 20px rgba(0, 0, 0, 0.1);
  .sales-statistics-container.is-fullscreen {
    min-height: 100vh;
    height: 100vh;
  }
  .dashboard-header {
  /* æ·±è‰²èƒŒæ™¯å›¾ */
  .bi-bg {
    position: absolute;
    inset: 0;
    /* background-image: url("@/assets/BI/backImage@2x.png"); */
    background-size: cover;
    background-position: center;
    background-repeat: no-repeat;
    z-index: 0;
  }
  /* é¡¶éƒ¨æ ‡é¢˜æ  */
  .bi-topbar {
    position: relative;
    z-index: 1;
    height: 86px;
    background-color: #ffffff;
    border-bottom: 1px solid #e4e7ed;
    z-index: 2;
    height: 5.8vh;
    display: flex;
    align-items: center;
    justify-content: center;
  }
  .factory-name {
    font-weight: 600;
    font-size: 32px;
    color: #303133;
  .bi-topbar-title-bg {
    position: absolute;
    top: 0;
    left: 0;
    height: 8vh;
    width: 100%;
    object-fit: cover;
    z-index: 0;
    pointer-events: none;
  }
  .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 {
  .bi-topbar-content {
    position: relative;
    z-index: 1;
    width: 100%;
    padding: 0 2.8vh;
    display: flex;
    flex-direction: column;
    gap: 20px;
    padding: 20px;
    min-height: 800px;
    overflow: hidden;
    align-items: center;
    justify-content: center;
  }
  /* è¡Œå¸ƒå±€ */
  .row {
  .bi-topbar-title {
    position: absolute;
    left: 50%;
    transform: translateX(-50%);
    font-size: 2.6vh;
    font-weight: 800;
    letter-spacing: 0.1vh;
    background: linear-gradient(180deg, #ffffff 0%, #b8dfff 100%);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
    color: transparent;
    text-shadow: 0 0 2.6vh rgba(0, 164, 237, 0.55);
  }
  .bi-topbar-left {
    position: absolute;
    left: 1vh;
    display: flex;
    gap: 20px;
    align-items: stretch;
    align-items: center;
    gap: 0.8vh;
    color: rgba(208, 231, 255, 0.85);
    font-size: 1.3vh;
  }
  /* ç¬¬ä¸€è¡Œï¼š3个卡片 */
  .row-1 {
    height: 300px;
  .status-sun {
    color: #ffd85e;
    text-shadow: 0 0 1vh rgba(255, 216, 94, 0.8);
    font-size: 1.3vh;
    line-height: 1;
  }
  /* ç¬¬äºŒè¡Œï¼š2个卡片 */
  .row-2 {
    height: 300px;
  }
  /* ç¬¬ä¸‰è¡Œï¼š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: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: 0.8;
  }
  .card-4 {
    flex: 1.2;
  }
  .card-5 {
    flex: 0.8;
  }
  .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-title {
    padding: 15px 20px;
    font-size: 16px;
  .bi-topbar-meta {
    position: absolute;
    right: 5.2vh;
    /* top: 1.6vh; */
    font-size: 1.2vh;
    font-weight: 500;
    color: #303133;
    border-bottom: 1px solid #e4e7ed;
    background-color: #fafafa;
    letter-spacing: 0.05vh;
    color: rgba(208, 231, 255, 0.85);
    display: flex;
    align-items: center;
    gap: 1vh;
  }
  .card-1 .panel-title {
    border-left: 4px solid #409eff;
  .fullscreen-btn {
    position: absolute;
    bottom: -1vh;
    transform: none;
    border: 0.1vh solid rgba(64, 158, 255, 0.45);
    background: rgba(0, 164, 237, 0.14);
    color: #d0e7ff;
    width: 3.4vh;
    height: 3.4vh;
    border-radius: 0.6vh;
    padding: 0;
    cursor: pointer;
    transition: all 0.2s ease;
    z-index: 10;
    display: flex;
    align-items: center;
    justify-content: center;
  }
  .card-2 .panel-title {
    border-left: 4px solid #f56c6c;
  .fullscreen-btn:hover {
    background: rgba(0, 164, 237, 0.24);
    box-shadow: 0 0 1.2vh rgba(0, 164, 237, 0.3);
  }
  .card-3 .panel-title {
    border-left: 4px solid #e6a23c;
  .bi-topbar-sep {
    opacity: 0.7;
  }
  .card-4 .panel-title {
    border-left: 4px solid #409eff;
  /* ä¸»ä½“网格布局 */
  .bi-dashboard-grid {
    position: relative;
    z-index: 2;
    height: calc(100vh - 8.4vh - 5.8vh);
    min-height: 45vh;
    padding: 1vh 1.8vh 1.4vh;
    display: grid;
    grid-template-columns: 1fr 1.05fr 1fr;
    grid-template-rows: 1fr 1fr;
    gap: 1.2vh;
  }
  .card-5 .panel-title {
    border-left: 4px solid #67c23a;
  .sales-statistics-container.is-fullscreen .bi-dashboard-grid {
    height: calc(100vh - 5.8vh);
  }
  .card-6 .panel-title {
    border-left: 4px solid #e6a23c;
  .bi-panel {
    background: rgba(3, 18, 46, 0.62);
    border: 0.1vh solid rgba(64, 158, 255, 0.35);
    border-radius: 0.4vh;
    overflow: hidden;
    box-shadow: 0 0 2.2vh rgba(0, 164, 237, 0.12);
    display: flex;
    flex-direction: column;
    position: relative;
  }
  .chart-container {
  .bi-panel-title {
    height: 4.4vh;
    display: flex;
    align-items: center;
    padding: 0 1.8vh;
    font-size: 1.5vh;
    font-weight: 700;
    color: #b8c8e0;
    background: linear-gradient(
      90deg,
      rgba(0, 164, 237, 0.2),
      rgba(0, 164, 237, 0.04)
    );
    border-bottom: 0.1vh solid rgba(64, 158, 255, 0.25);
  }
  .panel-tabs,
  .panel-tabs2 {
    position: absolute;
    top: 0.8vh;
    display: flex;
    gap: 0.6vh;
    z-index: 4;
  }
  .panel-tabs {
    right: 1.2vh;
  }
  .panel-tabs2 {
    right: 8vh;
  }
  .tab-item {
    font-size: 1.2vh;
    color: rgba(184, 200, 224, 0.75);
    padding: 0.1vh 0.5vh;
    border: 0.1vh solid rgba(64, 158, 255, 0.25);
    border-radius: 0.3vh;
    line-height: 1.4;
    cursor: pointer;
  }
  .tab-item.active {
    color: #ffffff;
    border-color: rgba(0, 164, 237, 0.65);
    background: rgba(0, 164, 237, 0.22);
  }
  .bi-panel-body {
    flex: 1;
    padding: 20px;
    padding: 0.8vh 1vh;
    position: relative;
  }
  .table-container {
    flex: 1;
    padding: 20px;
  .scroll-table-container {
    height: 33vh;
    overflow: hidden;
    position: relative;
  }
  .scroll-table {
    width: 100%;
    border-collapse: collapse;
    color: #b8c8e0;
  }
  .scroll-table th {
    /* background-color: #0e2a54; */
    padding: 1.2vh;
    text-align: left;
    font-size: 1.2vh;
    font-weight: bold;
    border: 1px solid rgba(184, 200, 224, 0.2);
  }
  .scroll-table td {
    padding: 1vh;
    font-size: 1.1vh;
    border-bottom: 1px solid rgba(184, 200, 224, 0.1);
  }
  .scroll-table tbody {
    display: block;
    height: 35vh;
    overflow: hidden;
  }
  .scroll-table thead,
  .scroll-table tbody tr {
    display: table;
    width: 100%;
    table-layout: fixed;
  }
  .scroll-table th,
  .scroll-table td {
    width: 25%;
    box-sizing: border-box;
    font-size: 1.4vh;
  }
  .scroll-table tbody tr {
    transition: all 0.5s ease-in-out;
  }
  /* .scroll-table tbody tr:nth-child(odd) {
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  background-color: rgba(64, 158, 255, 0.05);
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  }
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                .scroll-table tbody tr:nth-child(even) {
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    background-color: rgba(64, 158, 255, 0.1);
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      } */
  .oddTableTr {
    background-color: rgba(64, 158, 255, 0.05);
  }
  .evenTableTr {
    background-color: rgba(64, 158, 255, 0.1);
  }
  .scroll-table-container:hover tbody {
    overflow: hidden;
  }
  .echart-fill {
    width: 100%;
    height: 100%;
  }
  .chart-filter-tabs {
    display: flex;
    gap: 0.6vh;
    margin: 0 0 0.5vh 0;
    justify-self: end;
  }
  .cf-tab {
    font-size: 1.1vh;
    color: rgba(184, 200, 224, 0.68);
    background: rgba(18, 56, 106, 0.65);
    border: 0.1vh solid rgba(64, 158, 255, 0.25);
    padding: 0.3vh 0.9vh;
    line-height: 1;
    cursor: pointer;
  }
  .cf-tab.active {
    color: #d9ecff;
    background: rgba(0, 108, 208, 0.85);
    border-color: rgba(64, 158, 255, 0.65);
  }
  .chart-unit-row {
    display: flex;
    justify-content: space-between;
    font-size: 1.2vh;
    color: rgba(208, 231, 255, 0.88);
    margin-bottom: 0.4vh;
    padding: 0 0.2vh;
  }
  .dot-legend::before {
    content: "";
    display: inline-block;
    width: 0.8vh;
    height: 0.8vh;
    background: #65a0ff;
    margin-right: 0.6vh;
  }
  .chart-mini-title {
    display: flex;
    align-items: center;
    gap: 0.8vh;
    font-size: 1.8vh;
    color: #d9ecff;
  }
  /* é¢æ¿åº•部合计行 */
  .panel-summary-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 0.8vh 1.2vh;
    /* margin-top: 0.8vh; */
    background: #041e3c;
    border-top: 0.1vh solid rgba(64, 158, 255, 0.25);
    border-radius: 0 0 0.4vh 0.4vh;
    width: 100%;
    position: absolute;
    bottom: 0;
  }
  .summary-label {
    font-size: 1.3vh;
    font-weight: 700;
    color: #b8c8e0;
  }
  .summary-value {
    font-size: 1.4vh;
    font-weight: 800;
    color: #00a4ed;
    margin-right: 3.8vh;
    text-shadow: 0 0 1vh rgba(0, 164, 237, 0.5);
  }
  .summary-value2 {
    font-size: 1.4vh;
    font-weight: 800;
    color: #00a4ed;
    margin-right: 5.8vh;
    text-shadow: 0 0 1vh rgba(0, 164, 237, 0.5);
  }
  .diamond {
    width: 1vh;
    height: 1vh;
    background: #1e8bff;
    transform: rotate(45deg);
    display: inline-block;
  }
  .chart-unit-single {
    justify-content: flex-start;
    margin-bottom: 0.2vh;
  }
  .bi-panel-top-left .echart-fill,
  .bi-panel-bottom-left .echart-fill {
    height: 24vh;
  }
  .bi-panel-bottom-right .echart-fill {
    height: calc(100% - 2.8vh);
  }
  .bi-panel-bottom-center .echart-fill,
  .bi-panel-top-right .echart-fill {
    height: calc(100% - 4.4vh);
  }
  .bi-panel-top-left {
    grid-column: 1;
    grid-row: 1;
    position: relative;
  }
  .bi-panel-top-right {
    grid-column: 3;
    grid-row: 1;
    position: relative;
  }
  .bi-panel-bottom-left {
    grid-column: 1;
    grid-row: 2;
    overflow-y: auto;
  }
  .bi-panel-bottom-left::-webkit-scrollbar {
    width: 0vh;
    height: 0vh;
  }
  .bi-panel-bottom-center {
    grid-column: 2;
    grid-row: 2;
  }
  .bi-panel-bottom-right {
    grid-column: 3;
    grid-row: 2;
    overflow-y: auto;
  }
  .bi-panel-bottom-right::-webkit-scrollbar {
    width: 0vh;
    height: 0vh;
  }
  /* ä¸­å¿ƒçŽ¯æµ®å±‚ï¼ˆç»å¯¹å®šä½åœ¨ç½‘æ ¼ä¸Šæ–¹ï¼‰ */
  .center-ring {
    grid-column: 2;
    grid-row: 1 / span 2;
    position: absolute;
    background: url("@/assets/BI/imageSS@2x.png") no-repeat bottom center;
    background-size: 100% 30%;
    left: 25%;
    top: 25%;
    transform: translate(-50%, -50%);
    width: 60vh;
    height: 40.5vh;
    z-index: 3;
    pointer-events: none;
  }
  .center-ring-box {
    position: absolute;
    /* inset: 0; */
    height: 100%;
    width: 100%;
    /* background-color: #fff; */
    background: url("@/assets/BI/imageSStop.png") no-repeat center center;
    background-size: 80% 90%;
  }
  .center-ring-bg {
    width: 100%;
    height: 100%;
    object-fit: contain;
    filter: drop-shadow(0 0 2vh rgba(0, 164, 237, 0.35));
  }
  .center-ring-content {
    position: absolute;
    inset: 0;
  }
  .center-ring-content::before,
  .center-ring-content::after {
    content: "";
    position: absolute;
    left: 50%;
    top: 56%;
    width: 37vh;
    height: 14.6vh;
    transform: translate(-50%, -50%) rotate(-18deg);
    border: 0.2vh solid rgba(40, 186, 255, 0.45);
    border-radius: 50%;
    filter: drop-shadow(0 0 0.8vh rgba(0, 164, 237, 0.35));
    opacity: 0.7;
  }
  .center-ring-content::after {
    width: 36vh;
    height: 15vh;
    transform: translate(-50%, -50%) rotate(26deg);
    border-color: rgba(80, 220, 255, 0.35);
    opacity: 0.55;
  }
  .center-ring-title {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    font-size: 3.6vh;
    line-height: 1.05;
    text-align: center;
    font-weight: 900;
    color: #eaf6ff;
    text-shadow: 0 0 2.2vh rgba(0, 164, 237, 0.55);
    z-index: 2;
  }
  .center-ring-title::before {
    content: "";
    position: absolute;
    left: 50%;
    top: 50%;
    width: 15.5vh;
    height: 15.5vh;
    transform: translate(-50%, -50%);
    background: radial-gradient(
      circle,
      rgba(43, 199, 255, 0.26) 0%,
      rgba(8, 28, 61, 0.86) 70%
    );
    border: 0.2vh solid rgba(39, 198, 255, 0.46);
    border-radius: 50%;
    box-shadow: 0 0 2vh rgba(0, 164, 237, 0.45),
      inset 0 0 2.6vh rgba(0, 164, 237, 0.2);
    z-index: -1;
  }
  .center-metric {
    position: absolute;
    width: 15.5vh;
    z-index: 3;
    text-align: center;
    height: 12vh;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
  }
  .center-metric-label {
    font-size: 1.2vh;
    font-weight: 500;
    color: rgba(234, 246, 255, 0.9);
    margin-top: 0;
  }
  .center-metric-value {
    font-size: 3.4vh;
    font-weight: 800;
    color: #eaf6ff;
    text-shadow: 0 0 0.8vh rgba(0, 229, 255, 0.22);
    line-height: 1;
  }
  .center-metric-unit {
    margin-top: 0;
    font-size: 1.2vh;
    color: rgba(208, 231, 255, 0.85);
  }
  .m1 {
    top: 2.5vh;
    left: 4.8vh;
    text-align: left;
  }
  .m2 {
    top: 4.1vh;
    right: 8.6vh;
    text-align: right;
  }
  .m3 {
    bottom: 7.9vh;
    left: 4vh;
    text-align: left;
  }
  .m4 {
    bottom: 7vh;
    right: 5.4vh;
    text-align: right;
  }
  @media (max-width: 1100px) {
    .bi-topbar-content {
      padding: 0 1.4vh;
    }
    .center-ring {
      left: 45.2%;
      width: 33vh;
      height: 24.5vh;
      top: 2.4vh;
    }
    .center-ring-title {
      top: 50%;
      font-size: 2.8vh;
      transform: translate(-50%, -50%);
    }
    .center-metric {
      height: 10.5vh;
    }
    .m1 {
      top: 5.2vh;
      left: 4.2vh;
    }
    .m2 {
      top: 5.4vh;
      right: 4.2vh;
    }
    .m3 {
      bottom: 6.2vh;
      left: 4.8vh;
    }
    .m4 {
      bottom: 6.8vh;
      right: 4.4vh;
    }
  }
  .scroll-table-content {
    height: 39vh;
    overflow: auto;
  }
  .scroll-table-content::-webkit-scrollbar {
    width: 0;
    height: 0;
    background-color: transparent;
  }
  .total-row {
    position: absolute;
    bottom: 0vh;
    left: 0;
    width: 100%;
    display: flex;
    height: 3.5vh;
    justify-content: space-around;
    align-items: center;
    background-color: #081843;
  }
  .stats-grid {
  .total-cell {
    width: 20%;
    font-size: 1.4vh;
    margin-bottom: 0.5vh;
    line-height: 3.5vh;
    padding-left: 0.8vh;
    color: #eaf6ff;
    text-shadow: 0 0 0.8vh rgba(0, 229, 255, 0.22);
    text-align: left;
    color: #c3c3c3;
  }
  .total-cell2 {
    width: 20%;
    font-size: 1.4vh;
    margin-bottom: 0.5vh;
    line-height: 3.5vh;
    color: #eaf6ff;
    text-shadow: 0 0 0.8vh rgba(0, 229, 255, 0.22);
    text-align: left;
    color: #c3c3c3;
  }
    /* ææ–™ä¿¡æ¯å¡ç‰‡ */
  .material-info-card {
    display: flex;
    align-items: center;
    padding: 1.2vh 1.6vh;
    background: rgba(0, 164, 237, 0.1);
    border-radius: 0.8vh;
    margin: 1.2vh 1.6vh;
  }
  .material-icon {
    width: 4vh;
    height: 4vh;
    background: rgba(0, 164, 237, 0.2);
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    margin-right: 1.2vh;
    color: #00a4ed;
  }
  .material-details {
    flex: 1;
    padding: 15px;
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    grid-template-rows: repeat(2, 1fr);
    gap: 15px;
  }
  .material-name {
    font-size: 1.3vh;
    font-weight: 600;
    color: #d0e7ff;
    margin-bottom: 0.6vh;
  }
  .material-stats {
    display: flex;
    gap: 1.6vh;
  }
  .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;
    gap: 0.4vh;
  }
  .stat-label {
    font-size: 13px;
    color: #606266;
    margin-bottom: 8px;
    font-size: 1vh;
    opacity: 0.7;
  }
  .stat-value {
    font-size: 20px;
    font-size: 1.2vh;
    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);
    color: #00a4ed;
  }
  .stat-unit {
    font-size: 11px;
    color: #909399;
    font-size: 1vh;
    opacity: 0.7;
  }
  /* è¡¨æ ¼æ ·å¼ */
  :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>
</style>
src/views/reportAnalysis/salesStatistics/index.vue
@@ -199,7 +199,7 @@
        </div>
        <div class="bi-panel-body">
          <div class="chart-unit-row chart-unit-single">
            <span>单位:人</span>
            <span>单位:家</span>
          </div>
          <div ref="productTypeTrendChart"
               class="echart-fill"></div>
@@ -1160,7 +1160,7 @@
        formatter: function (params) {
          let result = params[0].name + "<br/>";
          params.forEach(param => {
            result += `${param.marker}${param.seriesName}: ${param.value} äºº<br/>`;
            result += `${param.marker}${param.seriesName}: ${param.value} å®¶<br/>`;
          });
          return result;
        },
@@ -1880,12 +1880,12 @@
  }
  /* .scroll-table tbody tr:nth-child(odd) {
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  background-color: rgba(64, 158, 255, 0.05);
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  }
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      background-color: rgba(64, 158, 255, 0.05);
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      }
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                .scroll-table tbody tr:nth-child(even) {
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    background-color: rgba(64, 158, 255, 0.1);
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      } */
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    .scroll-table tbody tr:nth-child(even) {
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        background-color: rgba(64, 158, 255, 0.1);
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          } */
  .oddTableTr {
    background-color: rgba(64, 158, 255, 0.05);
  }