From 790aada08682e9fe23aa4f51716cc50915f27552 Mon Sep 17 00:00:00 2001
From: yyb <995253665@qq.com>
Date: 星期一, 18 五月 2026 17:40:05 +0800
Subject: [PATCH] 计划保养日期必填

---
 src/views/equipmentManagement/upkeep/Form/PlanModal.vue |  313 +++++++++++++++++++++++++++++++++++++++++++++------
 1 files changed, 274 insertions(+), 39 deletions(-)

diff --git a/src/views/equipmentManagement/upkeep/Form/PlanModal.vue b/src/views/equipmentManagement/upkeep/Form/PlanModal.vue
index bb686dc..ae32aef 100644
--- a/src/views/equipmentManagement/upkeep/Form/PlanModal.vue
+++ b/src/views/equipmentManagement/upkeep/Form/PlanModal.vue
@@ -2,12 +2,12 @@
   <FormDialog
     v-model="visible"
     :title="id ? '缂栬緫璁惧淇濆吇璁″垝' : '鏂板璁惧淇濆吇璁″垝'"
-    width="500px"
+    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,28 +32,45 @@
           disabled
         />
       </el-form-item>
-      <el-form-item label="淇濆吇椤圭洰">
+      <el-form-item label="褰曞叆浜�">
         <el-input
-          v-model="form.maintenanceLocation"
-          placeholder="璇疯緭鍏ヤ繚鍏婚」鐩�"
+          :model-value="registrantDisplayName"
+          disabled
+          placeholder="褰撳墠鐧诲綍鐢ㄦ埛"
         />
       </el-form-item>
-      <el-form-item label="褰曞叆浜�">
+      <el-form-item label="淇濆吇浜�" prop="maintenancePerson">
         <el-select
-          v-model="form.createUser"
-          placeholder="璇烽�夋嫨"
+          v-model="form.maintenancePerson"
           filterable
           default-first-option
           :reserve-keyword="false"
-          clearable
+          placeholder="璇烽�夋嫨淇濆吇浜�"
+          style="width: 100%"
         >
           <el-option
             v-for="item in userList"
-            :key="item.userId"
+            :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="淇濅慨鐘舵��">
         <el-select v-model="form.status">
@@ -62,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"
@@ -72,6 +89,18 @@
           placeholder="璇烽�夋嫨璁″垝淇濆吇鏃ユ湡鏃ユ湡"
           clearable
         />
+      </el-form-item>
+      <el-form-item label="闄勪欢">
+        <el-upload
+          :http-request="handlePlanFileUpload"
+          :file-list="planFileList"
+          :on-remove="handlePlanFileRemove"
+          multiple
+          list-type="picture-card"
+        >
+          <el-icon><Plus /></el-icon>
+        </el-upload>
+        <span v-if="!id" class="upload-tip">鍙厛閫夋嫨闄勪欢锛屼繚瀛樿鍒掑悗鑷姩鍏宠仈鍒版湰璁″垝</span>
       </el-form-item>
     </el-form>
   </FormDialog>
@@ -84,12 +113,21 @@
   editUpkeep,
   getUpkeepById,
 } 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 { onMounted } from "vue";
+import { userListNoPageByTenantId } from "@/api/system/user.js";
+import { computed, nextTick, onMounted, ref, unref } from "vue";
 import dayjs from "dayjs";
-import { userListNoPage } from "@/api/system/user.js";
+import useUserStore from "@/store/modules/user.js";
+import request from "@/utils/request";
 
 defineOptions({
   name: "璁惧淇濆吇鏂板璁″垝",
@@ -97,75 +135,256 @@
 
 const emits = defineEmits(["ok"]);
 
+const userStore = useUserStore();
+const javaApi = import.meta.env.VITE_APP_BASE_API;
+
+const pendingTempFiles = ref([]);
+const planFileList = 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 !== "") {
+    form.createUser = userStore.id;
+  }
+};
+
 const id = ref();
 const visible = ref(false);
 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({
-  deviceLedgerId: undefined, // 璁惧Id
-  deviceName: undefined, // 璁惧鍚嶇О
-  deviceModel: undefined, // 瑙勬牸鍨嬪彿
-  maintenanceLocation: undefined, // 淇濆吇椤圭洰
-  maintenancePlanTime: undefined, // 璁″垝淇濆吇鏃ユ湡
-  createUser: undefined, // 褰曞叆浜�
-  status: 0, //淇濅慨鐘舵��
+  deviceLedgerId: undefined,
+  deviceName: undefined,
+  deviceModel: undefined,
+  maintenanceLocation: undefined,
+  maintenanceItems: undefined,
+  maintenancePlanTime: undefined,
+  maintenancePerson: undefined,
+  createUser: undefined,
+  status: 0,
 });
 
 const setDeviceModel = (deviceId) => {
   const option = deviceOptions.value.find((item) => item.id === deviceId);
-  form.deviceModel = option.deviceModel;
+  if (option) {
+    form.deviceModel = option.deviceModel;
+  }
 };
 
-/**
- * @desc 璁剧疆琛ㄥ崟鍐呭
- * @param data 璁惧淇℃伅
- */
+const resetAttachmentState = () => {
+  pendingTempFiles.value = [];
+  planFileList.value = [];
+};
+
+const normalizeFilePreviewUrl = (url = "") => {
+  if (!url) return "";
+  if (url.startsWith("http")) return url;
+  if (url.startsWith("/profile")) return javaApi + url;
+  return url;
+};
+
+const loadPlanFiles = async (planId) => {
+  if (!planId) return;
+  const res = await listMaintenanceTaskFiles({
+    current: 1,
+    size: 100,
+    deviceMaintenanceId: planId,
+  });
+  const records = res?.data?.records || [];
+  planFileList.value = records.map((item) => ({
+    name: item.name,
+    url: normalizeFilePreviewUrl(item.url),
+    status: "success",
+    uid: `saved-${item.id}`,
+    fileId: item.id,
+  }));
+};
+
+const uploadTempFile = (file) => {
+  const fd = new FormData();
+  fd.append("file", file);
+  fd.append("type", "16");
+  return request({
+    url: "/file/upload",
+    method: "post",
+    data: fd,
+    headers: { "Content-Type": "multipart/form-data" },
+  });
+};
+
+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 || {};
+    pendingTempFiles.value.push({
+      tempId: data.tempId,
+      name: data.originalName || file.name,
+    });
+    onSuccess(res);
+    planFileList.value.push({
+      name: data.originalName || file.name,
+      url: "",
+      status: "success",
+      uid: data.tempId,
+      tempId: data.tempId,
+    });
+  } catch (e) {
+    onError(e);
+    ElMessage.error("闄勪欢涓婁紶澶辫触");
+  }
+};
+
+const handlePlanFileRemove = async (file) => {
+  if (file.fileId) {
+    try {
+      await delMaintenanceTaskFile(file.fileId);
+      await loadPlanFiles(id.value);
+    } catch (e) {
+      ElMessage.error("鍒犻櫎闄勪欢澶辫触");
+    }
+    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);
+};
+
+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 setForm = (data) => {
   form.deviceLedgerId = data.deviceLedgerId;
   form.deviceName = data.deviceName;
   form.deviceModel = data.deviceModel;
   form.maintenanceLocation = data.maintenanceLocation;
-  form.createUser = Number(data.createUser);
+  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 userList = ref([]);
+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;
+    }
+  }
+  return payload;
+};
 
 onMounted(() => {
   loadDeviceName();
-  userListNoPage().then((res) => {
-    userList.value = res.data;
-  });
+  loadUserList();
 });
 
 const openEdit = async (editId) => {
+  resetAttachmentState();
+  if (!userList.value.length) {
+    await loadUserList();
+  }
   const { data } = await getUpkeepById(editId);
   id.value = editId;
   visible.value = true;
   await nextTick();
   setForm(data);
+  await loadPlanFiles(editId);
 };
 
 const sendForm = async () => {
+  syncCreateUserFromLogin();
+  const valid = await formRef.value?.validate().catch(() => false);
+  if (!valid) return;
   loading.value = true;
   try {
-    const { code } = id.value
-      ? await editUpkeep({ id: unref(id), ...form })
-      : await addUpkeep(form);
-    if (code == 200) {
-      ElMessage.success(`${id.value ? "缂栬緫" : "鏂板"}璁″垝鎴愬姛`);
-      visible.value = false;
-      emits("ok");
+    const payload = buildSubmitPayload();
+    if (id.value) {
+      const { code } = await editUpkeep({ id: unref(id), ...payload });
+      if (code == 200) {
+        ElMessage.success("缂栬緫璁″垝鎴愬姛");
+        visible.value = false;
+        emits("ok");
+      }
+    } else {
+      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");
+      }
     }
   } finally {
     loading.value = false;
@@ -174,16 +393,24 @@
 
 const handleCancel = () => {
   resetForm();
+  resetAttachmentState();
   visible.value = false;
 };
 
 const handleClose = () => {
   resetForm();
+  resetAttachmentState();
   visible.value = false;
 };
 
 const openModal = () => {
   id.value = undefined;
+  resetForm();
+  resetAttachmentState();
+  syncCreateUserFromLogin();
+  if (userStore.id != null && userStore.id !== "") {
+    form.maintenancePerson = userStore.id;
+  }
   visible.value = true;
 };
 
@@ -193,4 +420,12 @@
 });
 </script>
 
-<style lang="scss" scoped></style>
+<style lang="scss" scoped>
+.upload-tip {
+  display: block;
+  font-size: 12px;
+  color: #999;
+  margin-top: 8px;
+  line-height: 1.4;
+}
+</style>

--
Gitblit v1.9.3