zhangwencui
8 天以前 4fef2b8afba85d8f2f8be70b85ffc105cfc4deda
src/views/energyManagement/officeEnergyConsumption/index.vue
@@ -11,14 +11,21 @@
                     style="width: 140px;"
                     @change="handleQuery">
            <el-option label="水"
                       value="water" />
                       value="水" />
            <el-option label="电"
                       value="electricity" />
                       value="电" />
            <el-option label="气"
                       value="gas" />
                       value="气" />
          </el-select>
        </el-form-item>
        <!-- <el-form-item label="日期范围:">
        <el-form-item label="能源名称:">
          <el-input v-model="searchForm.energyName"
                    placeholder="请输入"
                    clearable
                    style="width: 160px;"
                    @keyup.enter="handleQuery" />
        </el-form-item>
        <el-form-item label="日期范围:">
          <el-date-picker v-model="searchForm.dateRange"
                          type="daterange"
                          range-separator="至"
@@ -27,7 +34,7 @@
                          value-format="YYYY-MM-DD"
                          style="width: 240px;"
                          @change="handleQuery" />
        </el-form-item> -->
        </el-form-item>
        <el-form-item>
          <el-button type="primary"
                     @click="handleQuery">搜索</el-button>
@@ -35,10 +42,12 @@
        </el-form-item>
      </el-form>
      <div>
        <!-- <el-button type="primary"
                   @click="handleAdd">新增</el-button> -->
        <el-button type="primary"
                   @click="handleAdd">新增</el-button>
        <el-button type="success"
                   @click="handleExport">导出</el-button>
        <el-button type="warning"
                   @click="handleImport">导入</el-button>
      </div>
    </div>
    <!-- 数据表格 -->
@@ -102,8 +111,8 @@
                         label="备注"
                         min-width="150"
                         show-overflow-tooltip />
        <!-- <el-table-column label="操作"
                         width="180"
        <el-table-column label="操作"
                         width="220"
                         align="center"
                         fixed="right">
          <template #default="scope">
@@ -113,8 +122,11 @@
            <el-button type="danger"
                       link
                       @click="handleDelete(scope.row)">删除</el-button>
            <el-button type="info"
                       link
                       @click="downLoadFile(scope.row)">附件</el-button>
          </template>
        </el-table-column> -->
        </el-table-column>
      </el-table>
      <div class="pagination-container">
        <el-pagination v-model:current-page="page.current"
@@ -199,6 +211,28 @@
        </span>
      </template>
    </el-dialog>
    <!-- 附件列表弹窗 -->
    <FileListDialog ref="fileListRef"
                    v-model="fileListDialogVisible"
                    :show-upload-button="true"
                    :show-delete-button="true"
                    :is-show-pagination="true"
                    :page="filePagination"
                    :upload-method="handleUpload"
                    :delete-method="handleFileDelete"
                    @pagination="paginationSearch"
                    title="附件列表" />
    <ImportDialog ref="importDialogRef"
                  v-model="importDialogVisible"
                  title="导入明细"
                  :action="importAction"
                  :headers="importHeaders"
                  :auto-upload="false"
                  :on-success="handleImportSuccess"
                  :on-error="handleImportError"
                  @confirm="handleImportConfirm"
                  @download-template="handleDownloadTemplate"
                  @close="handleImportClose" />
  </div>
</template>
@@ -206,11 +240,18 @@
  import { ref, reactive, onMounted, getCurrentInstance } from "vue";
  import { ElMessage, ElMessageBox } from "element-plus";
  import { Watermelon, Lightning } from "@element-plus/icons-vue";
  import ImportDialog from "@/components/Dialog/ImportDialog.vue";
  import { getToken } from "@/utils/auth";
  import FileListDialog from "@/components/Dialog/FileListDialog.vue";
  import request from "@/utils/request";
  import {
    energyConsumptionDetailListPage,
    energyConsumptionDetailAdd,
    energyConsumptionDetailDelete,
    energyTypeListPage,
    fileListPage,
    energyConsumptionDetailFileAdd,
    energyConsumptionDetailFileDel,
  } from "@/api/energyManagement/energyType";
  // 搜索表单
@@ -247,6 +288,25 @@
  const formRef = ref(null);
  const isEdit = ref(false);
  const currentId = ref(null);
  // 附件相关
  const fileListRef = ref(null);
  const fileListDialogVisible = ref(false);
  const currentFileRow = ref(null);
  const filePagination = ref({
    current: 1,
    size: 10,
    total: 0,
  });
  // 导入相关
  const importDialogRef = ref(null);
  const importDialogVisible = ref(false);
  const importAction =
    import.meta.env.VITE_APP_BASE_API + "/energyConsumptionDetail/importData";
  const importHeaders = ref({
    Authorization: `Bearer ${getToken()}`,
  });
  // 表单数据
  const form = reactive({
@@ -314,15 +374,16 @@
      current: page.current,
      size: page.size,
      type: "办公",
      // energyType: searchForm.energyType,
      // startDate:
      //   searchForm.dateRange && searchForm.dateRange.length === 2
      //     ? searchForm.dateRange[0]
      //     : null,
      // endDate:
      //   searchForm.dateRange && searchForm.dateRange.length === 2
      //     ? searchForm.dateRange[1]
      //     : null,
      energyTyep: searchForm.energyType,
      energyName: searchForm.energyName,
      startDate:
        searchForm.dateRange && searchForm.dateRange.length === 2
          ? searchForm.dateRange[0]
          : null,
      endDate:
        searchForm.dateRange && searchForm.dateRange.length === 2
          ? searchForm.dateRange[1]
          : null,
    };
    energyConsumptionDetailListPage(params)
      .then(res => {
@@ -358,6 +419,7 @@
  // 重置
  const handleReset = () => {
    searchForm.energyType = "";
    searchForm.energyName = "";
    searchForm.dateRange = [];
    page.current = 1;
    handleQuery();
@@ -478,6 +540,205 @@
    });
  };
  // 下载文件
  const downLoadFile = row => {
    currentFileRow.value = row;
    fileListPage({
      energyConsumptionDetailId: row.id,
      current: filePagination.value.current,
      size: filePagination.value.size,
    }).then(res => {
      if (fileListRef.value) {
        fileListRef.value.open(res.data.records);
      }
      filePagination.value.total = res.data.total || 0;
    });
  };
  // 上传附件
  const handleUpload = async () => {
    if (!currentFileRow.value) {
      ElMessage.warning("请先选择数据");
      return null;
    }
    return new Promise(resolve => {
      // 创建一个隐藏的文件输入元素
      const input = document.createElement("input");
      input.type = "file";
      input.style.display = "none";
      input.onchange = async e => {
        const file = e.target.files[0];
        if (!file) {
          resolve(null);
          return;
        }
        try {
          // 使用 FormData 上传文件
          const formData = new FormData();
          formData.append("file", file);
          const uploadRes = await request({
            url: "/file/upload",
            method: "post",
            data: formData,
            headers: {
              "Content-Type": "multipart/form-data",
              Authorization: `Bearer ${getToken()}`,
            },
          });
          if (uploadRes.code === 200) {
            // 保存附件信息
            const fileData = {
              energyConsumptionDetailId: currentFileRow.value.id,
              name: uploadRes.data.originalName || file.name,
              url: uploadRes.data.tempPath || uploadRes.data.url,
            };
            const saveRes = await energyConsumptionDetailFileAdd(fileData);
            if (saveRes.code === 200) {
              proxy.$modal.msgSuccess("文件上传成功");
              // 重新加载文件列表
              const listRes = await fileListPage({
                energyConsumptionDetailId: currentFileRow.value.id,
                current: filePagination.value.current,
                size: filePagination.value.size,
              });
              if (listRes.code === 200 && fileListRef.value) {
                const fileList = (listRes.data?.records || []).map(item => ({
                  name: item.name,
                  url: item.url,
                  id: item.id,
                  ...item,
                }));
                fileListRef.value.setList(fileList);
                filePagination.value.total = listRes.data?.total || 0;
              }
              // 返回新文件信息
              resolve({
                name: fileData.name,
                url: fileData.url,
                id: Date.now(),
              });
            } else {
              ElMessage.error(uploadRes.message || "文件上传失败");
              resolve(null);
            }
          }
        } catch (error) {
          ElMessage.error("文件上传失败");
          resolve(null);
        } finally {
          document.body.removeChild(input);
        }
      };
      document.body.appendChild(input);
      input.click();
    });
  };
  // 分页搜索
  const paginationSearch = async (page, size) => {
    filePagination.value.current = page;
    filePagination.value.size = size;
    const listRes = await fileListPage({
      energyConsumptionDetailId: currentFileRow.value.id,
      current: filePagination.value.current,
      size: filePagination.value.size,
    });
    if (listRes.code === 200) {
      const fileList = (listRes.data?.records || []).map(item => ({
        name: item.name,
        url: item.url,
        id: item.id,
        ...item,
      }));
      fileListRef.value.setList(fileList);
      filePagination.value.total = listRes.data?.total || 0;
    }
  };
  // 删除附件
  const handleFileDelete = async row => {
    try {
      const res = await energyConsumptionDetailFileDel([row.id]);
      if (res.code === 200) {
        proxy.$modal.msgSuccess("删除成功");
        // 重新加载文件列表
        if (currentFileRow.value && fileListRef.value) {
          const listRes = await fileListPage({
            energyConsumptionDetailId: currentFileRow.value.id,
            current: filePagination.value.current,
            size: filePagination.value.size,
          });
          if (listRes.code === 200) {
            const fileList = (listRes.data?.records || []).map(item => ({
              name: item.name,
              url: item.url,
              id: item.id,
              ...item,
            }));
            fileListRef.value.setList(fileList);
            filePagination.value.total = listRes.data?.total || 0;
          }
        }
        return true; // 返回 true 表示删除成功,组件会更新列表
      } else {
        proxy.$modal.msgError(res.msg || "删除失败");
        return false;
      }
    } catch (error) {
      ElMessage.error("删除失败");
      return false;
    }
  };
  // 导入
  const handleImport = () => {
    importDialogVisible.value = true;
  };
  // 导入成功
  const handleImportSuccess = response => {
    if (response.code === 200) {
      ElMessage.success("导入成功");
      importDialogVisible.value = false;
      handleQuery();
    } else {
      ElMessage.error(response.message || "导入失败");
    }
  };
  // 导入失败
  const handleImportError = error => {
    ElMessage.error("导入失败,请检查文件格式是否正确");
  };
  // 确认导入
  const handleImportConfirm = () => {
    if (importDialogRef.value) {
      importDialogRef.value.submit();
    }
  };
  // 下载模板
  const handleDownloadTemplate = () => {
    proxy.download(
      "/energyConsumptionDetail/downloadTemplate",
      {},
      "生产能耗导入模板.xlsx"
    );
  };
  // 关闭导入弹窗
  const handleImportClose = () => {
    importDialogVisible.value = false;
  };
  onMounted(() => {
    getEnergyTypeList();
    handleQuery();
@@ -494,7 +755,9 @@
  .search_form {
    display: flex;
    justify-content: space-between;
    align-items: center;
    align-items: flex-start;
    flex-wrap: wrap;
    gap: 16px;
    margin-bottom: 24px;
    padding: 20px;
    background-color: #ffffff;
@@ -504,6 +767,28 @@
    &:hover {
      box-shadow: 0 4px 16px 0 rgba(0, 0, 0, 0.08);
    }
    :deep(.el-form) {
      display: flex;
      flex-wrap: wrap;
      gap: 0;
      .el-form-item {
        margin-right: 16px;
        margin-bottom: 0;
        &:last-child {
          margin-right: 0;
        }
      }
    }
    > div {
      display: flex;
      flex-wrap: wrap;
      gap: 8px;
      flex-shrink: 0;
    }
  }
@@ -636,28 +921,83 @@
    font-size: 12px;
  }
  @media (max-width: 768px) {
    .app-container {
      padding: 16px;
  @media (max-width: 1200px) {
    .search_form {
      :deep(.el-form) {
        .el-form-item {
          margin-right: 12px;
          margin-bottom: 8px;
        }
      }
    }
  }
  @media (max-width: 992px) {
    .search_form {
      flex-direction: column;
      align-items: flex-start;
      align-items: stretch;
      gap: 12px;
      .el-form {
      :deep(.el-form) {
        width: 100%;
        .el-form-item {
          width: 100%;
          margin-right: 12px;
          margin-bottom: 8px;
          flex: 1;
          min-width: 200px;
          &:last-child {
            margin-right: 12px;
          }
        }
      }
      > div {
        width: 100%;
        display: flex;
        gap: 12px;
        justify-content: flex-end;
      }
    }
  }
  @media (max-width: 768px) {
    .app-container {
      padding: 12px;
    }
    .search_form {
      padding: 16px;
      gap: 12px;
      :deep(.el-form) {
        flex-direction: column;
        width: 100%;
        .el-form-item {
          width: 100%;
          margin-right: 0;
          margin-bottom: 12px;
          &:last-child {
            margin-right: 0;
            margin-bottom: 0;
          }
          .el-form-item__content {
            width: 100%;
            .el-input,
            .el-select,
            .el-date-editor {
              width: 100% !important;
            }
          }
        }
      }
      > div {
        width: 100%;
        justify-content: stretch;
        .el-button {
          flex: 1;
@@ -665,17 +1005,36 @@
      }
    }
    .table_list {
      height: calc(100vh - 300px);
    }
    :deep(.el-table) {
      th,
      td {
        padding: 10px 0;
        padding: 8px 0;
        font-size: 12px;
      }
    }
    :deep(.el-dialog) {
      width: 90% !important;
      margin: 20px auto !important;
      width: 95% !important;
      margin: 10px auto !important;
    }
  }
  @media (max-width: 480px) {
    .search_form {
      padding: 12px;
      > div {
        flex-direction: column;
        gap: 8px;
        .el-button {
          width: 100%;
        }
      }
    }
  }
  .consumption-value {