已修改11个文件
565 ■■■■ 文件已修改
src/components/PIMTable/PIMTable.vue 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/inspectionManagement/components/formDia.vue 56 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/inspectionManagement/index.vue 119 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/repair/Modal/MaintainModal.vue 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/repair/Modal/RepairModal.vue 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/repair/index.vue 17 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/upkeep/Form/MaintenanceModal.vue 21 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/upkeep/Form/PlanModal.vue 192 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/upkeep/Form/UpkeepDetailModal.vue 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/upkeep/Form/formDia.vue 43 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/upkeep/index.vue 58 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/PIMTable/PIMTable.vue
@@ -146,7 +146,7 @@
              @click.stop="o.clickFun(scope.row)"
              :key="key"
            >
              {{ o.name }}
              {{ typeof o.name === 'function' ? o.name(scope.row) : o.name }}
            </el-button>
            <el-upload
              :action="
@@ -426,12 +426,13 @@
};
const getOperationColor = (operation, row) => {
  const colorValue = typeof operation?.color === 'function' ? operation.color(row) : operation?.color;
  const baseColor =
    operation?.name === "删除" || operation?.name === "delete"
      ? "#D93025"
      : operation?.name === "详情"
      ? "#67C23A"
      : operation?.color || "var(--el-color-primary)";
      : colorValue || "var(--el-color-primary)";
  if (isOperationDisabled(operation, row)) {
    return fadeColor(baseColor, 0.35);
src/views/equipmentManagement/inspectionManagement/components/formDia.vue
@@ -30,6 +30,17 @@
              <el-input v-model="form.remarks" placeholder="请输入备注" type="textarea" />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="任务状态" prop="isActive">
              <el-switch
                v-model="form.isActive"
                :active-value="1"
                :inactive-value="0"
                active-text="启用"
                inactive-text="停用"
              />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row>
          <el-col :span="12">
@@ -122,7 +133,8 @@
    frequencyType: '',
    frequencyDetail: '',
    week: '',
    time: ''
    time: '',
    isActive: 1  // 默认启用
  },
    rules: {
        taskId: [{ required: true, message: "请选择设备", trigger: "change" },],
@@ -217,9 +229,35 @@
  await loadDeviceName();
  
  if (type === 'edit' && row) {
    form.value = {...row}
    form.value.inspector = form.value.inspectorIds.split(',').map(Number)
    form.value = {
      ...data.form,  // 先复制默认表单
      ...row,        // 再覆盖 row 中的值
    }
    // 确保 inspectorIds 存在才进行 split
    if (form.value.inspectorIds) {
      form.value.inspector = form.value.inspectorIds.split(',').map(Number)
    } else {
      form.value.inspector = []
    }
    // 确保 isActive 有值,默认启用
    if (form.value.isActive === undefined || form.value.isActive === null) {
      form.value.isActive = 1
    }
    if (row.frequencyDetail) {
      if (row.frequencyType === 'WEEKLY') {
        const parts = row.frequencyDetail.split(',')
        if (parts.length === 2) {
          form.value.week = parts[0]
          form.value.time = parts[1]
        }
      } else if (row.frequencyType === 'DAILY') {
        form.value.frequencyDetail = row.frequencyDetail
      } else {
        form.value.frequencyDetail = row.frequencyDetail
      }
    }
    // 如果有设备ID,自动设置设备信息
    if (form.value.taskId) {
      setDeviceModel(form.value.taskId);
@@ -249,7 +287,8 @@
    frequencyType: '',
    frequencyDetail: '',
    week: '',
    time: ''
    time: '',
    isActive: 1  // 默认启用
  }
}
@@ -258,8 +297,11 @@
  proxy.$refs["formRef"].validate(async valid => {
    if (valid) {
      try {
        form.value.inspectorIds = form.value.inspector.join(',')
        delete form.value.inspector
        // 确保 inspector 是数组才进行 join
        if (form.value.inspector && Array.isArray(form.value.inspector)) {
          form.value.inspectorIds = form.value.inspector.join(',')
          delete form.value.inspector
        }
        
        if (form.value.frequencyType === 'WEEKLY') {
          let frequencyDetail = ''
src/views/equipmentManagement/inspectionManagement/index.vue
@@ -55,8 +55,6 @@
                  :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"
@@ -69,6 +67,10 @@
              <span v-else
                    class="no-data">--</span>
            </div>
          </template>
          <template #statusRef="{ row }">
            <el-tag v-if="row.isActive === true || row.isActive === 1" type="success">启用</el-tag>
            <el-tag v-else type="danger">停用</el-tag>
          </template>
        </PIMTable>
      </div>
@@ -83,6 +85,7 @@
  import { Delete, Plus } from "@element-plus/icons-vue";
  import { onMounted, ref, reactive, getCurrentInstance, nextTick } from "vue";
  import { ElMessageBox } from "element-plus";
  import dayjs from "dayjs";
  // 组件引入
  import PIMTable from "@/components/PIMTable/PIMTable.vue";
@@ -94,6 +97,7 @@
    delTimingTask,
    inspectionTaskList,
    timingTaskList,
    addOrEditTimingTask,
  } from "@/api/inspectionManagement/index.js";
  // 全局变量
@@ -109,8 +113,8 @@
  // 单选框配置
  const activeRadio = ref("taskManage");
  const radios = reactive([
    { name: "taskManage", label: "定时任务管理" },
    { name: "task", label: "定时任务记录" },
    { name: "taskManage", label: "巡检任务管理" },
    { name: "task", label: "巡检任务记录" },
  ]);
  // 表格数据
@@ -132,12 +136,6 @@
      prop: "frequencyType",
      label: "频次",
      minWidth: 150,
      // formatter: (_, __, val) => ({
      //   DAILY: "每日",
      //   WEEKLY: "每周",
      //   MONTHLY: "每月",
      //   QUARTERLY: "季度"
      // }[val] || "")
      formatData: params => {
        return params === "DAILY"
          ? "每日"
@@ -175,38 +173,55 @@
      },
    },
    { prop: "registrant", label: "登记人", minWidth: 100 },
    { prop: "createTime", label: "登记日期", minWidth: 100 },
    { prop: "createTime", label: "登记日期", minWidth: 120, formatData: (cell) => cell ? dayjs(cell).format("YYYY-MM-DD HH:MM:ss") : "-" },
  ]);
  const statusColumn = {
    prop: "isActive",
    label: "任务状态",
    minWidth: 100,
    align: "center",
    dataType: "slot",
    slot: "statusRef",
  };
  // 操作列配置
  const getOperationColumn = operations => {
    if (!operations || operations.length === 0) return null;
    const operationList = operations
      .map(op => {
        switch (op) {
          case "edit":
            return {
              name: "编辑",
              clickFun: handleAdd,
              color: "#409EFF",
            };
          case "viewFile":
            return {
              name: "查看附件",
              clickFun: viewFile,
              color: "#67C23A",
            };
          case "toggleActive":
            return {
              name: (row) => row.isActive === true || row.isActive === 1 ? "停用" : "启用",
              clickFun: handleToggleActive,
              color: (row) => row.isActive === true || row.isActive === 1 ? "#F56C6C" : "#67C23A",
            };
          default:
            return null;
        }
      })
      .filter(Boolean);
    const operationConfig = {
      label: "操作",
      width: 130,
      width: 200,
      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),
      operation: operationList,
    };
    return operationConfig;
@@ -219,12 +234,13 @@
  // 单选变化
  const radioChange = value => {
    if (value === "taskManage") {
      const operationColumn = getOperationColumn(["edit"]);
      const operationColumn = getOperationColumn(["edit", "toggleActive"]);
      tableColumns.value = [
        ...columns.value,
        statusColumn,
        ...(operationColumn ? [operationColumn] : []),
      ];
      operationsArr.value = ["edit"];
      operationsArr.value = ["edit", "toggleActive"];
    } else if (value === "task") {
      const operationColumn = getOperationColumn(["viewFile"]);
      tableColumns.value = [
@@ -346,6 +362,35 @@
      .catch(() => {});
  };
  // 启用/停用切换
  const handleToggleActive = async (row) => {
    const newStatus = row.isActive === true || row.isActive === 1 ? 0 : 1;
    const actionText = newStatus === 1 ? "启用" : "停用";
    try {
      await proxy.$modal.confirm(`是否确认${actionText}该任务?`)
    } catch {
      return
    }
    try {
      await addOrEditTimingTask({
        id: row.id,
        taskId: row.taskId,
        taskName: row.taskName,
        inspectorIds: row.inspectorIds,
        remarks: row.remarks,
        frequencyType: row.frequencyType,
        frequencyDetail: row.frequencyDetail,
        isActive: newStatus,
      })
      proxy.$modal.msgSuccess(`${actionText}成功`)
      handleQuery()
    } catch (error) {
      console.error(`${actionText}失败:`, error)
    }
  };
  // 多选变更
  const handleSelectionChange = selection => {
    selectedRows.value = selection;
@@ -361,11 +406,11 @@
      .then(() => {
        // 根据当前选中的标签页调用不同的导出接口
        if (activeRadio.value === "taskManage") {
          // 定时任务管理
          proxy.download("/timingTask/export", {}, "定时任务管理.xlsx");
          // 保养任务管理
          proxy.download("/timingTask/export", {}, "保养任务管理.xlsx");
        } else if (activeRadio.value === "task") {
          // 定时任务记录
          proxy.download("/inspectionTask/export", {}, "定时任务记录.xlsx");
          proxy.download("/inspectionTask/export", {}, "保养任务记录.xlsx");
        }
      })
      .catch(() => {
src/views/equipmentManagement/repair/Modal/MaintainModal.vue
@@ -10,10 +10,19 @@
  >
    <el-form ref="formRef" :model="form" :rules="rules" label-width="90px">
      <el-form-item label="维修人" prop="maintenanceName">
        <el-input v-model="form.maintenanceName" disabled placeholder="报修时指定的维修人" />
        <el-input
          v-model="form.maintenanceName"
          :placeholder="isEditableMaintenanceName ? '请输入维修人姓名' : '报修时指定的维修人'"
          :disabled="!isEditableMaintenanceName"
        />
      </el-form-item>
      <el-form-item label="维修结果" prop="maintenanceResult">
        <el-input v-model="form.maintenanceResult" placeholder="请输入维修结果" />
        <el-input
          v-model="form.maintenanceResult"
          type="textarea"
          :autosize="{ minRows: 2, maxRows: 6 }"
          placeholder="请输入维修结果"
        />
      </el-form-item>
      <el-form-item label="维修状态" prop="status">
        <el-select v-model="form.status" style="width: 100%">
@@ -57,11 +66,13 @@
</template>
<script setup>
import { computed } from "vue";
import FormDialog from "@/components/Dialog/FormDialog.vue";
import { addMaintain, uploadRepairFile } from "@/api/equipmentManagement/repair";
import { REPAIR_FILE_TYPE_MAINTAIN } from "@/api/equipmentManagement/repairFileType.js";
import useFormData from "@/hooks/useFormData";
import useUserStore from "@/store/modules/user";
import { userListNoPage } from "@/api/system/user.js";
import dayjs from "dayjs";
import { ElMessage } from "element-plus";
import { UploadFilled } from "@element-plus/icons-vue";
@@ -80,6 +91,23 @@
const ATTACH_MAX_MB = 50;
const userStore = useUserStore();
const systemUserNames = ref([]);
const isSystemUser = (name) => {
  return systemUserNames.value.includes(name);
};
//  维修人是否可编辑:外部人员时可以编辑修改
const isEditableMaintenanceName = computed(() => {
  const name = form.maintenanceName;
  if (!name) return false;
  return !isSystemUser(name);
});
const loadSystemUsers = async () => {
  const res = await userListNoPage();
  systemUserNames.value = (res?.data || []).map((u) => u.nickName);
};
const rules = {
  maintenanceName: [{ required: true, message: "请选择维修人", trigger: "change" }],
@@ -141,7 +169,9 @@
const sendForm = async () => {
  const valid = await formRef.value?.validate().catch(() => false);
  if (!valid) return;
  if (form.maintenanceName !== userStore.nickName) {
  const maintenanceName = form.maintenanceName;
  // 如果维修人是系统用户且非当前用户,禁止提交
  if (isSystemUser(maintenanceName) && maintenanceName !== userStore.nickName) {
    ElMessage.warning("仅指定的维修人可进行维修");
    return;
  }
@@ -183,8 +213,11 @@
  clearAttachmentQueue();
  visible.value = true;
  await nextTick();
  await loadSystemUsers();
  setForm(row);
  if (row?.maintenanceName && row.maintenanceName !== userStore.nickName) {
  const maintenanceName = row?.maintenanceName;
  // 如果维修人是系统用户且非当前用户,禁止操作
  if (isSystemUser(maintenanceName) && maintenanceName !== userStore.nickName) {
    ElMessage.warning("仅指定的维修人可进行维修");
    visible.value = false;
  }
src/views/equipmentManagement/repair/Modal/RepairModal.vue
@@ -74,8 +74,10 @@
          <el-form-item label="维修人" required>
            <el-select
              v-model="form.maintenanceName"
              placeholder="请选择维修人"
              placeholder="请选择或输入维修人"
              filterable
              allow-create
              default-first-option
              clearable
              style="width: 100%"
            >
@@ -351,7 +353,7 @@
    return;
  }
  if (!form.maintenanceName) {
    ElMessage.warning("请选择维修人");
    ElMessage.warning("请选择或输入维修人");
    return;
  }
  loading.value = true;
src/views/equipmentManagement/repair/index.vue
@@ -242,6 +242,7 @@
import RepairDetailModal from "./Modal/RepairDetailModal.vue";
import { getToken } from "@/utils/auth";
import useUserStore from "@/store/modules/user";
import { userListNoPage } from "@/api/system/user.js";
import {
  REPAIR_FILE_TYPE_PROBLEM,
  isProblemRepairFile,
@@ -261,6 +262,14 @@
const acceptanceModalRef = ref();
const repairDetailModalRef = ref();
const userStore = useUserStore();
const systemUserNames = ref([]);
const loadSystemUsers = async () => {
  const res = await userListNoPage();
  systemUserNames.value = (res?.data || []).map((u) => u.nickName);
};
const isSystemUser = (name) => systemUserNames.value.includes(name);
// 表格多选框选中项
const multipleList = ref([]);
@@ -424,11 +433,14 @@
const isCurrentUser = (name) => !!name && name === userStore.nickName;
const canEdit = (row) => row.status === 0;
/** 仅报修时指定的维修人可维修 */
//  仅报修时指定的维修人或外部人员时由报修人提交维修
const canMaintain = (row) => {
  if (row.status !== 0) return false;
  if (!row.maintenanceName) return false;
  return isCurrentUser(row.maintenanceName);
  if (isSystemUser(row.maintenanceName)) {
    return isCurrentUser(row.maintenanceName);
  }
  return true;
};
const canDelete = (row) => row.status === 0;
/** 仅报修时指定的验收人可验收 */
@@ -645,6 +657,7 @@
onMounted(() => {
  getTableData();
  loadSystemUsers();
});
</script>
src/views/equipmentManagement/upkeep/Form/MaintenanceModal.vue
@@ -10,8 +10,9 @@
    <el-form :model="form" label-width="100px">
      <el-form-item label="实际保养人">
        <el-input
          v-model="form.maintenanceActuallyName"
          placeholder="请输入实际保养人"
          :model-value="currentUserName"
          disabled
          placeholder="当前登录用户"
        ></el-input>
      </el-form-item>
      <el-form-item label="实际保养日期">
@@ -48,6 +49,7 @@
</template>
<script setup>
import { computed } from "vue";
import FormDialog from "@/components/Dialog/FormDialog.vue";
import { addMaintenance } from "@/api/equipmentManagement/upkeep";
import useFormData from "@/hooks/useFormData";
@@ -67,6 +69,8 @@
const loading = ref(false);
const userStore = useUserStore();
const currentUserName = computed(() => userStore.nickName || userStore.name || "");
const { form, resetForm } = useFormData({
  maintenanceActuallyName: undefined, // 实际保养人
  maintenanceActuallyTime: undefined, // 实际保养日期
@@ -75,10 +79,10 @@
});
const setForm = (data) => {
  form.maintenanceActuallyName =
    data.maintenanceActuallyName ?? userStore.nickName;
  // 实际保养人自动填充当前登录人,不可编辑
  form.maintenanceActuallyName = userStore.nickName || userStore.name || "";
  form.maintenanceActuallyTime =
    data.maintenanceActuallyTime
    data.maintenanceActuallyTime
      ? dayjs(data.maintenanceActuallyTime).format("YYYY-MM-DD HH:mm:ss")
      : dayjs().format("YYYY-MM-DD HH:mm:ss");
  form.maintenanceResult = data.maintenanceResult;
@@ -91,7 +95,12 @@
const sendForm = async () => {
  loading.value = true;
  try {
    const { code } = await addMaintenance({ id: planId.value, ...form });
    // 确保实际保养人是当前登录人
    const payload = {
      ...form,
      maintenanceActuallyName: userStore.nickName || userStore.name || "",
    };
    const { code } = await addMaintenance({ id: planId.value, ...payload });
    if (code == 200) {
      ElMessage.success("保养成功");
      emits("ok");
src/views/equipmentManagement/upkeep/Form/PlanModal.vue
@@ -2,12 +2,12 @@
  <FormDialog
    v-model="visible"
    :title="id ? '编辑设备保养计划' : '新增设备保养计划'"
    width="640px"
    width="680px"
    @confirm="sendForm"
    @cancel="handleCancel"
    @close="handleClose"
  >
    <el-form :model="form" label-width="100px">
    <el-form ref="formRef" :model="form" :rules="rules" label-width="120px">
      <el-form-item label="设备名称">
        <el-select
          v-model="form.deviceLedgerId"
@@ -32,19 +32,44 @@
          disabled
        />
      </el-form-item>
      <el-form-item label="保养项目">
        <el-input
          v-model="form.maintenanceLocation"
          type="textarea"
          :rows="3"
          placeholder="请输入保养项目"
        />
      </el-form-item>
      <el-form-item label="录入人">
        <el-input
          :model-value="registrantDisplayName"
          disabled
          placeholder="当前登录用户"
        />
      </el-form-item>
      <el-form-item label="保养人" prop="maintenancePerson">
        <el-select
          v-model="form.maintenancePerson"
          filterable
          default-first-option
          :reserve-keyword="false"
          placeholder="请选择保养人"
          style="width: 100%"
        >
          <el-option
            v-for="item in userList"
            :key="'mp-' + item.userId"
            :label="item.nickName"
            :value="item.userId"
          />
        </el-select>
      </el-form-item>
      <el-form-item label="保养部位" prop="maintenanceLocation">
        <el-input
          v-model="form.maintenanceLocation"
          type="textarea"
          :rows="3"
          placeholder="请输入保养部位"
        />
      </el-form-item>
      <el-form-item label="保养内容" prop="maintenanceItems">
        <el-input
          v-model="form.maintenanceItems"
          type="textarea"
          :rows="3"
          placeholder="请输入保养内容"
        />
      </el-form-item>
      <el-form-item v-if="id" label="保修状态">
@@ -54,7 +79,7 @@
          <el-option label="失败" :value="2"></el-option>
        </el-select>
      </el-form-item>
      <el-form-item label="计划保养日期">
      <el-form-item label="计划保养日期" prop="maintenancePlanTime">
        <el-date-picker
          style="width: 100%"
          v-model="form.maintenancePlanTime"
@@ -90,15 +115,14 @@
} from "@/api/equipmentManagement/upkeep";
import {
  listMaintenanceTaskFiles,
  bindMaintenanceTaskFile,
  uploadMaintenanceTaskFile,
  delMaintenanceTaskFile,
} from "@/api/equipmentManagement/maintenanceTaskFile";
import { ElMessage } from "element-plus";
import { Plus } from "@element-plus/icons-vue";
import useFormData from "@/hooks/useFormData";
import { getDeviceLedger } from "@/api/equipmentManagement/ledger";
import { computed, onMounted, ref } from "vue";
import { userListNoPageByTenantId } from "@/api/system/user.js";
import { computed, nextTick, onMounted, ref, unref } from "vue";
import dayjs from "dayjs";
import useUserStore from "@/store/modules/user.js";
import request from "@/utils/request";
@@ -114,10 +138,21 @@
const pendingTempFiles = ref([]);
const planFileList = ref([]);
// 编辑模式下已保存但待删除的文件列表
const pendingDeleteFiles = ref([]);
const registrantDisplayName = computed(
  () => userStore.nickName || userStore.name || "当前登录用户"
);
const formRef = ref();
const rules = {
  maintenancePerson: [{ required: true, message: "请选择保养人", trigger: "change" }],
  maintenanceLocation: [{ required: true, message: "请输入保养部位", trigger: "blur" }],
  maintenanceItems: [{ required: true, message: "请输入保养内容", trigger: "blur" }],
  maintenancePlanTime: [{ required: true, message: "请选择计划保养日期", trigger: "change" }],
};
const syncCreateUserFromLogin = () => {
  if (userStore.id != null && userStore.id !== "") {
@@ -130,9 +165,16 @@
const loading = ref(false);
const deviceOptions = ref([]);
const userList = ref([]);
const loadDeviceName = async () => {
  const { data } = await getDeviceLedger();
  deviceOptions.value = data;
};
const loadUserList = async () => {
  const res = await userListNoPageByTenantId();
  userList.value = res.data || [];
};
const { form, resetForm } = useFormData({
@@ -140,7 +182,9 @@
  deviceName: undefined,
  deviceModel: undefined,
  maintenanceLocation: undefined,
  maintenanceItems: undefined,
  maintenancePlanTime: undefined,
  maintenancePerson: undefined,
  createUser: undefined,
  status: 0,
});
@@ -155,6 +199,7 @@
const resetAttachmentState = () => {
  pendingTempFiles.value = [];
  planFileList.value = [];
  pendingDeleteFiles.value = [];
};
const normalizeFilePreviewUrl = (url = "") => {
@@ -178,6 +223,8 @@
    status: "success",
    uid: `saved-${item.id}`,
    fileId: item.id,
    // 标记为已保存的文件,不是新上传的
    isNew: false,
  }));
};
@@ -196,38 +243,33 @@
const handlePlanFileUpload = async (options) => {
  const { file, onSuccess, onError } = options;
  try {
    if (id.value) {
      const fd = new FormData();
      fd.append("file", file);
      fd.append("deviceMaintenanceId", String(id.value));
      const res = await uploadMaintenanceTaskFile(fd);
      if (res.code === 200) {
        await loadPlanFiles(id.value);
        onSuccess(res);
        ElMessage.success("附件上传成功");
      } else {
        onError(new Error(res.msg || "上传失败"));
      }
      return;
    }
    // 无论新增还是编辑,都先上传到临时目录
    const res = await uploadTempFile(file);
    if (res.code !== 200) {
      onError(new Error(res.msg || "上传失败"));
      return;
    }
    const data = res.data || {};
    const tempId = data.tempId;
    // 记录临时文件信息
    pendingTempFiles.value.push({
      tempId: data.tempId,
      tempId: tempId,
      name: data.originalName || file.name,
      fileId: id.value ? tempId : undefined,
    });
    onSuccess(res);
    planFileList.value.push({
      name: data.originalName || file.name,
      url: "",
      status: "success",
      uid: data.tempId,
      tempId: data.tempId,
      uid: tempId,
      tempId: tempId,
      // 标记为新上传的临时文件
      isNew: true,
    });
    ElMessage.success("附件上传成功");
  } catch (e) {
    onError(e);
    ElMessage.error("附件上传失败");
@@ -235,28 +277,29 @@
};
const handlePlanFileRemove = async (file) => {
  if (file.fileId) {
    try {
      await delMaintenanceTaskFile(file.fileId);
      await loadPlanFiles(id.value);
    } catch (e) {
      ElMessage.error("删除附件失败");
    }
  // 从显示列表中移除
  planFileList.value = planFileList.value.filter((f) => f.uid !== file.uid);
  const tempId = file.tempId || file.uid;
  if (file.isNew) {
    // 新上传的临时文件,直接从待上传列表移除
    pendingTempFiles.value = pendingTempFiles.value.filter((f) => f.tempId !== tempId);
    return;
  }
  const tempId = file.tempId || file.uid;
  pendingTempFiles.value = pendingTempFiles.value.filter((f) => f.tempId !== tempId);
  planFileList.value = planFileList.value.filter((f) => (f.tempId || f.uid) !== tempId);
  if (file.fileId) {
    pendingDeleteFiles.value.push({
      fileId: file.fileId,
      name: file.name,
    });
  }
};
const bindPendingFiles = async (planId) => {
  if (!pendingTempFiles.value.length) return;
  for (const item of pendingTempFiles.value) {
    await bindMaintenanceTaskFile({
      tempId: item.tempId,
      name: item.name,
      deviceMaintenanceId: planId,
    });
// 处理编辑模式下待删除的文件
const processPendingDeletes = async () => {
  if (!pendingDeleteFiles.value.length) return;
  for (const file of pendingDeleteFiles.value) {
    await delMaintenanceTaskFile(file.fileId);
  }
};
@@ -265,19 +308,53 @@
  form.deviceName = data.deviceName;
  form.deviceModel = data.deviceModel;
  form.maintenanceLocation = data.maintenanceLocation;
  form.maintenanceItems = data.maintenanceItems;
  form.status = data.status;
  syncCreateUserFromLogin();
  if (data.maintenancePersonId) {
    form.maintenancePerson = data.maintenancePersonId;
  } else if (data.maintenancePerson) {
    const matched = userList.value.find(
      (u) => u.nickName === data.maintenancePerson
    );
    if (matched) {
      form.maintenancePerson = matched.userId;
    }
  }
  form.maintenancePlanTime = dayjs(data.maintenancePlanTime).format(
    "YYYY-MM-DD HH:mm:ss"
  );
};
const buildSubmitPayload = () => {
  const payload = { ...form };
  const maintenancePersonUserId = form.maintenancePerson;
  if (maintenancePersonUserId) {
    const maintainer = userList.value.find(
      (u) => String(u.userId) === String(maintenancePersonUserId)
    );
    if (maintainer) {
      payload.maintenancePersonId = maintainer.userId;
      payload.maintenancePerson = maintainer.nickName;
    }
  }
  // 传递临时文件ID列表,由后端统一处理
  if (pendingTempFiles.value.length > 0) {
    payload.tempFileIds = pendingTempFiles.value.map((f) => f.tempId);
  }
  return payload;
};
onMounted(() => {
  loadDeviceName();
  loadUserList();
});
const openEdit = async (editId) => {
  resetAttachmentState();
  if (!userList.value.length) {
    await loadUserList();
  }
  const { data } = await getUpkeepById(editId);
  id.value = editId;
  visible.value = true;
@@ -288,22 +365,24 @@
const sendForm = async () => {
  syncCreateUserFromLogin();
  const valid = await formRef.value?.validate().catch(() => false);
  if (!valid) return;
  loading.value = true;
  try {
    const payload = buildSubmitPayload();
    if (id.value) {
      const { code } = await editUpkeep({ id: unref(id), ...form });
      // 编辑模式:先处理待删除的文件,再保存表单
      await processPendingDeletes();
      const { code } = await editUpkeep({ id: unref(id), ...payload });
      if (code == 200) {
        ElMessage.success("编辑计划成功");
        visible.value = false;
        emits("ok");
      }
    } else {
      const res = await addUpkeep(form);
      // 新增模式:tempFileIds 会随 payload 一起传到后端,由后端处理临时文件的关联
      const res = await addUpkeep(payload);
      if (res.code == 200) {
        const planId = res.data?.id;
        if (planId) {
          await bindPendingFiles(planId);
        }
        ElMessage.success("新增计划成功");
        visible.value = false;
        emits("ok");
@@ -331,6 +410,9 @@
  resetForm();
  resetAttachmentState();
  syncCreateUserFromLogin();
  if (userStore.id != null && userStore.id !== "") {
    form.maintenancePerson = userStore.id;
  }
  visible.value = true;
};
src/views/equipmentManagement/upkeep/Form/UpkeepDetailModal.vue
@@ -2,7 +2,7 @@
  <el-dialog
    v-model="visible"
    title="保养计划详情"
    width="820px"
    width="960px"
    destroy-on-close
    @closed="onClosed"
  >
@@ -11,9 +11,12 @@
        <el-descriptions :column="2" border size="small">
          <el-descriptions-item label="设备名称">{{ detail.deviceName || "—" }}</el-descriptions-item>
          <el-descriptions-item label="规格型号">{{ detail.deviceModel || "—" }}</el-descriptions-item>
          <el-descriptions-item label="保养项目" :span="2">
          <el-descriptions-item label="保养部位" :span="2">
            <div class="multiline">{{ detail.maintenanceLocation || "—" }}</div>
          </el-descriptions-item>
          <el-descriptions-item label="保养内容" :span="2">
            <div class="multiline">{{ detail.maintenanceItems || "—" }}</div>
          </el-descriptions-item>
          <el-descriptions-item label="保养人">{{ detail.maintenancePerson || "—" }}</el-descriptions-item>
          <el-descriptions-item label="计划保养日期">{{ fmtDate(detail.maintenancePlanTime) }}</el-descriptions-item>
          <el-descriptions-item label="录入人">{{ detail.createUserName || "—" }}</el-descriptions-item>
src/views/equipmentManagement/upkeep/Form/formDia.vue
@@ -75,6 +75,17 @@
                        />
                    </el-form-item>
                </el-col>
                <el-col :span="12">
                    <el-form-item label="任务状态">
                        <el-switch
                            v-model="form.isActive"
                            :active-value="1"
                            :inactive-value="0"
                            active-text="启用"
                            inactive-text="停用"
                        />
                    </el-form-item>
                </el-col>
            </el-row>
            <el-row>
                <el-col :span="12">
@@ -135,12 +146,24 @@
            </el-row>
            <el-row>
                <el-col :span="24">
                    <el-form-item label="保养项目" prop="maintenanceItems">
                    <el-form-item label="保养部位" prop="maintenanceLocation">
                        <el-input
                            v-model="form.maintenanceLocation"
                            type="textarea"
                            :rows="3"
                            placeholder="请输入保养部位"
                        />
                    </el-form-item>
                </el-col>
            </el-row>
            <el-row>
                <el-col :span="24">
                    <el-form-item label="保养内容" prop="maintenanceItems">
                        <el-input
                            v-model="form.maintenanceItems"
                            type="textarea"
                            :rows="3"
                            placeholder="请输入保养项目"
                            placeholder="请输入保养内容"
                        />
                    </el-form-item>
                </el-col>
@@ -178,6 +201,7 @@
        // 录入人、保养人:用户 id
        inspector: undefined,
        maintenancePerson: undefined,
        maintenanceLocation: '',
        maintenanceItems: '',
        remarks: '',
        frequencyType: '',
@@ -185,13 +209,15 @@
        week: '',
        time: '',
        deviceModel: undefined, // 规格型号
        registrationDate: ''
        registrationDate: '',
        isActive: 0, // 任务状态:0-停用,1-启用
    },
    rules: {
        taskId: [{ required: true, message: "请选择设备", trigger: "change" },],
        inspector: [{ required: true, message: "请选择录入人", trigger: "blur" },],
        maintenancePerson: [{ required: true, message: "请选择保养人", trigger: "change" }],
        maintenanceItems: [{ required: true, message: "请输入保养项目", trigger: "blur" }],
        maintenanceLocation: [{ required: true, message: "请输入保养部位", trigger: "blur" }],
        maintenanceItems: [{ required: true, message: "请输入保养内容", trigger: "blur" }],
        registrationDate: [{ required: true, message: "请选择登记时间", trigger: "change" }],
        frequencyDetail: [{
            validator: (rule, value, callback) => {
@@ -294,6 +320,7 @@
        taskName: undefined,
        inspector: undefined,
        maintenancePerson: undefined,
        maintenanceLocation: '',
        maintenanceItems: '',
        remarks: '',
        frequencyType: '',
@@ -301,7 +328,8 @@
        week: '',
        time: '',
        deviceModel: undefined,
        registrationDate: ''
        registrationDate: '',
        isActive: 0,
    }
}
@@ -335,10 +363,9 @@
                
                // 录入日期:直接使用表单里的 registrationDate 字段
                // 一些默认状态字段
                if (payload.status === undefined || payload.status === null || payload.status === '') {
                    payload.status = '0' // 默认状态,可按实际枚举调整
                if (payload.isActive === undefined || payload.isActive === null) {
                    payload.isActive = 0 // 默认停用
                }
                payload.active = true
                payload.deleted = 0
                
                if (operationType.value === 'edit') {
src/views/equipmentManagement/upkeep/index.vue
@@ -1,8 +1,8 @@
<template>
  <div class="app-container">
    <el-tabs v-model="activeTab" @tab-change="handleTabChange">
      <!-- 定时任务管理tab -->
      <el-tab-pane label="定时任务管理" name="scheduled">
      <!-- 保养任务管理tab -->
      <el-tab-pane label="保养任务管理" name="scheduled">
        <div class="search_form">
          <el-form :model="scheduledFilters" :inline="true">
            <el-form-item label="任务名称">
@@ -16,9 +16,9 @@
              />
            </el-form-item>
            <el-form-item label="任务状态">
              <el-select v-model="scheduledFilters.status" placeholder="请选择任务状态" clearable style="width: 200px">
                <el-option label="启用" value="1" />
                <el-option label="停用" value="0" />
              <el-select v-model="scheduledFilters.isActive" placeholder="请选择任务状态" clearable style="width: 200px">
                <el-option label="启用" :value="1" />
                <el-option label="停用" :value="0" />
              </el-select>
            </el-form-item>
            <el-form-item>
@@ -29,7 +29,7 @@
        </div>
        <div class="table_list">
          <div class="actions">
            <el-text class="mx-1" size="large">定时任务管理</el-text>
            <el-text class="mx-1" size="large">保养任务管理</el-text>
            <div>
              <el-button type="primary" icon="Plus" @click="addScheduledTask">
                新增任务
@@ -58,8 +58,8 @@
            @pagination="changeScheduledPage"
          >
            <template #statusRef="{ row }">
              <el-tag v-if="row.status === 1" type="success">启用</el-tag>
              <el-tag v-if="row.status === 0" type="danger">停用</el-tag>
              <el-tag v-if="row.isActive === 1" type="success">启用</el-tag>
              <el-tag v-if="row.isActive === 0" type="danger">停用</el-tag>
            </template>
            <template #operation="{ row }">
              <el-button
@@ -82,7 +82,7 @@
      </el-tab-pane>
      <!-- 任务记录tab(原设备保养页面) -->
      <el-tab-pane label="任务记录" name="record">
      <el-tab-pane label="保养任务记录" name="record">
        <div class="search_form">
          <el-form :model="filters" :inline="true">
            <el-form-item label="设备名称">
@@ -131,7 +131,7 @@
        </div>
        <div class="table_list">
          <div class="actions">
            <el-text class="mx-1" size="large">任务记录</el-text>
            <el-text class="mx-1" size="large">保养任务记录</el-text>
            <div>
              <el-button type="success" icon="Van" @click="addPlan">
                新增计划
@@ -312,10 +312,10 @@
})
const multipleList = ref([])
// 定时任务管理tab相关变量
// 保养任务管理tab相关变量
const scheduledFilters = reactive({
  taskName: '',
  status: '',
  isActive: '',
})
const scheduledDataList = ref([])
@@ -326,7 +326,7 @@
})
const scheduledMultipleList = ref([])
// 定时任务管理表格列配置
// 保养任务管理表格列配置
const scheduledColumns = ref([
    { prop: "taskName", label: "设备名称"},
    {
@@ -369,12 +369,26 @@
    { prop: "registrant", label: "登记人", minWidth: 100 },
    { prop: "maintenancePerson", label: "保养人", minWidth: 100 },
    {
        prop: "maintenanceLocation",
        label: "保养部位",
        minWidth: 150,
        showOverflowTooltip: true,
    },
    {
        prop: "maintenanceItems",
        label: "保养项目",
        label: "保养内容",
        minWidth: 180,
        showOverflowTooltip: true,
    },
    { prop: "registrationDate", label: "登记日期", minWidth: 100 },
    {
        label: "任务状态",
        prop: "isActive",
        minWidth: 100,
        dataType: "slot",
        slot: "statusRef",
        align: "center",
    },
    {
        fixed: "right",
        label: "操作",
@@ -398,9 +412,17 @@
        prop: "deviceModel",
    },
    {
        label: "保养项目",
        label: "保养部位",
        align: "center",
        prop: "maintenanceLocation",
        minWidth: 150,
        showOverflowTooltip: true,
    },
    {
        label: "保养内容",
        align: "center",
        prop: "maintenanceItems",
        minWidth: 150,
        showOverflowTooltip: true,
    },
    {
@@ -471,14 +493,14 @@
  }
}
// 定时任务管理相关方法
// 保养任务管理相关方法
const getScheduledTableData = async () => {
  try {
    const params = {
      current: scheduledPagination.currentPage,
      size: scheduledPagination.pageSize,
      taskName: scheduledFilters.taskName || undefined,
      status: scheduledFilters.status || undefined,
      isActive: scheduledFilters.isActive !== '' ? scheduledFilters.isActive : undefined,
    }
    const { code, data } = await deviceMaintenanceTaskList(params)
    if (code === 200) {
@@ -492,7 +514,7 @@
const resetScheduledFilters = () => {
  scheduledFilters.taskName = ''
  scheduledFilters.status = ''
  scheduledFilters.isActive = ''
  getScheduledTableData()
}