gongchunyi
11 小时以前 7b8e5ab57c3da7cfe46d1b0360f642bd1f841c06
fix: 异常图片上传、bug修改
已修改5个文件
179 ■■■■ 文件已修改
src/api/safeProduction/specialEquipmentManagement.js 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/PIMTable/PIMTable.vue 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/safeProduction/lineInspection/index.vue 31 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/safeProduction/safetyFacility/index.vue 64 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/safeProduction/specialEquipmentManagement/index.vue 60 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/safeProduction/specialEquipmentManagement.js
@@ -88,6 +88,14 @@
  });
}
export function specialEquipmentRectificationUpdate(data) {
  return request({
    url: "/safe/specialEquipment/rectification/update",
    method: "post",
    data,
  });
}
export function specialEquipmentRectificationClose(data) {
  return request({
    url: "/safe/specialEquipment/rectification/close",
src/components/PIMTable/PIMTable.vue
@@ -118,7 +118,7 @@
          <template v-for="(o, key) in item.operation"
                    :key="key">
            <el-button v-show="o.type != 'upload'"
                       v-if="o.showHide ? o.showHide(scope.row) : true"
                       v-if="isOperationVisible(o, scope.row)"
                       :disabled="isOperationDisabled(o, scope.row)"
                       :loading="isOperationLoading(o, scope.row)"
                       :plain="o.plain"
@@ -149,7 +149,7 @@
              "
                       v-if="o.type == 'upload'"
                       style="display: inline-block; width: 50px"
                       v-show="o.showHide ? o.showHide(scope.row) : true"
                       v-show="isOperationVisible(o, scope.row)"
                       :headers="uploadHeader"
                       :before-upload="(file) => beforeUpload(file, scope.$index)"
                       :on-change="
@@ -224,7 +224,9 @@
  };
  const formatters = (val, format) => {
    return typeof format === "function" ? format(val) : val;
    if (typeof format === "function") return format(val);
    if (format && typeof format === "object") return format[val] ?? val;
    return val;
  };
  // Props(使用 defineProps 的非 TS 形式)
@@ -374,6 +376,12 @@
      : !!operation.disabled;
  };
  const isOperationVisible = (operation, row) => {
    const visibleHandler = operation?.showHide ?? operation?.show;
    if (visibleHandler === undefined) return true;
    return typeof visibleHandler === "function" ? !!visibleHandler(row) : !!visibleHandler;
  };
  const isOperationLoading = (operation, row) => {
    if (!operation?.loading) return false;
    return typeof operation.loading === "function"
@@ -455,7 +463,7 @@
  // 文件上传前校验
  const beforeUpload = (rawFile, index) => {
    currentFiles.value[index] = {};
    if (rawfile.size > 1024 * 1024 * 10 * 10) {
    if (rawFile.size > 1024 * 1024 * 10 * 10) {
      ElMessage.error("上传文件不超过10M");
      return false;
    }
src/views/safeProduction/lineInspection/index.vue
@@ -176,6 +176,13 @@
            </template>
          </el-table-column>
          <el-table-column prop="checkDesc" label="检查说明" width="200" show-overflow-tooltip />
          <el-table-column label="现场照片" width="100">
            <template #default="{ row }">
              <el-tag :type="hasAttachments(row.storageBlobVOs) ? 'success' : 'info'">
                {{ hasAttachments(row.storageBlobVOs) ? '已上传' : '未上传' }}
              </el-tag>
            </template>
          </el-table-column>
          <el-table-column prop="checkTime" label="检查时间" width="180" />
          <el-table-column label="操作" width="120" fixed="right">
            <template #default="{ row }">
@@ -226,6 +233,11 @@
                      type="textarea"
                      :rows="2"
                      placeholder="请输入检查说明" />
          </el-form-item>
          <el-form-item v-if="recordForm.checkResult === '异常'" label="现场照片">
            <ImageUpload v-model:file-list="recordForm.storageBlobDTOs"
                         :limit="6"
                         button-text="上传照片" />
          </el-form-item>
          <el-form-item label="检查时间">
            <el-date-picker v-model="recordForm.checkTime"
@@ -368,9 +380,10 @@
<script setup>
import { Search } from "@element-plus/icons-vue";
import { nextTick, onMounted, ref, reactive, toRefs } from "vue";
import { onMounted, ref, reactive, toRefs } from "vue";
import { ElMessage, ElMessageBox } from "element-plus";
import PIMTable from "@/components/PIMTable/PIMTable.vue";
import ImageUpload from "@/components/AttachmentUpload/image/index.vue";
import { userListNoPage } from "@/api/system/user.js";
import {
  getLineInspectionList,
@@ -450,7 +463,8 @@
    checkContent: "",
    checkResult: "正常",
    checkDesc: "",
    checkTime: ""
    checkTime: "",
    storageBlobDTOs: []
  },
  // 隐患管理
  hazardDialogVisible: false,
@@ -684,6 +698,9 @@
  return map[status] || "info";
};
const getAttachments = row => row?.storageBlobDTOs || row?.storageBlobVOs || [];
const hasAttachments = attachments => Array.isArray(attachments) && attachments.length > 0;
// 打开表单
const openForm = (type, row = null) => {
  dialogType.value = type;
@@ -809,7 +826,8 @@
    checkContent: "",
    checkResult: "正常",
    checkDesc: "",
    checkTime: ""
    checkTime: "",
    storageBlobDTOs: []
  });
  recordFormVisible.value = true;
};
@@ -823,7 +841,8 @@
    checkContent: row.checkContent,
    checkResult: row.checkResult,
    checkDesc: row.checkDesc,
    checkTime: row.checkTime
    checkTime: row.checkTime,
    storageBlobDTOs: getAttachments(row)
  });
  recordFormVisible.value = true;
};
@@ -849,6 +868,10 @@
const submitRecordForm = async () => {
  try {
    await recordFormRef.value.validate();
    if (recordForm.value.checkResult === "异常" && !hasAttachments(recordForm.value.storageBlobDTOs)) {
      ElMessage.warning("巡检结果异常时请上传现场照片");
      return;
    }
    const api = recordForm.value.id ? updateInspectionRecord : addInspectionRecord;
    const res = await api({ ...recordForm.value });
    if (res.code === 200) {
src/views/safeProduction/safetyFacility/index.vue
@@ -276,7 +276,8 @@
            <el-form-item label="巡检编号"
                          prop="inspectionCode">
              <el-input v-model="inspectionForm.inspectionCode"
                        placeholder="请输入巡检编号" />
                        placeholder="请输入巡检编号"
                        :disabled="isInspectionView" />
            </el-form-item>
          </el-col>
          <el-col :span="12">
@@ -284,7 +285,8 @@
                          prop="inspectionType">
              <el-select v-model="inspectionForm.inspectionType"
                         placeholder="请选择巡检类型"
                         style="width: 100%">
                         style="width: 100%"
                         :disabled="isInspectionView">
                <el-option label="定期巡检" value="定期巡检" />
                <el-option label="临时巡检" value="临时巡检" />
              </el-select>
@@ -298,12 +300,13 @@
                          placeholder="请选择计划巡检时间"
                          format="YYYY-MM-DD HH:mm:ss"
                          value-format="YYYY-MM-DD HH:mm:ss"
                          style="width: 100%" />
                          style="width: 100%"
                          :disabled="isInspectionView" />
        </el-form-item>
        <template v-if="inspectionDialogTitle === '巡检'">
        <template v-if="inspectionDialogType !== 'add'">
          <el-form-item label="检查结果"
                        prop="checkResult">
            <el-radio-group v-model="inspectionForm.checkResult">
            <el-radio-group v-model="inspectionForm.checkResult" :disabled="isInspectionView">
              <el-radio label="正常">正常</el-radio>
              <el-radio label="异常">异常</el-radio>
            </el-radio-group>
@@ -312,15 +315,23 @@
            <el-input v-model="inspectionForm.checkDesc"
                      type="textarea"
                      :rows="3"
                      placeholder="请输入检查说明" />
                      placeholder="请输入检查说明"
                      :disabled="isInspectionView" />
          </el-form-item>
          <el-form-item v-if="inspectionForm.checkResult === '异常'" label="现场照片">
            <ImageUpload v-model:file-list="inspectionForm.storageBlobDTOs"
                         :limit="6"
                         button-text="上传照片"
                         :disabled="isInspectionView" />
          </el-form-item>
        </template>
      </el-form>
      <template #footer>
        <span class="dialog-footer">
          <el-button type="primary"
          <el-button v-if="!isInspectionView"
                     type="primary"
                     @click="submitInspectionForm">确定</el-button>
          <el-button @click="inspectionDialogVisible = false">取消</el-button>
          <el-button @click="inspectionDialogVisible = false">{{ isInspectionView ? '关闭' : '取消' }}</el-button>
        </span>
      </template>
    </el-dialog>
@@ -338,12 +349,14 @@
            <el-input v-model="rectificationForm.problemDesc"
                      type="textarea"
                      :rows="3"
                      placeholder="请输入问题描述" />
                      placeholder="请输入问题描述"
                      :disabled="isRectificationView" />
          </el-form-item>
          <el-form-item label="问题等级">
            <el-select v-model="rectificationForm.problemLevel"
                       placeholder="请选择问题等级"
                       style="width: 100%">
                       style="width: 100%"
                       :disabled="isRectificationView">
              <el-option label="一般" value="一般" />
              <el-option label="重大" value="重大" />
            </el-select>
@@ -354,27 +367,31 @@
                            placeholder="请选择计划整改时间"
                            format="YYYY-MM-DD HH:mm:ss"
                            value-format="YYYY-MM-DD HH:mm:ss"
                            style="width: 100%" />
                            style="width: 100%"
                            :disabled="isRectificationView" />
          </el-form-item>
        </template>
        <el-form-item label="整改说明" v-if="rectificationDialogTitle === '整改'">
          <el-input v-model="rectificationForm.rectifyDesc"
                    type="textarea"
                    :rows="3"
                    placeholder="请输入整改说明" />
                    placeholder="请输入整改说明"
                    :disabled="isRectificationView" />
        </el-form-item>
        <el-form-item label="验收说明" v-if="rectificationDialogTitle === '验收'">
          <el-input v-model="rectificationForm.verifyDesc"
                    type="textarea"
                    :rows="3"
                    placeholder="请输入验收说明" />
                    placeholder="请输入验收说明"
                    :disabled="isRectificationView" />
        </el-form-item>
      </el-form>
      <template #footer>
        <span class="dialog-footer">
          <el-button type="primary"
          <el-button v-if="!isRectificationView"
                     type="primary"
                     @click="submitRectificationForm">确定</el-button>
          <el-button @click="rectificationDialogVisible = false">取消</el-button>
          <el-button @click="rectificationDialogVisible = false">{{ isRectificationView ? '关闭' : '取消' }}</el-button>
        </span>
      </template>
    </el-dialog>
@@ -386,6 +403,7 @@
import { onMounted, ref, reactive, toRefs, computed } from "vue";
import { ElMessage, ElMessageBox } from "element-plus";
import PIMTable from "@/components/PIMTable/PIMTable.vue";
import ImageUpload from "@/components/AttachmentUpload/image/index.vue";
import {
  getFacilityLedgerList,
  addFacilityLedger,
@@ -436,7 +454,7 @@
  inspectionTableData: [],
  inspectionForm: {
    id: null, facilityId: null, inspectionCode: "", inspectionType: "定期巡检",
    planTime: "", checkResult: "", checkDesc: ""
    planTime: "", checkResult: "", checkDesc: "", storageBlobDTOs: []
  },
  inspectionDialogVisible: false,
  inspectionDialogTitle: "",
@@ -469,6 +487,8 @@
const ledgerFormRef = ref();
const inspectionFormRef = ref();
const rectificationFormRef = ref();
const isInspectionView = computed(() => inspectionDialogType.value === "view");
const isRectificationView = computed(() => rectificationDialogType.value === "view");
// 自动计算下次检查时间
const computedNextCheckTime = computed(() => {
@@ -702,17 +722,17 @@
    inspectionDialogTitle.value = "发起巡检";
    Object.assign(inspectionForm.value, {
      id: null, facilityId: row.id, inspectionCode: "", inspectionType: "定期巡检",
      planTime: "", checkResult: "", checkDesc: ""
      planTime: "", checkResult: "", checkDesc: "", storageBlobDTOs: []
    });
  } else if (type === "do") {
    inspectionDialogTitle.value = "巡检";
    Object.assign(inspectionForm.value, {
      id: row.id, facilityId: row.facilityId, inspectionCode: row.inspectionCode,
      inspectionType: row.inspectionType, planTime: row.planTime, checkResult: "", checkDesc: ""
      inspectionType: row.inspectionType, planTime: row.planTime, checkResult: "", checkDesc: "", storageBlobDTOs: []
    });
  } else {
    inspectionDialogTitle.value = "查看巡检";
    Object.assign(inspectionForm.value, { ...row });
    Object.assign(inspectionForm.value, { ...row, storageBlobDTOs: row.storageBlobVOs || row.storageBlobDTOs || [] });
  }
  inspectionDialogVisible.value = true;
};
@@ -721,6 +741,10 @@
  try {
    await inspectionFormRef.value.validate();
    if (inspectionDialogTitle.value === "巡检") {
      if (inspectionForm.value.checkResult === "异常" && !hasAttachments(inspectionForm.value.storageBlobDTOs)) {
        ElMessage.warning("检查结果异常时请上传现场照片");
        return;
      }
      inspectionForm.value.status = "已巡检";
      inspectionForm.value.actualTime = new Date().toISOString().replace("T", " ").substring(0, 19);
    }
@@ -736,6 +760,8 @@
  }
};
const hasAttachments = attachments => Array.isArray(attachments) && attachments.length > 0;
const handleDeleteInspection = row => {
  ElMessageBox.confirm("确认删除该巡检记录吗?", "删除", {
    confirmButtonText: "确认", cancelButtonText: "取消", type: "warning"
src/views/safeProduction/specialEquipmentManagement/index.vue
@@ -107,6 +107,9 @@
        <el-form-item label="问题描述" prop="problemDescription"><el-input v-model="recordForm.problemDescription" type="textarea" :rows="3" /></el-form-item>
        <el-form-item label="处理措施" prop="disposeMeasure"><el-input v-model="recordForm.disposeMeasure" type="textarea" :rows="3" /></el-form-item>
        <el-form-item label="附件说明" prop="attachmentRemark"><el-input v-model="recordForm.attachmentRemark" type="textarea" :rows="2" /></el-form-item>
        <el-form-item label="附件上传">
          <FileUpload v-model:file-list="recordForm.storageBlobDTOs" :limit="6" />
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button type="primary" @click="submitRecordForm">确定</el-button>
@@ -137,6 +140,9 @@
        <el-form-item label="隐患描述" prop="hazardDescription"><el-input v-model="rectForm.hazardDescription" type="textarea" :rows="3" /></el-form-item>
        <el-form-item label="整改措施" prop="rectificationMeasures"><el-input v-model="rectForm.rectificationMeasures" type="textarea" :rows="3" /></el-form-item>
        <el-form-item label="整改结果" prop="rectificationResult"><el-input v-model="rectForm.rectificationResult" type="textarea" :rows="3" /></el-form-item>
        <el-form-item label="整改附件">
          <FileUpload v-model:file-list="rectForm.storageBlobDTOs" :limit="6" />
        </el-form-item>
        <el-form-item label="备注" prop="remarks"><el-input v-model="rectForm.remarks" type="textarea" :rows="2" /></el-form-item>
      </el-form>
      <template #footer>
@@ -149,7 +155,7 @@
<script setup>
import { Search } from "@element-plus/icons-vue";
import { computed, reactive, ref, onMounted, getCurrentInstance } from "vue";
import { computed, reactive, ref, onMounted } from "vue";
import { ElMessage, ElMessageBox } from "element-plus";
import PIMTable from "@/components/PIMTable/PIMTable.vue";
import {
@@ -164,12 +170,12 @@
  specialEquipmentRecordDel,
  specialEquipmentRectificationListPage,
  specialEquipmentRectificationAdd,
  specialEquipmentRectificationClose,
  specialEquipmentRectificationUpdate,
  specialEquipmentRectificationDel,
} from "@/api/safeProduction/specialEquipmentManagement.js";
import { userListNoPageByTenantId } from "@/api/system/user.js";
import FileUpload from "@/components/AttachmentUpload/file/index.vue";
const { proxy } = getCurrentInstance();
const activeTab = ref("ledger");
const userOptions = ref([]);
@@ -222,6 +228,7 @@
  executorName: "",
  nextDueDate: "",
  attachmentRemark: "",
  storageBlobDTOs: [],
});
const recordRules = {
  equipmentId: [{ required: true, message: "请选择关联设备", trigger: "change" }],
@@ -243,6 +250,7 @@
  rectificationStatus: 1,
  rectificationMeasures: "",
  rectificationResult: "",
  storageBlobDTOs: [],
  remarks: "",
});
const rectRules = {
@@ -254,6 +262,39 @@
const ledgerOptions = ref([]);
const activeLedgerOptions = computed(() => ledgerOptions.value);
const activeUserOptions = computed(() => userOptions.value || []);
const getAttachments = row => row?.storageBlobDTOs || row?.storageBlobVOs || [];
const getDueDays = (dateValue) => {
  if (!dateValue) return null;
  const today = new Date();
  today.setHours(0, 0, 0, 0);
  const dueDate = new Date(`${dateValue}T00:00:00`);
  if (Number.isNaN(dueDate.getTime())) return null;
  return Math.ceil((dueDate.getTime() - today.getTime()) / 86400000);
};
const formatDueStatus = (dateValue) => {
  const days = getDueDays(dateValue);
  if (days === null) return "未设置";
  if (days < 0) return "已逾期";
  if (days === 0) return "今日到期";
  if (days <= 30) return `${days}天后到期`;
  return "未到期";
};
const getDueStatusType = (dateValue) => {
  const days = getDueDays(dateValue);
  if (days === null) return "info";
  if (days < 0) return "danger";
  if (days <= 7) return "danger";
  if (days <= 30) return "warning";
  return "success";
};
const getRectStatusType = status => {
  const map = { 1: "danger", 2: "warning", 3: "primary", 4: "success" };
  return map[status] || "info";
};
const ledgerColumns = [
  { label: "设备编号", prop: "equipmentNo" },
@@ -279,6 +320,7 @@
  { label: "执行人", prop: "executorName" },
  { label: "执行结果", prop: "executeResult" },
  { label: "下次到期日期", prop: "nextDueDate" },
  { label: "到期提醒", prop: "nextDueDate", dataType: "tag", formatData: formatDueStatus, formatType: getDueStatusType },
  {
    label: "操作",
    dataType: "action",
@@ -296,12 +338,13 @@
  { label: "发现日期", prop: "discoveredDate" },
  { label: "责任人", prop: "responsibleUserName" },
  { label: "整改期限", prop: "rectificationDeadline" },
  { label: "整改状态", prop: "rectificationStatus", formatData: { 1: "待整改", 2: "整改中", 3: "待复核", 4: "已闭环" } },
  { label: "整改状态", prop: "rectificationStatus", dataType: "tag", formatData: { 1: "待整改", 2: "整改中", 3: "待复核", 4: "已闭环" }, formatType: getRectStatusType },
  {
    label: "操作",
    dataType: "action",
    width: "220",
    operation: [
      { name: "编辑", clickFun: (row) => openRectForm(row) },
      { name: "删除", clickFun: (row) => deleteRect(row.id) },
    ],
  },
@@ -406,8 +449,10 @@
    executorName: "",
    nextDueDate: "",
    attachmentRemark: "",
    storageBlobDTOs: [],
  });
  Object.assign(recordForm, row);
  recordForm.storageBlobDTOs = getAttachments(row);
  if (!recordForm.executorId && recordForm.executorName) {
    const matched = userOptions.value.find((item) => (item.nickName || item.userName) === recordForm.executorName);
    recordForm.executorId = matched?.userId || "";
@@ -447,20 +492,23 @@
    rectificationStatus: 1,
    rectificationMeasures: "",
    rectificationResult: "",
    storageBlobDTOs: [],
    remarks: "",
  });
  Object.assign(rectForm, row);
  rectForm.storageBlobDTOs = getAttachments(row);
  if (!rectForm.responsibleUserId && rectForm.responsibleUserName) {
    const matched = userOptions.value.find((item) => (item.nickName || item.userName) === rectForm.responsibleUserName);
    rectForm.responsibleUserId = matched?.userId || "";
  }
  rectDialogTitle.value = "新增整改";
  rectDialogTitle.value = row.id ? "编辑整改" : "新增整改";
  rectDialogVisible.value = true;
};
const submitRectForm = async () => {
  await rectFormRef.value.validate();
  await specialEquipmentRectificationAdd(rectForm);
  const api = rectForm.id ? specialEquipmentRectificationUpdate : specialEquipmentRectificationAdd;
  await api(rectForm);
  ElMessage.success("保存成功");
  rectDialogVisible.value = false;
  rectQuery();