| | |
| | | }); |
| | | } |
| | | |
| | | export function bindMaintenanceTaskFile(data) { |
| | | return addMaintenanceTaskFile(data); |
| | | } |
| | | |
| | | // ä¸ä¼ ä¿å
»è®¡åéä»¶ |
| | | export function uploadMaintenanceTaskFile(formData) { |
| | | return request({ |
| | | url: "/maintenanceTaskFile/upload", |
| | | method: "post", |
| | | data: formData, |
| | | headers: { "Content-Type": "multipart/form-data" }, |
| | | }); |
| | | } |
| | | |
| | | // å é¤ä¿å
»ä»»å¡éä»¶ |
| | | export function delMaintenanceTaskFile(id) { |
| | | return request({ |
| | |
| | | class="upload-demo" |
| | | :action="uploadAction" |
| | | :headers="uploadHeaders" |
| | | :data="uploadData" |
| | | :show-file-list="false" |
| | | :on-success="handleDefaultUploadSuccess" |
| | | :on-error="handleDefaultUploadError"> |
| | |
| | | type: String, |
| | | default: `${import.meta.env.VITE_APP_BASE_API}/file/upload`, |
| | | }, |
| | | uploadData: { |
| | | type: Object, |
| | | default: () => ({}), |
| | | }, |
| | | uploadDirectSave: { |
| | | type: Boolean, |
| | | default: false, |
| | | }, |
| | | isShowPagination: { |
| | | type: Boolean, |
| | | default: false, |
| | |
| | | ElMessage.error(res?.msg || "æä»¶ä¸ä¼ 失败"); |
| | | return; |
| | | } |
| | | if (props.uploadDirectSave) { |
| | | ElMessage.success("ä¸ä¼ æå"); |
| | | emit("upload", res?.data || {}); |
| | | return; |
| | | } |
| | | if (!props.rulesRegulationsManagementId) { |
| | | ElMessage.error("缺å°è§ç« å¶åº¦IDï¼æ æ³ä¿åéä»¶"); |
| | | ElMessage.error("缺å°ä¸å¡IDï¼æ æ³ä¿åéä»¶"); |
| | | return; |
| | | } |
| | | const fileName = res?.data?.originalName || file?.name; |
| | |
| | | <FormDialog |
| | | v-model="visible" |
| | | :title="'设å¤ä¿å
»'" |
| | | width="500px" |
| | | width="640px" |
| | | @confirm="sendForm" |
| | | @cancel="handleCancel" |
| | | @close="handleClose" |
| | |
| | | <el-form-item label="ä¿å
ȍȾ"> |
| | | <el-input |
| | | v-model="form.maintenanceResult" |
| | | type="textarea" |
| | | :rows="6" |
| | | placeholder="请è¾å
¥ä¿å
ȍȾ" |
| | | type="text" /> |
| | | maxlength="2000" |
| | | show-word-limit |
| | | resize="vertical" |
| | | /> |
| | | </el-form-item> |
| | | </el-form> |
| | | </FormDialog> |
| | |
| | | <FormDialog |
| | | v-model="visible" |
| | | :title="id ? 'ç¼è¾è®¾å¤ä¿å
»è®¡å' : 'æ°å¢è®¾å¤ä¿å
»è®¡å'" |
| | | width="500px" |
| | | width="640px" |
| | | @confirm="sendForm" |
| | | @cancel="handleCancel" |
| | | @close="handleClose" |
| | |
| | | <el-form-item label="ä¿å
»é¡¹ç®"> |
| | | <el-input |
| | | v-model="form.maintenanceLocation" |
| | | type="textarea" |
| | | :rows="3" |
| | | placeholder="请è¾å
¥ä¿å
»é¡¹ç®" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="å½å
¥äºº"> |
| | | <el-select |
| | | v-model="form.createUser" |
| | | placeholder="è¯·éæ©" |
| | | filterable |
| | | default-first-option |
| | | :reserve-keyword="false" |
| | | clearable |
| | | > |
| | | <el-option |
| | | v-for="item in userList" |
| | | :key="item.userId" |
| | | :label="item.nickName" |
| | | :value="item.userId" |
| | | /> |
| | | </el-select> |
| | | <el-input |
| | | :model-value="registrantDisplayName" |
| | | disabled |
| | | placeholder="å½åç»å½ç¨æ·" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item v-if="id" label="ä¿ä¿®ç¶æ"> |
| | | <el-select v-model="form.status"> |
| | |
| | | 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> |
| | |
| | | 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 { computed, onMounted, ref } 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: "设å¤ä¿å
»æ°å¢è®¡å", |
| | | }); |
| | | |
| | | 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 syncCreateUserFromLogin = () => { |
| | | if (userStore.id != null && userStore.id !== "") { |
| | | form.createUser = userStore.id; |
| | | } |
| | | }; |
| | | |
| | | const id = ref(); |
| | | const visible = ref(false); |
| | |
| | | }; |
| | | |
| | | 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, |
| | | maintenancePlanTime: 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.status = data.status; |
| | | syncCreateUserFromLogin(); |
| | | form.maintenancePlanTime = dayjs(data.maintenancePlanTime).format( |
| | | "YYYY-MM-DD HH:mm:ss" |
| | | ); |
| | | }; |
| | | |
| | | // ç¨æ·å表 |
| | | const userList = ref([]); |
| | | |
| | | onMounted(() => { |
| | | loadDeviceName(); |
| | | userListNoPage().then((res) => { |
| | | userList.value = res.data; |
| | | }); |
| | | }); |
| | | |
| | | const openEdit = async (editId) => { |
| | | resetAttachmentState(); |
| | | const { data } = await getUpkeepById(editId); |
| | | id.value = editId; |
| | | visible.value = true; |
| | | await nextTick(); |
| | | setForm(data); |
| | | await loadPlanFiles(editId); |
| | | }; |
| | | |
| | | const sendForm = async () => { |
| | | syncCreateUserFromLogin(); |
| | | 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"); |
| | | if (id.value) { |
| | | const { code } = await editUpkeep({ id: unref(id), ...form }); |
| | | if (code == 200) { |
| | | ElMessage.success("ç¼è¾è®¡åæå"); |
| | | visible.value = false; |
| | | emits("ok"); |
| | | } |
| | | } else { |
| | | const res = await addUpkeep(form); |
| | | 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(); |
| | | visible.value = true; |
| | | }; |
| | | |
| | |
| | | }); |
| | | </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> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <el-dialog |
| | | v-model="visible" |
| | | title="ä¿å
»è®¡å详æ
" |
| | | width="820px" |
| | | destroy-on-close |
| | | @closed="onClosed" |
| | | > |
| | | <div v-loading="loading" class="upkeep-detail"> |
| | | <template v-if="detail"> |
| | | <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"> |
| | | <div class="multiline">{{ detail.maintenanceLocation || "â" }}</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> |
| | | <el-descriptions-item label="å®é
ä¿å
»äºº">{{ detail.maintenanceActuallyName || "â" }}</el-descriptions-item> |
| | | <el-descriptions-item label="å®é
ä¿å
»æ¥æ">{{ fmtDateTime(detail.maintenanceActuallyTime) }}</el-descriptions-item> |
| | | <el-descriptions-item label="ç¶æ"> |
| | | <el-tag v-if="detail.status === 2" type="danger" size="small">失败</el-tag> |
| | | <el-tag v-else-if="detail.status === 1" type="success" size="small">å®ç»</el-tag> |
| | | <el-tag v-else-if="detail.status === 0" type="warning" size="small">å¾
ä¿å
»</el-tag> |
| | | <span v-else>â</span> |
| | | </el-descriptions-item> |
| | | <el-descriptions-item label="ä¿å
ȍȾ" :span="2"> |
| | | <div class="multiline">{{ detail.maintenanceResult || "â" }}</div> |
| | | </el-descriptions-item> |
| | | <el-descriptions-item label="å½å
¥æ¶é´">{{ fmtDateTime(detail.createTime) }}</el-descriptions-item> |
| | | <el-descriptions-item label="æ´æ°æ¶é´">{{ fmtDateTime(detail.updateTime) }}</el-descriptions-item> |
| | | </el-descriptions> |
| | | |
| | | <div class="attach-block"> |
| | | <div class="attach-title">éä»¶ï¼{{ fileList.length }}ï¼</div> |
| | | <div v-if="fileList.length" class="img-grid"> |
| | | <div v-for="file in fileList" :key="file.id" class="attach-item"> |
| | | <el-image |
| | | v-if="isImageFile(file.name)" |
| | | :src="file.url" |
| | | fit="cover" |
| | | class="thumb" |
| | | :preview-src-list="imagePreviewList" |
| | | preview-teleported |
| | | /> |
| | | <div v-else class="file-chip"> |
| | | <el-link type="primary" :href="file.url" target="_blank">{{ file.name }}</el-link> |
| | | </div> |
| | | <div class="file-name" :title="file.name">{{ file.name }}</div> |
| | | </div> |
| | | </div> |
| | | <el-empty v-else description="ææ éä»¶" :image-size="56" /> |
| | | </div> |
| | | </template> |
| | | </div> |
| | | <template #footer> |
| | | <el-button type="primary" @click="visible = false">å
³é</el-button> |
| | | </template> |
| | | </el-dialog> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { computed, ref } from "vue"; |
| | | import dayjs from "dayjs"; |
| | | import { getUpkeepById } from "@/api/equipmentManagement/upkeep"; |
| | | import { listMaintenanceTaskFiles } from "@/api/equipmentManagement/maintenanceTaskFile"; |
| | | |
| | | defineOptions({ name: "UpkeepDetailModal" }); |
| | | |
| | | const props = defineProps({ |
| | | javaApi: { |
| | | type: String, |
| | | default: "", |
| | | }, |
| | | }); |
| | | |
| | | const visible = ref(false); |
| | | const loading = ref(false); |
| | | const detail = ref(null); |
| | | const fileList = ref([]); |
| | | |
| | | const apiBase = computed(() => props.javaApi || import.meta.env.VITE_APP_BASE_API || ""); |
| | | |
| | | const imagePreviewList = computed(() => |
| | | fileList.value.filter((f) => isImageFile(f.name)).map((f) => f.url) |
| | | ); |
| | | |
| | | const fmtDate = (v) => (v ? dayjs(v).format("YYYY-MM-DD") : "â"); |
| | | const fmtDateTime = (v) => (v ? dayjs(v).format("YYYY-MM-DD HH:mm:ss") : "â"); |
| | | |
| | | const isImageFile = (name = "") => /\.(jpg|jpeg|png|gif|webp|bmp)$/i.test(name); |
| | | |
| | | const normalizeFileUrl = (rawUrl = "") => { |
| | | let fileUrl = rawUrl || ""; |
| | | if (!fileUrl) return ""; |
| | | if (fileUrl.startsWith("http://") || fileUrl.startsWith("https://")) return fileUrl; |
| | | if (fileUrl.indexOf("\\") > -1) { |
| | | const lowerPath = fileUrl.toLowerCase(); |
| | | const uploadPathIndex = lowerPath.indexOf("uploadpath"); |
| | | if (uploadPathIndex > -1) { |
| | | fileUrl = fileUrl.substring(uploadPathIndex).replace(/\\/g, "/"); |
| | | } else { |
| | | fileUrl = fileUrl.replace(/\\/g, "/"); |
| | | } |
| | | } |
| | | fileUrl = fileUrl.replace(/^\/?uploadPath/i, "/profile"); |
| | | if (!fileUrl.startsWith("/")) fileUrl = "/" + fileUrl; |
| | | if (!fileUrl.startsWith(apiBase.value)) fileUrl = apiBase.value + fileUrl; |
| | | return fileUrl; |
| | | }; |
| | | |
| | | const loadFiles = async (id) => { |
| | | const res = await listMaintenanceTaskFiles({ |
| | | current: 1, |
| | | size: 100, |
| | | deviceMaintenanceId: id, |
| | | }); |
| | | const records = res?.data?.records || []; |
| | | fileList.value = records.map((item) => ({ |
| | | id: item.id, |
| | | name: item.name, |
| | | url: normalizeFileUrl(item.url), |
| | | })); |
| | | }; |
| | | |
| | | const open = async (row) => { |
| | | if (!row?.id) return; |
| | | visible.value = true; |
| | | loading.value = true; |
| | | detail.value = null; |
| | | fileList.value = []; |
| | | try { |
| | | const { data } = await getUpkeepById(row.id); |
| | | detail.value = { ...row, ...data }; |
| | | await loadFiles(row.id); |
| | | } finally { |
| | | loading.value = false; |
| | | } |
| | | }; |
| | | |
| | | const onClosed = () => { |
| | | detail.value = null; |
| | | fileList.value = []; |
| | | }; |
| | | |
| | | defineExpose({ open }); |
| | | </script> |
| | | |
| | | <style lang="scss" scoped> |
| | | .upkeep-detail { |
| | | min-height: 120px; |
| | | } |
| | | .multiline { |
| | | white-space: pre-wrap; |
| | | word-break: break-word; |
| | | line-height: 1.6; |
| | | } |
| | | .attach-block { |
| | | margin-top: 20px; |
| | | } |
| | | .attach-title { |
| | | font-size: 14px; |
| | | font-weight: 600; |
| | | margin-bottom: 12px; |
| | | color: #303133; |
| | | } |
| | | .img-grid { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | gap: 12px; |
| | | } |
| | | .attach-item { |
| | | width: 100px; |
| | | } |
| | | .thumb { |
| | | width: 100px; |
| | | height: 100px; |
| | | border-radius: 4px; |
| | | border: 1px solid #ebeef5; |
| | | } |
| | | .file-chip { |
| | | width: 100px; |
| | | height: 100px; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | padding: 8px; |
| | | border: 1px dashed #dcdfe6; |
| | | border-radius: 4px; |
| | | box-sizing: border-box; |
| | | } |
| | | .file-name { |
| | | display: block; |
| | | margin-top: 6px; |
| | | font-size: 12px; |
| | | color: #606266; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | white-space: nowrap; |
| | | } |
| | | </style> |
| | |
| | | <el-row> |
| | | <el-col :span="12"> |
| | | <el-form-item label="å½å
¥äºº" prop="inspector"> |
| | | <el-input |
| | | :model-value="registrantDisplayName" |
| | | disabled |
| | | placeholder="å½åç»å½ç¨æ·" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="ä¿å
»äºº" prop="maintenancePerson"> |
| | | <el-select |
| | | v-model="form.inspector" |
| | | v-model="form.maintenancePerson" |
| | | filterable |
| | | default-first-option |
| | | :reserve-keyword="false" |
| | |
| | | v-for="item in userList" |
| | | :label="item.nickName" |
| | | :value="item.userId" |
| | | :key="item.userId" |
| | | :key="'mp-' + item.userId" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row> |
| | | <el-col :span="12"> |
| | | <el-form-item label="ç»è®°æ¶é´" prop="registrationDate"> |
| | | <el-date-picker |
| | |
| | | </el-col> |
| | | </el-row> |
| | | <el-row> |
| | | <el-col :span="12"> |
| | | <el-col :span="24"> |
| | | <el-form-item label="ä¿å
»é¡¹ç®" prop="maintenanceItems"> |
| | | <el-input |
| | | v-model="form.maintenanceItems" |
| | | type="textarea" |
| | | :rows="3" |
| | | placeholder="请è¾å
¥ä¿å
»é¡¹ç®" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row> |
| | | <el-col :span="24"> |
| | | <el-form-item label="夿³¨" prop="remarks"> |
| | | <el-input v-model="form.remarks" placeholder="请è¾å
¥å¤æ³¨" type="textarea" /> |
| | | </el-form-item> |
| | |
| | | |
| | | <script setup> |
| | | import FormDialog from "@/components/Dialog/FormDialog.vue"; |
| | | import { reactive, ref, getCurrentInstance, toRefs } from "vue"; |
| | | import { reactive, ref, computed, getCurrentInstance, toRefs } from "vue"; |
| | | import {userListNoPageByTenantId} from "@/api/system/user.js"; |
| | | import { getDeviceLedger } from "@/api/equipmentManagement/ledger"; |
| | | import { deviceMaintenanceTaskAdd, deviceMaintenanceTaskEdit } from "@/api/equipmentManagement/upkeep"; |
| | |
| | | form: { |
| | | taskId: undefined, |
| | | taskName: undefined, |
| | | // å½å
¥äººï¼åéä¸ä¸ªç¨æ· id |
| | | // å½å
¥äººãä¿å
»äººï¼ç¨æ· id |
| | | inspector: undefined, |
| | | maintenancePerson: undefined, |
| | | maintenanceItems: '', |
| | | remarks: '', |
| | | frequencyType: '', |
| | | frequencyDetail: '', |
| | |
| | | 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" }], |
| | | registrationDate: [{ required: true, message: "è¯·éæ©ç»è®°æ¶é´", trigger: "change" }], |
| | | frequencyDetail: [{ |
| | | validator: (rule, value, callback) => { |
| | |
| | | }) |
| | | const { form, rules } = toRefs(data) |
| | | const userList = ref([]) |
| | | |
| | | const registrantDisplayName = computed( |
| | | () => userStore.nickName || userStore.name || "å½åç»å½ç¨æ·" |
| | | ) |
| | | |
| | | const syncRegistrantFromLogin = () => { |
| | | if (userStore.id != null && userStore.id !== "") { |
| | | form.value.inspector = userStore.id |
| | | } |
| | | } |
| | | |
| | | const loadDeviceName = async () => { |
| | | const { data } = await getDeviceLedger(); |
| | |
| | | |
| | | if (type === 'edit' && row) { |
| | | form.value = { ...row } |
| | | // ç¼è¾æ¶ç¨æ¥å£è¿åç registrantId åæ¾å½å
¥äºº |
| | | if (row.registrantId) { |
| | | form.value.inspector = row.registrantId |
| | | if (row.maintenancePersonId) { |
| | | form.value.maintenancePerson = row.maintenancePersonId |
| | | } |
| | | |
| | | // 妿æè®¾å¤IDï¼èªå¨è®¾ç½®è®¾å¤ä¿¡æ¯ |
| | | if (form.value.taskId) { |
| | | setDeviceModel(form.value.taskId); |
| | | } |
| | | } else if (type === 'add') { |
| | | // æ°å¢æ¶è®¾ç½®ç»è®°æ¥æä¸ºå½å¤© |
| | | form.value.registrationDate = getCurrentDate(); |
| | | // æ°å¢æ¶è®¾ç½®å½å
¥äººä¸ºå½åç»å½è´¦æ· |
| | | form.value.inspector = userStore.id; |
| | | form.value.maintenancePerson = userStore.id; |
| | | } |
| | | syncRegistrantFromLogin() |
| | | } |
| | | |
| | | // å
³éå¯¹è¯æ¡ |
| | |
| | | taskId: undefined, |
| | | taskName: undefined, |
| | | inspector: undefined, |
| | | inspector: undefined, |
| | | maintenancePerson: undefined, |
| | | maintenanceItems: '', |
| | | remarks: '', |
| | | frequencyType: '', |
| | | frequencyDetail: '', |
| | |
| | | |
| | | // æäº¤è¡¨å |
| | | const submitForm = () => { |
| | | syncRegistrantFromLogin() |
| | | proxy.$refs["formRef"].validate(async valid => { |
| | | if (valid) { |
| | | try { |
| | | const payload = { ...form.value } |
| | | // ä¸åååç«¯ä¼ ä¿å
»äººå段ï¼ä»
ä½¿ç¨æ¥å£è¦æ±ç registrant / registrantId |
| | | // æ ¹æ®éæ©ç"å½å
¥äºº"设置 registrant / registrantId |
| | | if (payload.inspector) { |
| | | const selectedUser = userList.value.find( |
| | | (u) => String(u.userId) === String(payload.inspector) |
| | | payload.registrantId = userStore.id |
| | | payload.registrant = userStore.nickName || userStore.name |
| | | const maintenancePersonUserId = form.value.maintenancePerson |
| | | if (maintenancePersonUserId) { |
| | | const maintainer = userList.value.find( |
| | | (u) => String(u.userId) === String(maintenancePersonUserId) |
| | | ) |
| | | if (selectedUser) { |
| | | payload.registrantId = selectedUser.userId |
| | | payload.registrant = selectedUser.nickName |
| | | if (maintainer) { |
| | | payload.maintenancePersonId = maintainer.userId |
| | | payload.maintenancePerson = maintainer.nickName |
| | | } |
| | | } |
| | | delete payload.inspector |
| | |
| | | @selection-change="handleSelectionChange" |
| | | @pagination="changePage" |
| | | > |
| | | <template #maintenanceResultRef="{ row }"> |
| | | <div>{{ row.maintenanceResult || '-' }}</div> |
| | | </template> |
| | | <template #statusRef="{ row }"> |
| | | <el-tag v-if="row.status === 2" type="danger">失败</el-tag> |
| | | <el-tag v-if="row.status === 1" type="success">å®ç»</el-tag> |
| | | <el-tag v-if="row.status === 0" type="warning">å¾
ä¿å
»</el-tag> |
| | | </template> |
| | | <template #operation="{ row }"> |
| | | <!-- è¿ä¸ªåè½è·æ°å¢ä¿å
»åè½ä¸æ¨¡ä¸æ ·ï¼æå¥æä¹ï¼ --> |
| | | <!-- <el-button |
| | | type="primary" |
| | | text |
| | | @click="addMaintain(row)" |
| | | <el-button |
| | | type="primary" |
| | | link |
| | | @click="openDetail(row)" |
| | | > |
| | | æ°å¢ä¿å
» |
| | | </el-button> --> |
| | | 详æ
|
| | | </el-button> |
| | | <el-button |
| | | type="primary" |
| | | link |
| | |
| | | <PlanModal ref="planModalRef" @ok="getTableData" /> |
| | | <MaintenanceModal ref="maintainModalRef" @ok="getTableData" /> |
| | | <FormDia ref="formDiaRef" @closeDia="getScheduledTableData" /> |
| | | <FileListDialog |
| | | <UpkeepDetailModal ref="upkeepDetailModalRef" :java-api="javaApi" /> |
| | | <FileListDialog |
| | | ref="fileListDialogRef" |
| | | v-model="fileDialogVisible" |
| | | :show-upload-button="true" |
| | | :show-delete-button="true" |
| | | :title="currentRecordFinished ? 'éä»¶ï¼å·²å®ç»ï¼ä»
坿¥çï¼' : 'éä»¶'" |
| | | :show-upload-button="!currentRecordFinished" |
| | | :show-delete-button="!currentRecordFinished" |
| | | :delete-method="handleAttachmentDelete" |
| | | :name-column-label="'éä»¶åç§°'" |
| | | :rulesRegulationsManagementId="currentMaintenanceTaskId" |
| | | @upload="handleAttachmentUpload" /> |
| | | :upload-url="maintenanceFileUploadUrl" |
| | | :upload-data="maintenanceFileUploadData" |
| | | :upload-direct-save="true" |
| | | @upload="refreshFileList" |
| | | /> |
| | | </div> |
| | | </template> |
| | | |
| | |
| | | import { ElMessage, ElMessageBox } from 'element-plus' |
| | | import PlanModal from './Form/PlanModal.vue' |
| | | import MaintenanceModal from './Form/MaintenanceModal.vue' |
| | | import UpkeepDetailModal from './Form/UpkeepDetailModal.vue' |
| | | import FormDia from './Form/formDia.vue' |
| | | import FileListDialog from '@/components/Dialog/FileListDialog.vue' |
| | | import { |
| | |
| | | } from '@/api/equipmentManagement/upkeep' |
| | | import { |
| | | listMaintenanceTaskFiles, |
| | | addMaintenanceTaskFile, |
| | | delMaintenanceTaskFile, |
| | | } from '@/api/equipmentManagement/maintenanceTaskFile' |
| | | import dayjs from 'dayjs' |
| | |
| | | const planModalRef = ref() |
| | | // ä¿å
»å¼¹çªæ§å¶å¨ |
| | | const maintainModalRef = ref() |
| | | const upkeepDetailModalRef = ref() |
| | | // 宿¶ä»»å¡å¼¹çªæ§å¶å¨ |
| | | const formDiaRef = ref() |
| | | // éä»¶å¼¹çª |
| | | const fileListDialogRef = ref(null) |
| | | const fileDialogVisible = ref(false) |
| | | const currentMaintenanceTaskId = ref(null) |
| | | /** å½åéä»¶æå±è®°å½æ¯å¦å·²å®ç»ï¼status=1ï¼ */ |
| | | const currentRecordFinished = ref(false) |
| | | |
| | | const javaApi = import.meta.env.VITE_APP_BASE_API |
| | | const maintenanceFileUploadUrl = `${javaApi}/maintenanceTaskFile/upload` |
| | | const maintenanceFileUploadData = computed(() => ({ |
| | | deviceMaintenanceId: currentMaintenanceTaskId.value, |
| | | })) |
| | | |
| | | const normalizeMaintenanceFileUrl = (rawUrl = "") => { |
| | | let fileUrl = rawUrl || "" |
| | | if (!fileUrl) return "" |
| | | if (fileUrl.startsWith("http://") || fileUrl.startsWith("https://")) return fileUrl |
| | | if (fileUrl.indexOf("\\") > -1) { |
| | | const lowerPath = fileUrl.toLowerCase() |
| | | const uploadPathIndex = lowerPath.indexOf("uploadpath") |
| | | if (uploadPathIndex > -1) { |
| | | fileUrl = fileUrl.substring(uploadPathIndex).replace(/\\/g, "/") |
| | | } else { |
| | | fileUrl = fileUrl.replace(/\\/g, "/") |
| | | } |
| | | } |
| | | fileUrl = fileUrl.replace(/^\/?uploadPath/i, "/profile") |
| | | if (!fileUrl.startsWith("/")) fileUrl = "/" + fileUrl |
| | | if (!fileUrl.startsWith(javaApi)) fileUrl = javaApi + fileUrl |
| | | return fileUrl |
| | | } |
| | | |
| | | // ä»»å¡è®°å½tabï¼å设å¤ä¿å
»é¡µé¢ï¼ç¸å
³åé |
| | | const filters = reactive({ |
| | |
| | | } |
| | | }, |
| | | { prop: "registrant", label: "ç»è®°äºº", minWidth: 100 }, |
| | | { prop: "maintenancePerson", label: "ä¿å
»äºº", minWidth: 100 }, |
| | | { |
| | | prop: "maintenanceItems", |
| | | label: "ä¿å
»é¡¹ç®", |
| | | minWidth: 180, |
| | | showOverflowTooltip: true, |
| | | }, |
| | | { prop: "registrationDate", label: "ç»è®°æ¥æ", minWidth: 100 }, |
| | | { |
| | | fixed: "right", |
| | |
| | | label: "ä¿å
»é¡¹ç®", |
| | | align: "center", |
| | | prop: "maintenanceLocation", |
| | | showOverflowTooltip: true, |
| | | }, |
| | | { |
| | | label: "ä¿å
»äºº", |
| | | align: "center", |
| | | prop: "maintenancePerson", |
| | | }, |
| | | { |
| | | label: "计åä¿å
»æ¥æ", |
| | |
| | | label: "ä¿å
ȍȾ", |
| | | align: "center", |
| | | prop: "maintenanceResult", |
| | | dataType: "slot", |
| | | slot: "maintenanceResultRef", |
| | | minWidth: 200, |
| | | showOverflowTooltip: true, |
| | | }, |
| | | { |
| | | label: "ç¶æ", |
| | |
| | | dataType: "slot", |
| | | slot: "operation", |
| | | align: "center", |
| | | width: "350px", |
| | | width: "400px", |
| | | }, |
| | | ]) |
| | | |
| | |
| | | current: 1, |
| | | size: 100, |
| | | deviceMaintenanceId, |
| | | rulesRegulationsManagementId:deviceMaintenanceId |
| | | } |
| | | const res = await listMaintenanceTaskFiles(params) |
| | | const records = res?.data?.records || [] |
| | | const mapped = records.map(item => ({ |
| | | id: item.id, |
| | | name: item.fileName || item.name, |
| | | url: item.fileUrl || item.url, |
| | | url: normalizeMaintenanceFileUrl(item.fileUrl || item.url), |
| | | raw: item, |
| | | })) |
| | | fileListDialogRef.value?.setList(mapped) |
| | |
| | | } |
| | | } |
| | | |
| | | const openDetail = (row) => { |
| | | upkeepDetailModalRef.value?.open(row) |
| | | } |
| | | |
| | | // æå¼éä»¶å¼¹çª |
| | | const openFileDialog = async (row) => { |
| | | currentMaintenanceTaskId.value = row.id |
| | | currentRecordFinished.value = row.status === 1 |
| | | fileDialogVisible.value = true |
| | | await fetchMaintenanceTaskFiles(row.id) |
| | | } |
| | |
| | | await fetchMaintenanceTaskFiles(currentMaintenanceTaskId.value) |
| | | } |
| | | |
| | | // ä¸ä¼ éä»¶ |
| | | const handleAttachmentUpload = async (filePayload) => { |
| | | if (!currentMaintenanceTaskId.value) return |
| | | try { |
| | | const payload = { |
| | | name: filePayload?.fileName || filePayload?.name, |
| | | url: filePayload?.fileUrl || filePayload?.url, |
| | | deviceMaintenanceId: currentMaintenanceTaskId.value, |
| | | } |
| | | await addMaintenanceTaskFile(payload) |
| | | ElMessage.success('æä»¶ä¸ä¼ æå') |
| | | await refreshFileList() |
| | | } catch (error) { |
| | | ElMessage.error('æä»¶ä¸ä¼ 失败') |
| | | } |
| | | } |
| | | |
| | | // å é¤éä»¶ |
| | | // å é¤éä»¶ï¼å·²å®ç»ä¸å¯å ï¼ |
| | | const handleAttachmentDelete = async (row) => { |
| | | if (currentRecordFinished.value) { |
| | | ElMessage.warning('该ä¿å
»å·²å®ç»ï¼ä¸å¯å é¤éä»¶') |
| | | return false |
| | | } |
| | | if (!row?.id) return false |
| | | try { |
| | | await ElMessageBox.confirm('确认å é¤è¯¥éä»¶ï¼', 'æç¤º', { type: 'warning' }) |