gaoluyang
8 天以前 11b40328f7aa7599f89189d0ebcbbdf8773f9e1b
src/views/equipmentManagement/inspectionManagement/index.vue
@@ -1,393 +1,397 @@
<template>
  <div class="app-container">
    <el-form :inline="true"
             :model="queryParams"
             class="search-form">
    <el-form :inline="true" :model="queryParams" class="search-form">
      <el-form-item label="巡检任务名称">
        <el-input v-model="queryParams.taskName"
                  placeholder="请输入巡检任务名称"
                  clearable
                  style="width: 200px " />
        <el-input
          v-model="queryParams.taskName"
          placeholder="请输入巡检任务名称"
          clearable
          style="width: 200px"
        />
      </el-form-item>
      <el-form-item label="所属区域">
        <el-tree-select
          v-model="queryParams.areaId"
          :data="areaOptions"
          :props="areaTreeProps"
          node-key="id"
          value-key="id"
          check-strictly
          clearable
          filterable
          placeholder="请选择所属区域"
          style="width: 220px"
        />
      </el-form-item>
      <el-form-item>
        <el-button type="primary"
                   @click="handleQuery">查询</el-button>
        <el-button type="primary" @click="handleQuery">查询</el-button>
        <el-button @click="resetQuery">重置</el-button>
      </el-form-item>
    </el-form>
    <el-card>
      <div style="display: flex;flex-direction: row;justify-content: space-between;margin-bottom: 10px;">
        <el-radio-group v-model="activeRadio"
                        @change="radioChange">
          <el-radio-button v-for="tab in radios"
                           :key="tab.name"
                           :label="tab.label"
                           :value="tab.name" />
      <div class="toolbar">
        <el-radio-group v-model="activeRadio" @change="radioChange">
          <el-radio-button
            v-for="tab in radios"
            :key="tab.name"
            :label="tab.label"
            :value="tab.name"
          />
        </el-radio-group>
        <!-- 操作按钮区 -->
        <el-space v-if="activeRadio !== 'task'">
          <el-button type="primary"
                     :icon="Plus"
                     @click="handleAdd(undefined)">新建</el-button>
          <el-button type="danger"
                     :icon="Delete"
                     @click="handleDelete">删除</el-button>
          <el-button type="primary" :icon="Plus" @click="handleAdd(undefined)">新建</el-button>
          <el-button type="danger" :icon="Delete" @click="handleDelete">删除</el-button>
          <el-button @click="handleOut">导出</el-button>
        </el-space>
        <el-space v-else>
          <el-button @click="handleOut">导出</el-button>
        </el-space>
      </div>
      <div>
        <PIMTable :table-loading="tableLoading"
                  :table-data="tableData"
                  :column="tableColumns"
                  @selection-change="handleSelectionChange"
                  @pagination="handlePagination"
                  :is-selection="true"
                  :border="true"
                  :page="{
                  current: pageNum,
                  size: pageSize,
                  total: total,
                  layout: 'total, sizes, prev, pager, next, jumper'
                }"
                  :table-style="{ width: '100%', height: 'calc(100vh - 23em)' }">
          <template #inspector="{ row }">
            <div class="person-tags">
              <!-- 调试信息,上线时删除 -->
              <!-- {{ console.log('inspector data:', row.inspector) }} -->
              <template v-if="row.inspector && row.inspector.length > 0">
                <el-tag v-for="(person, index) in row.inspector"
                        :key="index"
                        size="small"
                        type="primary"
                        class="person-tag">
                  {{ person }}
                </el-tag>
              </template>
              <span v-else
                    class="no-data">--</span>
            </div>
          </template>
        </PIMTable>
      </div>
      <PIMTable
        :table-loading="tableLoading"
        :table-data="tableData"
        :column="tableColumns"
        :is-selection="true"
        :border="true"
        :page="{
          current: pageNum,
          size: pageSize,
          total,
          layout: 'total, sizes, prev, pager, next, jumper',
        }"
        :table-style="{ width: '100%', height: 'calc(100vh - 23em)' }"
        @selection-change="handleSelectionChange"
        @pagination="handlePagination"
      >
        <template #inspector="{ row }">
          <div class="person-tags">
            <template v-if="row.inspector && row.inspector.length > 0">
              <el-tag
                v-for="(person, index) in row.inspector"
                :key="index"
                size="small"
                type="primary"
                class="person-tag"
              >
                {{ person }}
              </el-tag>
            </template>
            <span v-else class="no-data">--</span>
          </div>
        </template>
      </PIMTable>
    </el-card>
    <form-dia ref="formDia"
              @closeDia="handleQuery"></form-dia>
    <view-files ref="viewFiles"></view-files>
    <form-dia ref="formDia" @closeDia="handleQuery" />
    <view-files ref="viewFiles" />
  </div>
</template>
<script setup>
  import { Delete, Plus } from "@element-plus/icons-vue";
  import { onMounted, ref, reactive, getCurrentInstance, nextTick } from "vue";
  import { ElMessageBox } from "element-plus";
import { Delete, Plus } from "@element-plus/icons-vue";
import { ElMessageBox } from "element-plus";
import { getCurrentInstance, nextTick, onMounted, reactive, ref } from "vue";
import PIMTable from "@/components/PIMTable/PIMTable.vue";
import FormDia from "@/views/equipmentManagement/inspectionManagement/components/formDia.vue";
import ViewFiles from "@/views/equipmentManagement/inspectionManagement/components/viewFiles.vue";
import {
  delTimingTask,
  inspectionTaskList,
  timingTaskList,
} from "@/api/inspectionManagement/index.js";
import { getDeviceAreaTree } from "@/api/equipmentManagement/deviceArea";
  // 组件引入
  import PIMTable from "@/components/PIMTable/PIMTable.vue";
  import FormDia from "@/views/equipmentManagement/inspectionManagement/components/formDia.vue";
  import ViewFiles from "@/views/equipmentManagement/inspectionManagement/components/viewFiles.vue";
const { proxy } = getCurrentInstance();
const formDia = ref();
const viewFiles = ref();
  // 接口引入
  import {
    delTimingTask,
    inspectionTaskList,
    timingTaskList,
  } from "@/api/inspectionManagement/index.js";
const queryParams = reactive({
  taskName: "",
  areaId: undefined,
});
  // 全局变量
  const { proxy } = getCurrentInstance();
  const formDia = ref();
  const viewFiles = ref();
const areaOptions = ref([]);
const areaTreeProps = {
  label: "areaName",
  children: "children",
};
  // 查询参数
  const queryParams = reactive({
    taskName: "",
  });
const activeRadio = ref("taskManage");
const radios = reactive([
  { name: "taskManage", label: "定时任务管理" },
  { name: "task", label: "定时任务记录" },
]);
  // 单选框配置
  const activeRadio = ref("taskManage");
  const radios = reactive([
    { name: "taskManage", label: "定时任务管理" },
    { name: "task", label: "定时任务记录" },
  ]);
const selectedRows = ref([]);
const tableData = ref([]);
const tableColumns = ref([]);
const tableLoading = ref(false);
const total = ref(0);
const pageNum = ref(1);
const pageSize = ref(10);
  // 表格数据
  const selectedRows = ref([]);
  const tableData = ref([]);
  const operationsArr = ref([]);
  const tableColumns = ref([]);
  const tableLoading = ref(false);
  const total = ref(0);
  const pageNum = ref(1);
  const pageSize = ref(10);
  // 列配置
  const columns = ref([
    { prop: "taskName", label: "巡检任务名称", minWidth: 160 },
    { prop: "remarks", label: "备注", minWidth: 150 },
    { prop: "inspector", label: "执行巡检人", minWidth: 150, slot: "inspector" },
    {
      prop: "frequencyType",
      label: "频次",
      minWidth: 150,
      // formatter: (_, __, val) => ({
      //   DAILY: "每日",
      //   WEEKLY: "每周",
      //   MONTHLY: "每月",
      //   QUARTERLY: "季度"
      // }[val] || "")
      formatData: params => {
        return params === "DAILY"
          ? "每日"
          : params === "WEEKLY"
          ? "每周"
          : params === "MONTHLY"
          ? "每月"
          : params === "QUARTERLY"
          ? "季度"
          : "";
      },
    },
    {
      prop: "frequencyDetail",
      label: "开始日期与时间",
      minWidth: 150,
      formatter: (row, column, cellValue) => {
        // 先判断是否是字符串
        if (typeof cellValue !== "string") return "";
        let val = cellValue;
        const replacements = {
          MON: "周一",
          TUE: "周二",
          WED: "周三",
          THU: "周四",
          FRI: "周五",
          SAT: "周六",
          SUN: "周日",
        };
        // 使用正则一次性替换所有匹配项
        return val.replace(
          /MON|TUE|WED|THU|FRI|SAT|SUN/g,
          match => replacements[match]
        );
      },
    },
    { prop: "registrant", label: "登记人", minWidth: 100 },
    { prop: "createTime", label: "登记日期", minWidth: 100 },
  ]);
  // 操作列配置
  const getOperationColumn = operations => {
    if (!operations || operations.length === 0) return null;
    const operationConfig = {
      label: "操作",
      width: 130,
      fixed: "right",
      dataType: "action",
      operation: operations
        .map(op => {
          switch (op) {
            case "edit":
              return {
                name: "编辑",
                clickFun: handleAdd,
                color: "#409EFF",
              };
            case "viewFile":
              return {
                name: "查看附件",
                clickFun: viewFile,
                color: "#67C23A",
              };
            default:
              return null;
          }
        })
        .filter(Boolean),
    };
    return operationConfig;
  };
  onMounted(() => {
    radioChange("taskManage");
  });
  // 单选变化
  const radioChange = value => {
    if (value === "taskManage") {
      const operationColumn = getOperationColumn(["edit"]);
      tableColumns.value = [
        ...columns.value,
        ...(operationColumn ? [operationColumn] : []),
      ];
      operationsArr.value = ["edit"];
    } else if (value === "task") {
      const operationColumn = getOperationColumn(["viewFile"]);
      tableColumns.value = [
        ...columns.value,
        ...(operationColumn ? [operationColumn] : []),
      ];
      operationsArr.value = ["viewFile"];
    }
    pageNum.value = 1;
    pageSize.value = 10;
    getList();
  };
  // 查询操作
  const handleQuery = () => {
    pageNum.value = 1;
    pageSize.value = 10;
    getList();
  };
  // 分页处理
  const handlePagination = val => {
    pageNum.value = val.page;
    pageSize.value = val.limit;
    getList();
  };
  // 获取列表数据
  const getList = () => {
    tableLoading.value = true;
    const params = {
      ...queryParams,
      size: pageSize.value,
      current: pageNum.value,
    };
    let apiCall;
    if (activeRadio.value === "task") {
      apiCall = inspectionTaskList(params);
    } else {
      apiCall = timingTaskList(params);
    }
    apiCall
      .then(res => {
        const rawData = res.data.records || [];
        // 处理 inspector 字段,将字符串转换为数组(适用于所有情况)
        tableData.value = rawData.map(item => {
          const processedItem = { ...item };
          // 处理 inspector 字段
          if (processedItem.inspector) {
            if (typeof processedItem.inspector === "string") {
              // 字符串按逗号分割
              processedItem.inspector = processedItem.inspector
                .split(",")
                .map(s => s.trim())
                .filter(s => s);
            } else if (!Array.isArray(processedItem.inspector)) {
              // 非数组转为数组
              processedItem.inspector = [processedItem.inspector];
            }
          } else {
            // 空值设为空数组
            processedItem.inspector = [];
          }
          return processedItem;
        });
        total.value = res.data.total || 0;
      })
      .finally(() => {
        tableLoading.value = false;
      });
  };
  // 重置查询
  const resetQuery = () => {
    for (const key in queryParams) {
      if (!["pageNum", "pageSize"].includes(key)) {
        queryParams[key] = "";
const columns = ref([
   {
      label: "所在区域",
      prop: "areaName",
   },
  { prop: "taskName", label: "巡检任务名称", minWidth: 160 },
  { prop: "remarks", label: "备注", minWidth: 150 },
  { prop: "inspector", label: "执行巡检人", minWidth: 150, slot: "inspector" },
  {
    prop: "frequencyType",
    label: "频次",
    minWidth: 150,
    formatData: (value) =>
      ({
        DAILY: "每日",
        WEEKLY: "每周",
        MONTHLY: "每月",
        QUARTERLY: "季度",
            YEARLY: "每年",
      }[value] || ""),
  },
  {
    prop: "frequencyDetail",
    label: "开始日期与时间",
    minWidth: 150,
    formatter: (row, column, cellValue) => {
      if (typeof cellValue !== "string") {
        return "";
      }
    }
    handleQuery();
  };
      const replacements = {
        MON: "周一",
        TUE: "周二",
        WED: "周三",
        THU: "周四",
        FRI: "周五",
        SAT: "周六",
        SUN: "周日",
      };
      return cellValue.replace(/MON|TUE|WED|THU|FRI|SAT|SUN/g, (match) => replacements[match]);
    },
  },
  { prop: "registrant", label: "登记人", minWidth: 100 },
  { prop: "createTime", label: "登记日期", minWidth: 100 },
]);
  // 新增 / 编辑
  const handleAdd = row => {
    const type = row ? "edit" : "add";
    nextTick(() => {
      formDia.value?.openDialog(type, row);
    });
  };
// 巡检状态列(仅定时任务记录显示)
const inspectionStatusColumn = {
  prop: "inspectionStatus",
  label: "巡检状态",
  minWidth: 100,
  dataType: "tag",
  formatData: (value) =>
    ({
      1: "待巡检",
      2: "已巡检",
    }[value] || ""),
  formatType: (value) =>
    ({
      1: "warning",
      2: "success",
    }[value] || "info"),
};
// 巡检结果列(仅定时任务记录显示)
const inspectionResultColumn = {
  prop: "inspectionResult",
  label: "巡检结果",
  minWidth: 100,
  dataType: "tag",
  formatData: (value) =>
    ({
      1: "正常",
      2: "异常",
    }[value] || ""),
  formatType: (value) =>
    ({
      1: "success",
      2: "error",
    }[value] || "info"),
};
  // 查看附件
  const viewFile = row => {
    nextTick(() => {
      viewFiles.value?.openDialog(row);
    });
  };
  // 删除操作
  const handleDelete = () => {
    if (!selectedRows.value.length) {
      proxy.$modal.msgWarning("请选择要删除的数据");
      return;
    }
    const deleteIds = selectedRows.value.map(item => item.id);
    proxy.$modal
      .confirm("是否确认删除所选数据项?")
      .then(() => {
        return delTimingTask(deleteIds);
      })
      .then(() => {
        proxy.$modal.msgSuccess("删除成功");
        handleQuery();
      })
      .catch(() => {});
  };
  // 多选变更
  const handleSelectionChange = selection => {
    selectedRows.value = selection;
  };
  // 导出
  const handleOut = () => {
    ElMessageBox.confirm("选中的内容将被导出,是否确认导出?", "导出", {
      confirmButtonText: "确认",
      cancelButtonText: "取消",
      type: "warning",
    })
      .then(() => {
        // 根据当前选中的标签页调用不同的导出接口
        if (activeRadio.value === "taskManage") {
          // 定时任务管理
          proxy.download("/timingTask/export", {}, "定时任务管理.xlsx");
        } else if (activeRadio.value === "task") {
          // 定时任务记录
          proxy.download("/inspectionTask/export", {}, "定时任务记录.xlsx");
const getOperationColumn = (operations) => {
  if (!operations || operations.length === 0) {
    return null;
  }
  return {
    label: "操作",
    width: 130,
    fixed: "right",
    dataType: "action",
    operation: operations
      .map((op) => {
        switch (op) {
          case "edit":
            return {
              name: "编辑",
              clickFun: handleAdd,
              color: "#409EFF",
            };
          case "viewFile":
            return {
              name: "查看附件",
              clickFun: viewFile,
              color: "#67C23A",
            };
          default:
            return null;
        }
      })
      .catch(() => {
        proxy.$modal.msg("已取消");
      });
      .filter(Boolean),
  };
};
const loadAreaTree = async () => {
  const { data } = await getDeviceAreaTree();
  areaOptions.value = Array.isArray(data) ? data : [];
};
onMounted(() => {
  loadAreaTree();
  radioChange("taskManage");
});
const radioChange = (value) => {
  if (value === "taskManage") {
    const operationColumn = getOperationColumn(["edit"]);
    tableColumns.value = [...columns.value, ...(operationColumn ? [operationColumn] : [])];
  } else {
    const operationColumn = getOperationColumn(["viewFile"]);
    // 定时任务记录添加巡检状态列
    tableColumns.value = [...columns.value, inspectionStatusColumn, inspectionResultColumn, ...(operationColumn ? [operationColumn] : [])];
  }
  pageNum.value = 1;
  pageSize.value = 10;
  getList();
};
const handleQuery = () => {
  pageNum.value = 1;
  pageSize.value = 10;
  getList();
};
const handlePagination = (val) => {
  pageNum.value = val.page;
  pageSize.value = val.limit;
  getList();
};
const getList = () => {
  tableLoading.value = true;
  const params = {
    ...queryParams,
    size: pageSize.value,
    current: pageNum.value,
  };
  const apiCall =
    activeRadio.value === "task" ? inspectionTaskList(params) : timingTaskList(params);
  apiCall
    .then((res) => {
      const rawData = res?.data?.records || [];
      tableData.value = rawData.map((item) => {
        const processedItem = { ...item };
        if (processedItem.inspector) {
          if (typeof processedItem.inspector === "string") {
            processedItem.inspector = processedItem.inspector
              .split(",")
              .map((text) => text.trim())
              .filter(Boolean);
          } else if (!Array.isArray(processedItem.inspector)) {
            processedItem.inspector = [processedItem.inspector];
          }
        } else {
          processedItem.inspector = [];
        }
        return processedItem;
      });
      total.value = res?.data?.total || 0;
    })
    .finally(() => {
      tableLoading.value = false;
    });
};
const resetQuery = () => {
  queryParams.taskName = "";
  queryParams.areaId = undefined;
  handleQuery();
};
const handleAdd = (row) => {
  const type = row ? "edit" : "add";
  nextTick(() => {
    formDia.value?.openDialog(type, row);
  });
};
const viewFile = (row) => {
  nextTick(() => {
    viewFiles.value?.openDialog(row);
  });
};
const handleDelete = () => {
  if (!selectedRows.value.length) {
    proxy.$modal.msgWarning("请选择要删除的数据");
    return;
  }
  const deleteIds = selectedRows.value.map((item) => item.id);
  proxy.$modal
    .confirm("是否确认删除所选数据项?")
    .then(() => delTimingTask(deleteIds))
    .then(() => {
      proxy.$modal.msgSuccess("删除成功");
      handleQuery();
    })
    .catch(() => {});
};
const handleSelectionChange = (selection) => {
  selectedRows.value = selection;
};
const handleOut = () => {
  ElMessageBox.confirm("选中的内容将被导出,是否确认导出?", "导出", {
    confirmButtonText: "确认",
    cancelButtonText: "取消",
    type: "warning",
  })
    .then(() => {
      if (activeRadio.value === "taskManage") {
        proxy.download("/timingTask/export", {}, "定时任务管理.xlsx");
      } else {
        proxy.download("/inspectionTask/export", {}, "定时任务记录.xlsx");
      }
    })
    .catch(() => {
      proxy.$modal.msg("已取消");
    });
};
</script>
<style scoped>
  .person-tags {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
  }
.toolbar {
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  margin-bottom: 10px;
}
  .person-tag {
    margin-right: 4px;
    margin-bottom: 2px;
  }
.person-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}
  .no-data {
    color: #909399;
    font-size: 14px;
  }
</style>
.person-tag {
  margin-right: 4px;
  margin-bottom: 2px;
}
.no-data {
  color: #909399;
  font-size: 14px;
}
</style>