gongchunyi
5 小时以前 48d0a176a96816506d881b61bf1369a49e4d6473
feat: 隐患排查上报详情、验收人选择
已修改1个文件
327 ■■■■■ 文件已修改
src/views/safeProduction/dangerInvestigation/index.vue 327 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/safeProduction/dangerInvestigation/index.vue
@@ -55,52 +55,82 @@
                         width="60" />
        <el-table-column label="隐患编号"
                         prop="hiddenCode"
                         width="180"
                         show-overflow-tooltip />
                         width="150"
                         align="center"
                         show-overflow-tooltip>
          <template #default="scope">
            <el-button class="hidden-code-link"
                       link
                       type="primary"
                       @click="openForm('detail', scope.row)">
              {{ scope.row.hiddenCode }}
            </el-button>
          </template>
        </el-table-column>
        <el-table-column label="隐患描述"
                         prop="hiddenDesc"
                         width="150"
                         align="center"
                         show-overflow-tooltip />
        <el-table-column label="隐患具体位置"
                         prop="location"
                         width="150"
                         align="center"
                         show-overflow-tooltip />
        <el-table-column label="上报人"
                         prop="createUserName"
                         width="180"
                         width="150"
                         align="center"
                         show-overflow-tooltip />
        <el-table-column label="上报时间"
                         prop="createTime"
                         width="180"
                         align="center"
                         show-overflow-tooltip />
        <el-table-column label="整改完成期限"
                         prop="rectifyTime"
                         width="120"
                         align="center"
                         show-overflow-tooltip />
        <el-table-column label="整改责任人"
                         prop="rectifyUserName"
                         width="120"
                         align="center"
                         show-overflow-tooltip />
        <el-table-column label="整改责任人联系方式"
                         prop="rectifyUserMobile"
                         width="120"
                         width="160"
                         align="center"
                         show-overflow-tooltip />
        <el-table-column label="整改具体措施"
                         prop="rectifyMeasures"
                         width="120"
                         align="center"
                         show-overflow-tooltip />
        <el-table-column label="实际整改完成时间"
                         prop="rectifyActualTime"
                         width="180"
                         align="center"
                         show-overflow-tooltip />
        <el-table-column label="验收人"
                         prop="verifyUserName"
                         width="120"
                         align="center"
                         show-overflow-tooltip />
        <el-table-column label="验收意见"
                         prop="verifyRemark"
                         width="120"
                         align="center"
                         show-overflow-tooltip />
        <el-table-column label="验收时间"
                         prop="verifyTime"
                         width="120"
                         align="center"
                         show-overflow-tooltip />
        <el-table-column label="验收结果"
                         prop="verifyResult"
                         width="120"
                         align="center"
                         show-overflow-tooltip>
          <template #default="scope">
            <el-tag v-if="scope.row.verifyResult"
@@ -130,7 +160,7 @@
            <el-button link
                       type="primary"
                       size="small"
                       :disabled="!scope.row.rectifyActualTime || scope.row.verifyTime"
                       :disabled="!scope.row.rectifyActualTime || scope.row.verifyTime || scope.row.isVerify"
                       @click="openForm('edit3', scope.row)">验收</el-button>
          </template>
        </el-table-column>
@@ -268,11 +298,11 @@
          </el-col>
        </el-row>
      </el-form>
      <div v-if="operationType === 'edit2' || operationType === 'edit3'"
      <div v-if="showHiddenDetail"
           class="classtitle">隐患详情</div>
      <el-descriptions :column="2"
                       style="margin-bottom: 20px;"
                       v-if="operationType === 'edit2' || operationType === 'edit3'"
                       v-if="showHiddenDetail"
                       border>
        <el-descriptions-item label="隐患编号">
          <span class="detail-title">{{ form.hiddenCode }}</span>
@@ -309,11 +339,11 @@
        </el-descriptions-item>
      </el-descriptions>
      <div class="classtitle"
           v-if="operationType === 'edit3'"
           v-if="showRectifyDetail"
           style="margin-top: 40px;">整改详情</div>
      <el-descriptions :column="2"
                       style="margin-bottom: 20px;"
                       v-if="operationType === 'edit3'"
                       v-if="showRectifyDetail"
                       border>
        <el-descriptions-item label="整改具体措施"
                              :span="2">
@@ -351,6 +381,20 @@
                              type="date"
                              placeholder="请选择"
                              clearable />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="验收人:"
                          prop="verifyUserId">
              <el-select v-model="form2.verifyUserId"
                         placeholder="请选择"
                         filterable
                         clearable>
                <el-option v-for="item in userList"
                           :key="item.userId"
                           :label="item.nickName"
                           :value="item.userId" />
              </el-select>
            </el-form-item>
          </el-col>
        </el-row>
@@ -402,8 +446,9 @@
            <el-form-item label="验收人:"
                          prop="verifyUserId">
              <el-select v-model="form3.verifyUserId"
                         disabled
                         :disabled="!!form3.verifyUserId"
                         placeholder="请选择"
                         filterable
                         clearable>
                <el-option v-for="item in userList"
                           :key="item.userId"
@@ -414,6 +459,68 @@
          </el-col>
        </el-row>
      </el-form>
      <div class="classtitle"
           v-if="showVerifyDetail"
           style="margin-top: 40px;">验收详情</div>
      <el-descriptions :column="2"
                       style="margin-bottom: 20px;"
                       v-if="showVerifyDetail"
                       border>
        <el-descriptions-item label="验收人">
          <span class="detail-title">{{ getVerifyUserName() }}</span>
        </el-descriptions-item>
        <el-descriptions-item label="验收时间">
          <span class="detail-title">{{ form3.verifyTime }}</span>
        </el-descriptions-item>
        <el-descriptions-item label="验收结果">
          <el-tag v-if="form3.verifyResult"
                  :type="form3.verifyResult === '通过' ? 'success' : 'danger'">
            {{ form3.verifyResult }}
          </el-tag>
        </el-descriptions-item>
        <el-descriptions-item label="验收意见"
                              :span="2">
          <span class="detail-title">{{ form3.verifyRemark }}</span>
        </el-descriptions-item>
      </el-descriptions>
      <div class="classtitle"
           v-if="operationType === 'detail'"
           style="margin-top: 40px;">附件</div>
      <div v-if="operationType === 'detail'"
           v-loading="detailAttachmentLoading"
           class="detail-attachment-preview-list">
        <el-empty v-if="!detailAttachmentLoading && detailAttachmentList.length === 0"
                  description="暂无附件"
                  :image-size="80" />
        <div v-for="item in detailAttachmentList"
             :key="item.storageAttachmentId || item.id || getAttachmentPreviewUrl(item)"
             class="detail-attachment-preview-card">
          <div class="detail-attachment-header">
            <span class="detail-attachment-name">{{ getAttachmentName(item) }}</span>
            <el-button link
                       type="primary"
                       size="small"
                       @click="downloadDetailAttachment(item)">下载</el-button>
          </div>
          <el-image v-if="isImageAttachment(item)"
                    class="detail-attachment-image"
                    :src="getAttachmentPreviewUrl(item)"
                    :preview-src-list="detailPreviewImageUrls"
                    :initial-index="getImagePreviewIndex(item)"
                    fit="contain"
                    preview-teleported />
          <iframe v-else-if="isPdfAttachment(item)"
                  class="detail-attachment-frame"
                  :src="getAttachmentPreviewUrl(item)" />
          <div v-else
               class="detail-attachment-placeholder">
            <span>该文件类型暂不支持内嵌预览</span>
            <el-button link
                       type="primary"
                       @click="downloadDetailAttachment(item)">下载查看</el-button>
          </div>
        </div>
      </div>
    </FormDialog>
    <FileListDialog
        v-if="fileListDialogVisible"
@@ -433,6 +540,7 @@
  import { userListNoPage } from "@/api/system/user.js";
  import FormDialog from "@/components/Dialog/FormDialog.vue";
  import { getQuotationList } from "@/api/salesManagement/salesQuotation.js";
  import { attachmentList } from "@/api/basicData/storageAttachment.js";
  import {
    dangerInvestigationListPage,
    safeHiddenAdd,
@@ -449,6 +557,8 @@
  const selectedRows = ref([]);
  const userList = ref([]);
  const tableLoading = ref(false);
  const detailAttachmentList = ref([]);
  const detailAttachmentLoading = ref(false);
  const currentRecordId = ref(0);
  const page = reactive({
    current: 1,
@@ -464,6 +574,8 @@
      return "整改页面";
    } else if (type === "edit3") {
      return "验收页面";
    } else if (type === "detail") {
      return "隐患详情";
    }
  };
  // 获取类型标签类型
@@ -511,11 +623,13 @@
  const rules2 = {
    rectifyActualTime: [{ required: true, message: "请选择", trigger: "blur" }],
    rectifyMeasures: [{ required: true, message: "请输入", trigger: "blur" }],
    verifyUserId: [{ required: true, message: "请选择", trigger: "change" }],
  };
  const rules3 = {
    verifyTime: [{ required: true, message: "请选择", trigger: "blur" }],
    verifyRemark: [{ required: true, message: "请输入", trigger: "blur" }],
    verifyResult: [{ required: true, message: "请选择", trigger: "change" }],
    verifyUserId: [{ required: true, message: "请选择", trigger: "change" }],
    acceptDesc: [{ required: true, message: "请输入", trigger: "blur" }],
  };
  const { hidden_danger_type } = proxy.useDict("hidden_danger_type");
@@ -527,6 +641,7 @@
  const form2 = ref({
    rectifyActualTime: "", // 实际整改完成时间
    rectifyMeasures: "", // 整改具体措施
    verifyUserId: "", // 验收人
  });
  const form3 = ref({
    verifyTime: "", // 验收时间
@@ -536,6 +651,21 @@
    verifyUserName: "",
    verifyResult: "", // 验收结果
  });
  const showHiddenDetail = computed(() => ["edit2", "edit3", "detail"].includes(operationType.value));
  const showRectifyDetail = computed(
    () =>
      operationType.value === "edit3" ||
      (operationType.value === "detail" && (form2.value.rectifyMeasures || form2.value.rectifyActualTime))
  );
  const showVerifyDetail = computed(
    () =>
      operationType.value === "detail" &&
      (form3.value.verifyUserId ||
        form3.value.verifyUserName ||
        form3.value.verifyRemark ||
        form3.value.verifyTime ||
        form3.value.verifyResult)
  );
  const riskLevelList = ref([
    {
      value: "重大风险",
@@ -572,6 +702,60 @@
      form.value.rectifyUserName = selectedUser.nickName;
      form.value.rectifyUserMobile = selectedUser.phonenumber;
    }
  };
  const hasUserId = userId => userId !== null && userId !== undefined && userId !== "" && userId !== "null";
  const normalizeUserId = userId => (hasUserId(userId) ? Number(userId) : "");
  const getVerifyUserName = () => {
    if (form3.value.verifyUserName) {
      return form3.value.verifyUserName;
    }
    const selectedUser = userList.value.find(user => Number(user.userId) === Number(form3.value.verifyUserId));
    return selectedUser?.nickName || selectedUser?.userName || "";
  };
  const getAttachmentName = row => row?.originalFilename || row?.fileName || row?.name || "";
  const getAttachmentPreviewUrl = row => row?.previewURL || row?.previewUrl || row?.url || row?.downloadURL || row?.downloadUrl || "";
  const getAttachmentDownloadUrl = row => row?.downloadURL || row?.downloadUrl || row?.previewURL || row?.previewUrl || row?.url || "";
  const getAttachmentTypeText = row => `${getAttachmentName(row)} ${getAttachmentPreviewUrl(row)}`.toLowerCase().split("?")[0];
  const isImageAttachment = row => /\.(jpg|jpeg|png|gif|bmp|webp|svg)$/.test(getAttachmentTypeText(row));
  const isPdfAttachment = row => /\.pdf$/.test(getAttachmentTypeText(row));
  const isRectifiedRecord = row =>
    !!(row?.rectifyActualTime || row?.rectifyMeasures || row?.verifyTime || row?.verifyResult || row?.verifyRemark);
  const detailPreviewImageUrls = computed(() =>
    detailAttachmentList.value
      .filter(isImageAttachment)
      .map(getAttachmentPreviewUrl)
      .filter(Boolean)
  );
  const getImagePreviewIndex = row => {
    const index = detailPreviewImageUrls.value.indexOf(getAttachmentPreviewUrl(row));
    return index > -1 ? index : 0;
  };
  const loadDetailAttachments = recordId => {
    detailAttachmentLoading.value = true;
    detailAttachmentList.value = [];
    return attachmentList({
      recordType: "safe_hidden",
      recordId,
    })
      .then(res => {
        detailAttachmentList.value = res?.data || [];
      })
      .catch(() => {
        detailAttachmentList.value = [];
        ElMessage.error("附件加载失败");
      })
      .finally(() => {
        detailAttachmentLoading.value = false;
      });
  };
  const downloadDetailAttachment = row => {
    const url = getAttachmentDownloadUrl(row);
    if (!url) {
      ElMessage.warning("文件地址无效,无法下载");
      return;
    }
    window.open(url, "_blank");
  };
  // 导入相关
@@ -657,6 +841,7 @@
          } else {
            item.isRectify = false;
          }
          item.isVerify = hasUserId(item.verifyUserId) && Number(item.verifyUserId) != Number(currentUserId.value);
        });
        return res;
      })
@@ -689,15 +874,18 @@
  const openForm = async (type, row) => {
    console.log("row", row);
    operationType.value = type;
    detailAttachmentList.value = [];
    form3.value = {
      verifyTime: "", // 验收时间
      verifyRemark: "", // 验收备注
      verifyResult: "", // 验收描述
      verifyUserId: "", // 验收人
      verifyUserName: "",
    };
    form2.value = {
      rectifyActualTime: "", // 实际整改完成时间
      rectifyMeasures: "", // 整改具体措施
      verifyUserId: "", // 验收人
    };
    if (type === "add") {
      form.value = {
@@ -749,6 +937,7 @@
      form2.value = {
        rectifyActualTime: row.rectifyActualTime, // 实际整改完成时间
        rectifyMeasures: row.rectifyMeasures, // 整改具体措施
        verifyUserId: normalizeUserId(row.verifyUserId), // 验收人
      };
    } else if (type === "edit3") {
      form.value = {
@@ -774,15 +963,41 @@
        verifyTime: row.verifyTime, // 验收时间
        verifyRemark: row.verifyRemark, // 验收备注
        verifyResult: row.verifyResult, // 验收描述
        verifyUserId: row.verifyUserId, // 验收人
        verifyUserId: normalizeUserId(row.verifyUserId), // 验收人
        verifyUserName: row.verifyUserName,
      };
      console.log("form3.value", form3.value);
      if (!form3.value.verifyUserId || form3.value.verifyUserId === "null") {
        form3.value.verifyUserId = Number(currentUserId.value); // 验收人
      }
      if (!form3.value.verifyTime || form3.value.verifyTime === "null") {
        form3.value.verifyTime = dayjs().format("YYYY-MM-DD"); // 验收描述
      }
    } else if (type === "detail") {
      form.value = {
        id: row.id,
        hiddenCode: row.hiddenCode, // 隐患编号
        location: row.location, // 隐患位置
        hiddenDesc: row.hiddenDesc, // 隐患描述
        createUser: row.createUser, // 上报人
        createUserName: row.createUserName,
        createTime: row.createTime, // 上报时间
        rectifyUserId: row.rectifyUserId, // 整改责任人
        rectifyUserName: row.rectifyUserName,
        rectifyTime: row.rectifyTime, // 整改完成期限
        rectifyUserMobile: row.rectifyUserMobile, // 整改责任人手机号
        riskLevel: row.riskLevel, // 隐患风险等级
        type: row.type, // 隐患类型
      };
      form2.value = {
        rectifyActualTime: row.rectifyActualTime, // 实际整改完成时间
        rectifyMeasures: row.rectifyMeasures, // 整改具体措施
        verifyUserId: normalizeUserId(row.verifyUserId), // 验收人
      };
      form3.value = {
        verifyTime: row.verifyTime, // 验收时间
        verifyRemark: row.verifyRemark, // 验收备注
        verifyResult: row.verifyResult, // 验收描述
        verifyUserId: normalizeUserId(row.verifyUserId), // 验收人
        verifyUserName: row.verifyUserName,
      };
      loadDetailAttachments(row.id);
    }
    dialogFormVisible.value = true;
  };
@@ -845,9 +1060,9 @@
      proxy.$refs["formRef3"].validate(valid => {
        if (valid) {
          safeHiddenUpdate({
            ...form3.value,
            ...form2.value,
            ...form.value,
            ...form3.value,
          }).then(res => {
            proxy.$modal.msgSuccess("提交成功");
            closeDia();
@@ -861,6 +1076,9 @@
  const closeDia = () => {
    proxy.resetForm("formRef");
    proxy.resetForm("formRef2");
    proxy.resetForm("formRef3");
    detailAttachmentList.value = [];
    detailAttachmentLoading.value = false;
    dialogFormVisible.value = false;
  };
  // 关闭产品弹框
@@ -872,12 +1090,18 @@
  const handleDelete = () => {
    let ids = [];
    if (selectedRows.value.length > 0) {
      const rectifiedRows = selectedRows.value.filter(isRectifiedRecord);
      if (rectifiedRows.length > 0) {
        const hiddenCodes = rectifiedRows.map(item => item.hiddenCode).filter(Boolean).join("、");
        proxy.$modal.msgWarning(`已整改的隐患不能删除${hiddenCodes ? `:${hiddenCodes}` : ""}`);
        return;
      }
      ids = selectedRows.value.map(item => item.id);
    } else {
      proxy.$modal.msgWarning("请选择数据");
      return;
    }
    ElMessageBox.confirm("选中的内容将被删除,是否确认删除?", "导出", {
    ElMessageBox.confirm("选中的未整改隐患及其附件将被删除,是否确认删除?", "提示", {
      confirmButtonText: "确认",
      cancelButtonText: "取消",
      type: "warning",
@@ -964,8 +1188,8 @@
    return "";
  };
  onMounted(() => {
    getCurrentFactoryName();
  onMounted(async () => {
    await getCurrentFactoryName();
    getList();
    userListNoPage().then(res => {
      userList.value = res.data;
@@ -1003,6 +1227,71 @@
    justify-content: space-between;
    margin-bottom: 10px;
  }
  .hidden-code-link {
    height: auto;
    padding: 0;
    font-weight: 500;
  }
  .detail-attachment-preview-list {
    min-height: 120px;
    margin-bottom: 20px;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(220px, 260px));
    gap: 12px;
    align-items: start;
  }
  .detail-attachment-preview-card {
    border: 1px solid #e5eaf3;
    border-radius: 6px;
    overflow: hidden;
    background: #fff;
  }
  .detail-attachment-header {
    min-height: 36px;
    padding: 6px 12px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    border-bottom: 1px solid #e5eaf3;
    background: #f7f9fc;
  }
  .detail-attachment-name {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-weight: 500;
    color: #303133;
  }
  .detail-attachment-image {
    width: 100%;
    height: 160px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: #fafafa;
  }
  .detail-attachment-frame {
    width: 100%;
    height: 180px;
    border: 0;
    display: block;
    background: #fafafa;
  }
  .detail-attachment-placeholder {
    min-height: 120px;
    padding: 12px;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 12px;
    color: #606266;
    background: #fafafa;
  }
  .detail-attachment-preview-list :deep(.el-empty) {
    grid-column: 1 / -1;
  }
  .print-preview-dialog {
    .el-dialog__body {
      padding: 0;