zhangwencui
9 小时以前 63bc8594046177d976d0436c709e928d71bbba0d
追踪进度
已修改4个文件
933 ■■■■ 文件已修改
src/views/productionManagement/productionReporting/detailDialog.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/productionPlan/productionPlan/index.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/productionPlan/trackProgress/index.vue 717 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/reportAnalysis/unitEnergyConsumption/index.vue 212 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/productionManagement/productionReporting/detailDialog.vue
@@ -28,7 +28,7 @@
      <div class="detail-section"
           v-if="detailData.productionProductRouteItemDtoList && detailData.productionProductRouteItemDtoList.length > 0">
        <h3 class="section-title">工序信息</h3>
        <div v-for="(process, index) in detailData.productionProductRouteItemDtoList"
        <div v-for="(process) in detailData.productionProductRouteItemDtoList"
             :key="process.id"
             class="process-item">
          <div class="process-header">
src/views/productionPlan/productionPlan/index.vue
@@ -672,7 +672,7 @@
    router.push({
      path: "/productionPlan/trackProgress",
      query: {
        row: encodeURIComponent(JSON.stringify(row)),
        applyNo: encodeURIComponent(row.applyNo),
      },
    });
  };
src/views/productionPlan/trackProgress/index.vue
@@ -1,11 +1,24 @@
<template>
  <div class="app-container">
    <PageHeader content="生产计划追踪进度">
    <PageHeader v-if="applyNo"
                content="生产计划追踪进度">
    </PageHeader>
    <el-card style="height:82vh;overflow:auto;">
      <template #header>
        <div class="card-header">
          <span>申请单编号 - {{ rowData.applyNo || '' }}</span>
          <el-form :inline="true"
                   :model="searchForm"
                   class="search-form">
            <el-form-item label="申请单编号">
              <el-input v-model="searchForm.applyNo"
                        placeholder="请输入申请单编号"
                        style="width: 400px;"></el-input>
            </el-form-item>
            <el-form-item>
              <el-button type="primary"
                         @click="handleSearch">搜索</el-button>
            </el-form-item>
          </el-form>
        </div>
      </template>
      <!-- 基础信息 -->
@@ -57,8 +70,7 @@
                  <el-link v-if="$index!=0"
                           @click="handleClickStep(row)"
                           type="primary">{{ row.step }}</el-link>
                  <span v-else
                        @click="handleClickStep(row)">{{ row.step }}</span>
                  <span v-else>{{ row.step }}</span>
                </template>
              </el-table-column>
              <el-table-column prop="status"
@@ -127,6 +139,156 @@
        </div> -->
      </div>
    </el-card>
    <!-- 生产报工详情弹窗 -->
    <el-dialog v-model="detailDialogVisible"
               :title="'生产报工详情'"
               width="1000px"
               :close-on-click-modal="false"
               custom-class="custom-dialog">
      <div class="detail-container">
        <!-- 基础信息 -->
        <div class="detail-section">
          <h3 class="section-title">基础信息</h3>
          <el-descriptions :column="3"
                           border>
            <el-descriptions-item label="生产订单号">{{ detailData.npsNo || '-' }}</el-descriptions-item>
            <el-descriptions-item label="班组"><el-tag :type="detailData.schedule == '白班' ? 'primary' : 'warning'">{{ detailData.schedule || '-' }}</el-tag></el-descriptions-item>
            <el-descriptions-item label="岗位人员">{{ detailData.postName || '-' }}</el-descriptions-item>
            <el-descriptions-item label="产品编码">{{ detailData.materialCode || '-' }}</el-descriptions-item>
            <el-descriptions-item label="产品名称">{{ detailData.productName || '-' }}</el-descriptions-item>
            <el-descriptions-item label="规格">{{ detailData.model || '-' }}</el-descriptions-item>
            <el-descriptions-item label="合格数量"><span class="num2">{{ detailData.qualifiedQuantity || 0 }}</span> <span class="unit">方</span></el-descriptions-item>
            <el-descriptions-item label="不合格数量"><span class="num3">{{ detailData.unqualifiedQuantity || 0 }}</span> <span class="unit">方</span></el-descriptions-item>
            <el-descriptions-item label="总数量"><span class="num1">{{ detailData.quantity || 0 }}</span> <span class="unit">方</span></el-descriptions-item>
            <el-descriptions-item label="报工时间">{{ formatTime(detailData.reportingTime) }}</el-descriptions-item>
            <el-descriptions-item label="创建时间">{{ formatTime(detailData.createTime) }}</el-descriptions-item>
            <el-descriptions-item label="更新时间">{{ formatTime(detailData.updateTime) }}</el-descriptions-item>
          </el-descriptions>
        </div>
        <!-- 工序信息 -->
        <div class="detail-section"
             v-if="detailData.productionProductRouteItemDtoList && detailData.productionProductRouteItemDtoList.length > 0">
          <h3 class="section-title">工序信息</h3>
          <div v-for="(process) in detailData.productionProductRouteItemDtoList"
               :key="process.id"
               class="process-item">
            <div class="process-header">
              <h4 class="process-title">{{ process.processName || '-' }}</h4>
              <div class="process-info">
                <span class="process-label">岗位人员:{{ process.postName || '-' }}</span>
                <span class="process-label">工序ID:{{ process.processNo || '-' }}</span>
              </div>
            </div>
            <!-- 工序基本信息 -->
            <div class="process-details">
              <el-descriptions :column="2"
                               border>
                <el-descriptions-item label="设备异常情况">{{ process.equipmentMalfunction || '-' }}</el-descriptions-item>
                <el-descriptions-item label="当班设备处置">{{ process.equipmentDisposal || '-' }}</el-descriptions-item>
                <el-descriptions-item label="工艺人员交待"
                                      :span="2">{{ process.processExplained || '-' }}</el-descriptions-item>
              </el-descriptions>
            </div>
            <!-- 工序参数 -->
            <div v-if="process.productionProductRouteItemParamDtoList && process.productionProductRouteItemParamDtoList.length > 0">
              <!-- BOM信息 -->
              <div class="param-section"
                   v-if="getBomList(process.productionProductRouteItemParamDtoList).length > 0">
                <h5 class="param-title">投入品信息</h5>
                <el-table :data="getBomList(process.productionProductRouteItemParamDtoList)"
                          style="width: 100%"
                          size="small">
                  <el-table-column prop="paramName"
                                   label="产品名称"
                                   min-width="120"></el-table-column>
                  <el-table-column prop="model"
                                   label="规格型号"
                                   min-width="120"></el-table-column>
                  <el-table-column prop="productValue"
                                   label="投入量"
                                   min-width="100"></el-table-column>
                  <el-table-column prop="unit"
                                   label="单位"
                                   width="80"></el-table-column>
                </el-table>
              </div>
              <!-- 参数信息 -->
              <div class="param-section"
                   v-if="getParamList(process.productionProductRouteItemParamDtoList).length > 0">
                <h5 class="param-title">生产记录</h5>
                <el-card v-for="group in getParamGroups(process.productionProductRouteItemParamDtoList)"
                         :key="group.sourceSort"
                         class="detail-card"
                         style="margin-top: 10px;">
                  <template #header>
                    <div class="card-header">
                      <span v-if="Object.keys(getParamGroups(process.productionProductRouteItemParamDtoList)).length > 1">生产记录组 - {{ group.sourceSort }}</span>
                      <span v-else>生产记录</span>
                    </div>
                  </template>
                  <el-table :data="group.items"
                            style="width: 100%"
                            :row-class-name="rowClassName">
                    <el-table-column prop="paramName"
                                     label="指标" />
                    <el-table-column prop="unit"
                                     label="单位"
                                     width="100">
                      <template #default="scope">
                        {{ scope.row.unit || "/" }}
                      </template>
                    </el-table-column>
                    <el-table-column prop="standardText"
                                     label="标准值" />
                    <el-table-column prop="paramValue"
                                     label="实际值" />
                    <el-table-column prop="result"
                                     label="结果"
                                     width="100">
                      <template #default="scope">
                        <el-tag :type="scope.row.result === '合格' ? 'success' : 'danger'">
                          {{ scope.row.result }}
                        </el-tag>
                      </template>
                    </el-table-column>
                  </el-table>
                </el-card>
              </div>
            </div>
            <!-- 上传文件 -->
            <div class="file-section"
                 v-if="process.fileList && process.fileList.length > 0">
              <h5 class="file-title">上传文件</h5>
              <div class="file-grid">
                <div v-for="file in process.fileList"
                     :key="file.id"
                     class="file-item">
                  <el-image style="width: 100px; height: 100px"
                            v-if="file.fileUrl"
                            :src="baseUrl + file.fileUrl"
                            :zoom-rate="1.2"
                            :max-scale="7"
                            :alt="file.fileName"
                            :min-scale="0.2"
                            :preview-src-list="formatFileList(process.fileList)"
                            show-progress
                            :initial-index="4"
                            fit="cover" />
                  <div class="file-info">
                    <span class="file-name">{{ file.fileName || '-' }}</span>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
      <template #footer>
        <div class="dialog-footer">
          <el-button @click="detailDialogVisible = false">关闭</el-button>
        </div>
      </template>
    </el-dialog>
  </div>
</template>
@@ -134,6 +296,7 @@
  import { ref, reactive, onMounted } from "vue";
  import { ElMessage } from "element-plus";
  import { useRouter, useRoute } from "vue-router";
  import dayjs from "dayjs";
  const router = useRouter();
  const route = useRoute();
@@ -149,6 +312,16 @@
    progressDetails: [],
    remark: "",
  });
  // 搜索表单
  const searchForm = reactive({
    applyNo: "",
  });
  // 生产报工详情弹窗
  const detailDialogVisible = ref(false);
  const detailData = ref({});
  const baseUrl = import.meta.env.VITE_APP_BASE_API;
  // 获取状态类型
  const getStatusType = status => {
@@ -261,6 +434,30 @@
    router.push("/productionPlan/productionPlan");
  };
  // 处理搜索
  const handleSearch = () => {
    const applyNo = searchForm.applyNo.trim();
    if (!applyNo) {
      ElMessage.warning("请输入申请单编号");
      return;
    }
    // 这里可以添加搜索逻辑,例如调用API获取数据
    // 目前使用模拟数据
    ElMessage.success(`搜索申请单编号: ${applyNo}`);
    // 模拟搜索结果
    rowData.applyNo = applyNo;
    rowData.productName = "搜索结果产品";
    rowData.model = "搜索结果规格";
    rowData.materialCode = "MAT-" + applyNo;
    rowData.assignedQuantity = 100;
    rowData.status = 1;
    trackProgressForm.progressDetails = generateProgressDetails(1);
    trackProgressForm.completionRate = calculateCompletionRate(
      trackProgressForm.progressDetails
    );
    rowData.orderList = generateOrderList();
  };
  // 生成模拟订单数据
  const generateOrderList = () => {
    return [
@@ -291,24 +488,215 @@
    ];
  };
  // 处理点击步骤查看详情
  const handleClickStep = row => {
    // 这里可以添加获取报工详情数据的逻辑
    // 目前使用模拟数据
    detailData.value = {
      npsNo: "NPS-2026-001",
      schedule: "白班",
      postName: "张三",
      materialCode: rowData.materialCode || "MAT-001",
      productName: rowData.productName || "产品A",
      model: rowData.model || "规格A",
      qualifiedQuantity: 100,
      unqualifiedQuantity: 5,
      quantity: 105,
      reportingTime: new Date(),
      createTime: new Date(),
      updateTime: new Date(),
      productionProductRouteItemDtoList: [
        {
          id: 1,
          processName: "工序1",
          postName: "张三",
          processNo: "PROC-001",
          equipmentMalfunction: "无异常",
          equipmentDisposal: "正常运行",
          processExplained: "按照标准工艺操作",
          productionProductRouteItemParamDtoList: [
            {
              id: 11,
              paramName: "原材料A",
              model: "型号A",
              productValue: "100",
              unit: "kg",
              bomId: 101,
            },
            {
              id: 12,
              paramName: "温度",
              paramValue: "25",
              unit: "°C",
              sourceSort: 1,
              valueMode: 2,
              minValue: 20,
              maxValue: 30,
            },
            {
              id: 13,
              paramName: "压力",
              paramValue: "1.5",
              unit: "MPa",
              sourceSort: 1,
              valueMode: 2,
              minValue: 1.0,
              maxValue: 2.0,
            },
            {
              id: 14,
              paramName: "转速",
              paramValue: "1500",
              unit: "rpm",
              sourceSort: 2,
              valueMode: 1,
              standardValue: "1500",
            },
            {
              id: 15,
              paramName: "电流",
              paramValue: "12",
              unit: "A",
              sourceSort: 2,
              valueMode: 2,
              minValue: 10,
              maxValue: 15,
            },
          ],
          fileList: [
            {
              id: 21,
              fileName: "生产记录1.jpg",
              fileUrl: "/upload/files/20260301/12345.jpg",
              fileSize: 1024000,
            },
            {
              id: 22,
              fileName: "生产记录2.jpg",
              fileUrl: "/upload/files/20260301/67890.jpg",
              fileSize: 2048000,
            },
          ],
        },
      ],
    };
    detailDialogVisible.value = true;
  };
  // 格式化时间
  const formatTime = time => {
    return time ? dayjs(time).format("YYYY-MM-DD HH:mm:ss") : "-";
  };
  // 格式化文件列表
  const formatFileList = fileList => {
    return fileList.map(file => ({
      name: file.fileName,
      url: baseUrl + file.fileUrl,
      size: file.fileSize,
    }));
  };
  // 获取BOM列表
  const getBomList = paramList => {
    return paramList.filter(item => item.bomId);
  };
  // 获取参数列表
  const getParamList = paramList => {
    return paramList.filter(item => !item.bomId);
  };
  // 按sourceSort分组参数
  const getParamGroups = paramList => {
    const params = getParamList(paramList);
    const groups = {};
    params.forEach(param => {
      const sort = param.sourceSort || 1;
      if (!groups[sort]) {
        groups[sort] = [];
      }
      // 计算结果
      let result = "合格";
      let standardText = "";
      if (param.valueMode === 1) {
        // 单值比较
        if (param.standardValue !== null && param.standardValue !== undefined) {
          standardText = param.standardValue;
          if (param.paramValue !== param.standardValue) {
            result = "不合格";
          }
        } else {
          standardText = "-";
          result = "合格";
        }
      } else if (param.valueMode === 2) {
        // 区间比较
        if (param.minValue !== null || param.maxValue !== null) {
          standardText =
            (param.minValue ? param.minValue : "-∞") +
            "~" +
            (param.maxValue ? param.maxValue : "+∞");
          if (
            param.paramValue < param.minValue ||
            param.paramValue > param.maxValue
          ) {
            result = "不合格";
          }
        } else {
          standardText = "-";
          result = "合格";
        }
      } else {
        // 默认情况
        standardText = "-";
        result = "合格";
      }
      groups[sort].push({
        ...param,
        standardText,
        result,
      });
    });
    // 转换为数组格式
    return Object.entries(groups).map(([key, items]) => ({
      sourceSort: key,
      items,
    }));
  };
  // 为不合格的行添加样式
  const rowClassName = ({ row }) => {
    return row.result === "不合格" ? "warning-row" : "";
  };
  const applyNo = ref(null);
  // 页面加载时获取数据
  onMounted(() => {
    // 从路由参数中获取数据
    const data = route.query.row
      ? JSON.parse(decodeURIComponent(route.query.row))
    applyNo.value = route.query.applyNo
      ? decodeURIComponent(route.query.applyNo)
      : null;
    if (data) {
      // 赋值给rowData
      Object.assign(rowData, data);
      // 赋值给表单数据
      trackProgressForm.materialCode = data.materialCode;
      trackProgressForm.currentStatus = data.status;
      trackProgressForm.progressDetails = generateProgressDetails(data.status);
      trackProgressForm.completionRate = calculateCompletionRate(
        trackProgressForm.progressDetails
      );
      trackProgressForm.remark = "";
    }
    searchForm.applyNo = applyNo.value;
    // 生成假数据
    rowData.applyNo = applyNo.value || "APPLY-2026-001";
    rowData.productName = "测试产品";
    rowData.model = "测试规格";
    rowData.materialCode = "MAT-001";
    rowData.assignedQuantity = 233;
    rowData.status = 1;
    // 赋值给表单数据
    trackProgressForm.materialCode = rowData.materialCode;
    trackProgressForm.currentStatus = rowData.status;
    trackProgressForm.progressDetails = generateProgressDetails(rowData.status);
    trackProgressForm.completionRate = calculateCompletionRate(
      trackProgressForm.progressDetails
    );
    trackProgressForm.remark = "";
    // 生成模拟订单数据
    rowData.orderList = generateOrderList();
  });
@@ -326,6 +714,14 @@
    justify-content: space-between;
    align-items: center;
    padding: 0 10px;
  }
  .search-form {
    width: 100%;
  }
  .search-form .el-form-item {
    margin-right: 10px;
  }
  .action-buttons {
@@ -468,4 +864,289 @@
    border-radius: 12px;
    padding: 2px 10px;
  }
  /* 弹窗样式 */
  .detail-container {
    max-height: 600px;
    overflow-y: auto;
    padding: 0 16px;
  }
  .process-item {
    margin-bottom: 24px;
    padding: 20px;
    background-color: #ffffff;
    border-radius: 8px;
    border: 1px solid #ebeef5;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
  }
  .process-header {
    margin-bottom: 20px;
    padding-bottom: 12px;
    border-bottom: 1px solid #f0f2f5;
  }
  .process-title {
    font-size: 15px;
    font-weight: 600;
    margin-bottom: 12px;
    color: #1a1a1a;
    display: flex;
    align-items: center;
  }
  .process-title::before {
    content: "";
    display: inline-block;
    width: 4px;
    height: 16px;
    background-color: #409eff;
    margin-right: 8px;
    border-radius: 2px;
  }
  .process-info {
    display: flex;
    gap: 20px;
    font-size: 13px;
    color: #606266;
  }
  .process-label {
    padding: 4px 12px;
    background-color: #ecf5ff;
    border-radius: 4px;
    color: #409eff;
    font-weight: 500;
  }
  .process-details {
    margin-bottom: 20px;
  }
  .param-section {
    margin-bottom: 20px;
    background-color: #f9f9f9;
    border-radius: 6px;
    padding: 16px;
    border: 1px solid #f0f2f5;
  }
  .param-title {
    font-size: 14px;
    font-weight: 600;
    margin-bottom: 14px;
    color: #1a1a1a;
    padding-bottom: 8px;
    border-bottom: 1px solid #e8e8e8;
  }
  .file-section {
    margin-top: 20px;
    background-color: #f9f9f9;
    border-radius: 6px;
    padding: 16px;
    border: 1px solid #f0f2f5;
  }
  .file-title {
    font-size: 14px;
    font-weight: 600;
    margin-bottom: 14px;
    color: #1a1a1a;
    padding-bottom: 8px;
    border-bottom: 1px solid #e8e8e8;
  }
  .file-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
    gap: 16px;
  }
  .file-item {
    display: flex;
    flex-direction: column;
    align-items: center;
    background-color: #ffffff;
    border: 1px solid #e8e8e8;
    border-radius: 6px;
    padding: 10px;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
    transition: all 0.3s ease;
  }
  .file-item:hover {
    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
    border-color: #409eff;
    transform: translateY(-2px);
  }
  .file-info {
    width: 100%;
    text-align: center;
  }
  .file-name {
    font-size: 12px;
    color: #606266;
    word-break: break-all;
    line-height: 1.4;
  }
  .param-group {
    margin-bottom: 16px;
    padding: 14px;
    background-color: #ffffff;
    border-radius: 6px;
    border: 1px solid #e8e8e8;
  }
  .group-header {
    margin-bottom: 12px;
    padding-bottom: 8px;
    border-bottom: 1px solid #f0f2f5;
  }
  .num1 {
    color: #1107cc;
    font-weight: 600;
  }
  .num2 {
    color: #0fcf25;
    font-weight: 600;
  }
  .num3 {
    color: #d31818;
    font-weight: 600;
  }
  .group-title {
    font-size: 14px;
    font-weight: 600;
    color: #303133;
  }
  .param-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: 16px;
  }
  .param-item {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 8px 0;
    border-bottom: 1px solid #f5f7fa;
  }
  .param-item:last-child {
    border-bottom: none;
  }
  .param-label {
    font-size: 13px;
    color: #606266;
    min-width: 100px;
    font-weight: 500;
  }
  .param-value {
    font-size: 13px;
    color: #1a1a1a;
    font-weight: 600;
    flex: 1;
  }
  .param-unit {
    font-size: 12px;
    color: #909399;
    background-color: #f0f2f5;
    padding: 2px 6px;
    border-radius: 3px;
  }
  .dialog-footer {
    text-align: center;
    padding: 20px;
    border-top: 1px solid #ebeef5;
  }
  .dialog-footer .el-button {
    min-width: 100px;
    padding: 8px 20px;
  }
  /* 自定义对话框样式 */
  :deep(.custom-dialog) {
    border-radius: 12px;
    overflow: hidden;
  }
  :deep(.custom-dialog .el-dialog__header) {
    background-color: #f5f7fa;
    padding: 20px;
    border-bottom: 1px solid #ebeef5;
  }
  :deep(.custom-dialog .el-dialog__title) {
    font-size: 18px;
    font-weight: 600;
    color: #1a1a1a;
  }
  :deep(.custom-dialog .el-dialog__body) {
    padding: 20px;
  }
  /* 表格样式优化 */
  :deep(.el-table) {
    border-radius: 6px;
    overflow: hidden;
  }
  :deep(.el-table th) {
    background-color: #f5f7fa;
    font-weight: 600;
    color: #303133;
  }
  :deep(.el-table tr:hover > td) {
    background-color: #ecf5ff !important;
  }
  /* 描述列表样式优化 */
  :deep(.el-descriptions) {
    border-radius: 6px;
    overflow: hidden;
  }
  :deep(.el-descriptions__label) {
    font-weight: 500;
    color: #606266;
  }
  :deep(.el-descriptions__content) {
    color: #1a1a1a;
    font-weight: 500;
  }
  /* 不合格行样式 */
  :deep(.el-table .warning-row) {
    background-color: #fef0f0 !important;
  }
  .detail-card {
    border-radius: 8px;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
  }
  .card-header {
    font-weight: 600;
    color: #303133;
  }
</style>
src/views/reportAnalysis/unitEnergyConsumption/index.vue
@@ -89,53 +89,48 @@
      <el-table :data="tableData"
                v-loading="tableLoading"
                border>
        <el-table-column prop="energyType"
                         label="能耗"
                         width="100"
                         align="center">
        <el-table-column prop="meterReadingDate"
                         label="日期"
                         align="center"
                         width="120" />
        <el-table-column prop="type"
                         label="类型"
                         align="center"
                         width="100">
          <template #default="scope">
            <el-tag :type="getEnergyTypeType(scope.row.energyType)">
              {{ scope.row.energyType }}
            <el-tag :type="scope.row.type === '生产' ? 'primary' : 'success'">
              {{ scope.row.type }}
            </el-tag>
          </template>
        </el-table-column>
        <el-table-column prop="unit"
                         label="单位"
                         width="120"
                         align="center" />
        <el-table-column label="月度数据"
                         v-if="searchForm.timeDimension === 'month'">
          <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="monthlyConsumption"
                           label="月度累计用量/月度累计产量"
                           align="right">
            <template #default="scope">
              <span class="data-value">{{ scope.row.monthlyConsumption }}/{{ scope.row.monthlyProduction }}</span>
            </template>
          </el-table-column>
        <el-table-column prop="energyTyep"
                         label="能耗类型"
                         align="center"
                         width="100">
          <template #default="scope">
            <el-tag :type="getEnergyTypeType(scope.row.energyTyep)">
              {{ scope.row.energyTyep }}
            </el-tag>
          </template>
        </el-table-column>
        <el-table-column label="年度数据"
                         v-if="searchForm.timeDimension === 'year'">
          <el-table-column prop="annualUnitConsumption"
                           label="年度累计单耗"
                           align="right">
            <template #default="scope">
              <span class="data-value">{{ scope.row.annualUnitConsumption }}</span>
            </template>
          </el-table-column>
          <el-table-column prop="annualConsumption"
                           label="年度累计用量/年度累计产量"
                           align="right">
            <template #default="scope">
              <span class="data-value">{{ scope.row.annualConsumption }}/{{ scope.row.annualProduction }}</span>
            </template>
          </el-table-column>
        <el-table-column prop="consumption"
                         label="用量"
                         align="right"
                         width="120" />
        <el-table-column prop="cost"
                         label="成本"
                         align="right"
                         width="120">
          <template #default="scope">
            <span class="data-value">¥{{ scope.row.cost }}</span>
          </template>
        </el-table-column>
        <el-table-column prop="unitConsumption"
                         label="单耗"
                         align="right">
          <template #default="scope">
            <span class="data-value">{{ scope.row.unitConsumption }}</span>
          </template>
        </el-table-column>
      </el-table>
    </div>
@@ -147,6 +142,7 @@
  import { ElMessage } from "element-plus";
  import { TrendCharts, List } from "@element-plus/icons-vue";
  import * as echarts from "echarts";
  import { energyConsumptionDetailStatistics } from "@/api/energyManagement/energyType";
  // 搜索表单
  const searchForm = reactive({
@@ -229,12 +225,12 @@
    const energyTypes = ["水", "电", "蒸汽"];
    energyTypes.forEach(type => {
      const typeData = data.find(item => item.energyType === type);
      if (typeData && typeData[seriesDataKey]) {
      const typeData = data.find(item => item.energyTyep === type);
      if (typeData) {
        series.push({
          name: type,
          type: "line",
          data: typeData[seriesDataKey].map(seriesDataMap),
          data: typeData.cost,
          smooth: true,
          symbol: "circle",
          symbolSize: 8,
@@ -302,12 +298,49 @@
  const handleQuery = () => {
    tableLoading.value = true;
    // 模拟接口调用
    setTimeout(() => {
      generateMockData();
      tableLoading.value = false;
      updateChart();
    }, 500);
    const params = {
      type: "",
      state: searchForm.timeDimension === "year" ? "年" : "月",
    };
    if (searchForm.energyType && searchForm.energyType !== "全部") {
      params.type = searchForm.energyType;
    }
    if (searchForm.timeDimension === "year") {
      params.startDate = searchForm.year + "-01-01";
      params.endDate = searchForm.year + "-12-31";
      params.days = 365;
    } else if (searchForm.timeDimension === "month") {
      const year = searchForm.year;
      const month = searchForm.month;
      const lastDay = new Date(year, month, 0).getDate();
      params.startDate = `${year}-${String(month).padStart(2, "0")}-01`;
      params.endDate = `${year}-${String(month).padStart(2, "0")}-${String(
        lastDay
      ).padStart(2, "0")}`;
      params.days = lastDay;
    }
    energyConsumptionDetailStatistics(params)
      .then(res => {
        if (res.code === 200) {
          const data = res.data;
          tableData.value = data.energyCostDtos || [];
          updateChart();
        } else {
          ElMessage.error(res.message || "获取数据失败");
          tableData.value = [];
        }
      })
      .catch(err => {
        console.error("获取数据异常:", err);
        ElMessage.error("系统异常,获取数据失败");
        tableData.value = [];
      })
      .finally(() => {
        tableLoading.value = false;
      });
  };
  // 重置
@@ -322,83 +355,6 @@
  // 导出
  const handleExport = () => {
    ElMessage.success("报表导出成功");
  };
  // 生成假数据
  const generateMockData = () => {
    const energyTypes = [
      {
        energyType: "水",
        unit: "吨/立方米",
        monthlyUnitConsumption: (Math.random() * 0.5 + 0.8).toFixed(4),
        monthlyConsumption: Math.floor(Math.random() * 5000 + 10000),
        monthlyProduction: Math.floor(Math.random() * 10000 + 20000),
        annualUnitConsumption: (Math.random() * 0.3 + 0.9).toFixed(4),
        annualConsumption: Math.floor(Math.random() * 60000 + 120000),
        annualProduction: Math.floor(Math.random() * 120000 + 240000),
        monthlyData: generateMonthlyData(0.8, 1.3),
        dailyData: generateDailyData(0.7, 1.4),
      },
      {
        energyType: "电",
        unit: "度/立方米",
        monthlyUnitConsumption: (Math.random() * 2 + 5).toFixed(4),
        monthlyConsumption: Math.floor(Math.random() * 50000 + 100000),
        monthlyProduction: Math.floor(Math.random() * 10000 + 20000),
        annualUnitConsumption: (Math.random() * 1.5 + 5.5).toFixed(4),
        annualConsumption: Math.floor(Math.random() * 600000 + 1200000),
        annualProduction: Math.floor(Math.random() * 120000 + 240000),
        monthlyData: generateMonthlyData(5, 7),
        dailyData: generateDailyData(4.5, 7.5),
      },
      {
        energyType: "蒸汽",
        unit: "吨/立方米",
        monthlyUnitConsumption: (Math.random() * 0.3 + 0.5).toFixed(4),
        monthlyConsumption: Math.floor(Math.random() * 3000 + 6000),
        monthlyProduction: Math.floor(Math.random() * 10000 + 20000),
        annualUnitConsumption: (Math.random() * 0.2 + 0.55).toFixed(4),
        annualConsumption: Math.floor(Math.random() * 36000 + 72000),
        annualProduction: Math.floor(Math.random() * 120000 + 240000),
        monthlyData: generateMonthlyData(0.5, 0.8),
        dailyData: generateDailyData(0.4, 0.9),
      },
    ];
    if (searchForm.energyType && searchForm.energyType !== "全部") {
      tableData.value = energyTypes.filter(
        item => item.energyType === searchForm.energyType
      );
    } else {
      tableData.value = energyTypes;
    }
  };
  // 生成月度数据
  const generateMonthlyData = (min, max) => {
    const data = [];
    for (let i = 1; i <= 12; i++) {
      data.push({
        month: i,
        unitConsumption: (Math.random() * (max - min) + min).toFixed(4),
      });
    }
    return data;
  };
  // 生成每日数据
  const generateDailyData = (min, max) => {
    const year = searchForm.year;
    const month = searchForm.month;
    const daysInMonth = new Date(year, month, 0).getDate();
    const data = [];
    for (let i = 1; i <= daysInMonth; i++) {
      data.push({
        day: i,
        unitConsumption: (Math.random() * (max - min) + min).toFixed(4),
      });
    }
    return data;
  };
  // 窗口大小变化时重新渲染图表