<template>
|
<FormDialog
|
v-model="visible"
|
:title="id ? '编辑设备保养计划' : '新增设备保养计划'"
|
width="680px"
|
@confirm="sendForm"
|
@cancel="handleCancel"
|
@close="handleClose"
|
>
|
<el-form ref="formRef" :model="form" :rules="rules" label-width="100px">
|
<el-form-item label="设备名称">
|
<el-select
|
v-model="form.deviceLedgerId"
|
@change="setDeviceModel"
|
placeholder="请选择设备"
|
filterable
|
default-first-option
|
:reserve-keyword="false"
|
>
|
<el-option
|
v-for="(item, index) in deviceOptions"
|
:key="index"
|
:label="item.deviceName"
|
:value="item.id"
|
></el-option>
|
</el-select>
|
</el-form-item>
|
<el-form-item label="规格型号">
|
<el-input
|
v-model="form.deviceModel"
|
placeholder="请输入规格型号"
|
disabled
|
/>
|
</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="保修状态">
|
<el-select v-model="form.status">
|
<el-option label="待保修" :value="0"></el-option>
|
<el-option label="完结" :value="1"></el-option>
|
<el-option label="失败" :value="2"></el-option>
|
</el-select>
|
</el-form-item>
|
<el-form-item label="计划保养日期">
|
<el-date-picker
|
style="width: 100%"
|
v-model="form.maintenancePlanTime"
|
format="YYYY-MM-DD"
|
value-format="YYYY-MM-DD HH:mm:ss"
|
type="date"
|
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>
|
</template>
|
|
<script setup>
|
import FormDialog from "@/components/Dialog/FormDialog.vue";
|
import {
|
addUpkeep,
|
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 { 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";
|
|
defineOptions({
|
name: "设备保养新增计划",
|
});
|
|
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" }],
|
};
|
|
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,
|
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);
|
if (option) {
|
form.deviceModel = option.deviceModel;
|
}
|
};
|
|
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.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;
|
}
|
}
|
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;
|
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 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;
|
}
|
};
|
|
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;
|
};
|
|
defineExpose({
|
openModal,
|
openEdit,
|
});
|
</script>
|
|
<style lang="scss" scoped>
|
.upload-tip {
|
display: block;
|
font-size: 12px;
|
color: #999;
|
margin-top: 8px;
|
line-height: 1.4;
|
}
|
</style>
|