| | |
| | | <template> |
| | | <FormDialog v-model="visible" |
| | | :title="computedTitle" |
| | | :operation-type="operationType" |
| | | width="800px" |
| | | @confirm="sendForm" |
| | | @cancel="handleCancel" |
| | | @close="handleClose"> |
| | | <el-form :model="form" |
| | | label-width="100px"> |
| | | <FormDialog |
| | | v-model="visible" |
| | | :title="id ? '编辑设备报修' : '新增设备报修'" |
| | | width="800px" |
| | | @confirm="sendForm" |
| | | @cancel="handleCancel" |
| | | @close="handleClose" |
| | | > |
| | | <el-form :model="form" label-width="100px"> |
| | | <el-row> |
| | | <el-col :span="12"> |
| | | <el-form-item label="所属区域"> |
| | | <el-tree-select |
| | | v-model="form.areaId" |
| | | :data="areaOptions" |
| | | :props="areaTreeProps" |
| | | node-key="id" |
| | | value-key="id" |
| | | check-strictly |
| | | clearable |
| | | filterable |
| | | placeholder="请选择所属区域" |
| | | style="width: 100%" |
| | | @change="handleAreaChange" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="设备名称"> |
| | | <el-select v-model="form.deviceLedgerId" |
| | | @change="setDeviceModel" |
| | | filterable |
| | | :disabled="operationType === 'view'"> |
| | | <el-option v-for="(item, index) in deviceOptions" |
| | | :key="index" |
| | | :label="item.deviceName" |
| | | :value="item.id"></el-option> |
| | | <el-select |
| | | v-model="form.deviceLedgerIds" |
| | | filterable |
| | | clearable |
| | | multiple |
| | | collapse-tags |
| | | collapse-tags-tooltip |
| | | placeholder="请先选择区域,再选择设备" |
| | | style="width: 100%" |
| | | @change="setDeviceModels" |
| | | > |
| | | <el-option |
| | | v-for="item in deviceOptions" |
| | | :key="item.id" |
| | | :label="item.deviceName" |
| | | :value="item.id" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="规格型号"> |
| | | <el-input v-model="form.deviceModel" |
| | | placeholder="请输入规格型号" |
| | | disabled /> |
| | | <el-input |
| | | v-model="form.deviceModel" |
| | | placeholder="自动带出规格型号" |
| | | disabled |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="报修日期"> |
| | | <el-date-picker v-model="form.repairTime" |
| | | placeholder="请选择报修日期" |
| | | format="YYYY-MM-DD" |
| | | value-format="YYYY-MM-DD" |
| | | type="date" |
| | | clearable |
| | | style="width: 100%" |
| | | :disabled="operationType === 'view'" /> |
| | | <el-date-picker |
| | | v-model="form.repairTime" |
| | | placeholder="请选择报修日期" |
| | | format="YYYY-MM-DD" |
| | | value-format="YYYY-MM-DD" |
| | | type="date" |
| | | clearable |
| | | style="width: 100%" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="报修人"> |
| | | <el-input v-model="form.repairName" |
| | | placeholder="请输入报修人" |
| | | :disabled="operationType === 'view'" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="报修报修项目"> |
| | | <el-input v-model="form.machineryCategory" |
| | | placeholder="请输入报修报修项目" |
| | | :disabled="operationType === 'view'" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row> |
| | | <el-col :span="12"> |
| | | <el-form-item label="维修人"> |
| | | <el-input v-model="form.maintenanceName" |
| | | placeholder="请输入维修人姓名" |
| | | :disabled="operationType === 'view'" /> |
| | | <el-input v-model="form.repairName" placeholder="请输入报修人" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row v-if="id"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="报修状态"> |
| | | <el-select v-model="form.status" |
| | | disabled> |
| | | <el-option label="待维修" |
| | | :value="0"></el-option> |
| | | <el-option label="已验收" |
| | | :value="1"></el-option> |
| | | <el-option label="失败" |
| | | :value="2"></el-option> |
| | | <el-select v-model="form.status"> |
| | | <el-option label="待维修" :value="0" /> |
| | | <el-option label="完结" :value="1" /> |
| | | <el-option label="失败" :value="2" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <!-- 验收信息展示 --> |
| | | <el-row v-if="id && (form.status === 1 || form.status === 3)"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="验收人"> |
| | | <el-input v-model="form.acceptanceName" |
| | | disabled /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="验收时间"> |
| | | <el-input v-model="form.acceptanceTime" |
| | | disabled /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="24"> |
| | | <el-form-item label="验收备注"> |
| | | <el-input v-model="form.acceptanceRemark" |
| | | type="textarea" |
| | | :rows="2" |
| | | disabled /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row> |
| | | <el-col :span="24"> |
| | | <el-form-item label="故障现象"> |
| | | <el-input v-model="form.remark" |
| | | :rows="2" |
| | | type="textarea" |
| | | placeholder="请输入故障现象" |
| | | :disabled="operationType === 'view'" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row v-if="operationType !== 'view'" |
| | | :gutter="30"> |
| | | <el-col :span="24"> |
| | | <el-form-item label="附件" |
| | | prop="attachmentIds"> |
| | | <FileUpload v-model:file-list="form.storageBlobDTOs" |
| | | :disabled="operationType === 'view'" /> |
| | | <el-input |
| | | v-model="form.remark" |
| | | :rows="2" |
| | | type="textarea" |
| | | placeholder="请输入故障现象" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | |
| | | </template> |
| | | |
| | | <script setup> |
| | | import FormDialog from "@/components/Dialog/FormDialog.vue"; |
| | | import FileUpload from "@/components/AttachmentUpload/file/index.vue"; |
| | | import { |
| | | addRepair, |
| | | editRepair, |
| | | getRepairById, |
| | | } from "@/api/equipmentManagement/repair"; |
| | | import { ElMessage } from "element-plus"; |
| | | import dayjs from "dayjs"; |
| | | import useFormData from "@/hooks/useFormData"; |
| | | import { getDeviceLedger } from "@/api/equipmentManagement/ledger"; |
| | | import useUserStore from "@/store/modules/user"; |
| | | import { nextTick, ref, unref } from "vue"; |
| | | import dayjs from "dayjs"; |
| | | import { ElMessage } from "element-plus"; |
| | | import FormDialog from "@/components/Dialog/FormDialog.vue"; |
| | | import useFormData from "@/hooks/useFormData"; |
| | | import useUserStore from "@/store/modules/user"; |
| | | import { |
| | | addRepair, |
| | | editRepair, |
| | | getRepairById, |
| | | } from "@/api/equipmentManagement/repair"; |
| | | import { |
| | | getDeviceAreaTree, |
| | | getDeviceAreaTreeWithDevices, |
| | | } from "@/api/equipmentManagement/deviceArea"; |
| | | |
| | | defineOptions({ |
| | | name: "设备报修弹窗", |
| | | }); |
| | | defineOptions({ |
| | | name: "设备报修弹窗", |
| | | }); |
| | | |
| | | const emits = defineEmits(["ok"]); |
| | | const emits = defineEmits(["ok"]); |
| | | |
| | | const id = ref(); |
| | | const visible = ref(false); |
| | | const loading = ref(false); |
| | | const operationType = ref(""); // add, edit, view |
| | | const id = ref(); |
| | | const visible = ref(false); |
| | | const loading = ref(false); |
| | | const userStore = useUserStore(); |
| | | const areaOptions = ref([]); |
| | | const deviceOptions = ref([]); |
| | | const areaTreeProps = { |
| | | label: "areaName", |
| | | children: "children", |
| | | }; |
| | | |
| | | const computedTitle = computed(() => { |
| | | if (operationType.value === "add") return "新增设备报修"; |
| | | if (operationType.value === "edit") return "编辑设备报修"; |
| | | if (operationType.value === "view") return "设备报修详情"; |
| | | return ""; |
| | | }); |
| | | const { form, resetForm } = useFormData({ |
| | | areaId: undefined, |
| | | deviceLedgerId: undefined, |
| | | deviceLedgerIds: [], |
| | | deviceLedgerIdsStr: undefined, |
| | | deviceName: undefined, |
| | | deviceModel: undefined, |
| | | repairTime: dayjs().format("YYYY-MM-DD"), |
| | | repairName: userStore.nickName, |
| | | remark: undefined, |
| | | status: 0, |
| | | }); |
| | | |
| | | const userStore = useUserStore(); |
| | | const deviceOptions = ref([]); |
| | | const fileList = ref([]); |
| | | const loadAreaTree = async () => { |
| | | const { data } = await getDeviceAreaTree(); |
| | | areaOptions.value = Array.isArray(data) ? data : []; |
| | | }; |
| | | |
| | | const loadDeviceName = async () => { |
| | | const { data } = await getDeviceLedger(); |
| | | deviceOptions.value = data; |
| | | }; |
| | | const normalizeIdList = (value) => { |
| | | if (Array.isArray(value)) { |
| | | return value |
| | | .map((item) => Number(item)) |
| | | .filter((item) => Number.isFinite(item)); |
| | | } |
| | | if (typeof value === "string") { |
| | | return value |
| | | .split(",") |
| | | .map((item) => Number(item.trim())) |
| | | .filter((item) => Number.isFinite(item)); |
| | | } |
| | | if (value !== undefined && value !== null && value !== "") { |
| | | const numericValue = Number(value); |
| | | return Number.isFinite(numericValue) ? [numericValue] : []; |
| | | } |
| | | return []; |
| | | }; |
| | | |
| | | const { form, resetForm } = useFormData({ |
| | | deviceLedgerId: undefined, // 设备Id |
| | | deviceName: undefined, // 设备名称 |
| | | deviceModel: undefined, // 规格型号 |
| | | repairTime: dayjs().format("YYYY-MM-DD"), // 报修日期,默认当天 |
| | | repairName: userStore.nickName, // 报修人 |
| | | remark: undefined, // 故障现象 |
| | | status: 0, // 报修状态 |
| | | machineryCategory: undefined, |
| | | storageBlobDTOs: [], |
| | | maintenanceName: undefined, // 维修人 |
| | | }); |
| | | const getNodeDevices = (node) => { |
| | | const candidates = [ |
| | | node?.deviceList, |
| | | node?.devices, |
| | | node?.deviceLedgerList, |
| | | node?.deviceLedgers, |
| | | node?.ledgerList, |
| | | node?.ledgers, |
| | | ]; |
| | | return candidates.find((item) => Array.isArray(item)) || []; |
| | | }; |
| | | |
| | | const setDeviceModel = deviceId => { |
| | | const option = deviceOptions.value.find(item => item.id === deviceId); |
| | | form.deviceModel = option.deviceModel; |
| | | }; |
| | | const normalizeDevice = (item) => ({ |
| | | ...item, |
| | | id: item.id ?? item.deviceLedgerId, |
| | | deviceName: item.deviceName ?? item.name, |
| | | deviceModel: item.deviceModel ?? item.model, |
| | | }); |
| | | |
| | | const setForm = data => { |
| | | form.deviceLedgerId = data.deviceLedgerId; |
| | | form.deviceName = data.deviceName; |
| | | form.deviceModel = data.deviceModel; |
| | | form.repairTime = data.repairTime; |
| | | form.repairName = data.repairName; |
| | | form.remark = data.remark; |
| | | form.status = data.status; |
| | | form.machineryCategory = data.machineryCategory; |
| | | form.storageBlobDTOs = data.storageBlobVOs || []; |
| | | form.maintenanceName = data.maintenanceName; |
| | | form.acceptanceName = data.acceptanceName; |
| | | form.acceptanceTime = data.acceptanceTime; |
| | | form.acceptanceRemark = data.acceptanceRemark; |
| | | }; |
| | | |
| | | const sendForm = async () => { |
| | | loading.value = true; |
| | | try { |
| | | const { code } = id.value |
| | | ? await editRepair({ id: unref(id), ...form }) |
| | | : await addRepair(form); |
| | | if (code == 200) { |
| | | ElMessage.success(`${id.value ? "编辑" : "新增"}报修成功`); |
| | | visible.value = false; |
| | | emits("ok"); |
| | | } |
| | | } finally { |
| | | loading.value = false; |
| | | const collectDevices = (node) => { |
| | | const currentDevices = getNodeDevices(node).map(normalizeDevice); |
| | | const childDevices = (node?.children || []).flatMap((child) => |
| | | collectDevices(child) |
| | | ); |
| | | const deviceMap = new Map(); |
| | | [...currentDevices, ...childDevices].forEach((item) => { |
| | | if (item?.id !== undefined && item?.id !== null) { |
| | | deviceMap.set(Number(item.id), item); |
| | | } |
| | | }; |
| | | |
| | | const handleCancel = () => { |
| | | resetForm(); |
| | | visible.value = false; |
| | | }; |
| | | |
| | | const handleClose = () => { |
| | | resetForm(); |
| | | visible.value = false; |
| | | }; |
| | | |
| | | const openAdd = async () => { |
| | | id.value = undefined; |
| | | operationType.value = "add"; |
| | | visible.value = true; |
| | | fileList.value = []; |
| | | await nextTick(); |
| | | await loadDeviceName(); |
| | | }; |
| | | |
| | | const openEdit = async editId => { |
| | | const { data } = await getRepairById(editId); |
| | | id.value = editId; |
| | | operationType.value = "edit"; |
| | | visible.value = true; |
| | | await nextTick(); |
| | | await loadDeviceName(); |
| | | setForm(data); |
| | | }; |
| | | |
| | | const openView = async viewId => { |
| | | const { data } = await getRepairById(viewId); |
| | | id.value = viewId; |
| | | operationType.value = "view"; |
| | | visible.value = true; |
| | | await nextTick(); |
| | | await loadDeviceName(); |
| | | setForm(data); |
| | | }; |
| | | |
| | | defineExpose({ |
| | | openAdd, |
| | | openEdit, |
| | | openView, |
| | | }); |
| | | return Array.from(deviceMap.values()); |
| | | }; |
| | | |
| | | const findAreaNode = (nodes, areaId) => { |
| | | for (const node of nodes || []) { |
| | | if (Number(node.id) === Number(areaId)) { |
| | | return node; |
| | | } |
| | | const target = findAreaNode(node.children, areaId); |
| | | if (target) { |
| | | return target; |
| | | } |
| | | } |
| | | return null; |
| | | }; |
| | | |
| | | const loadDevicesByArea = async (areaId) => { |
| | | if (!areaId) { |
| | | deviceOptions.value = []; |
| | | return; |
| | | } |
| | | const { data } = await getDeviceAreaTreeWithDevices(); |
| | | const treeData = Array.isArray(data) ? data : []; |
| | | const currentNode = findAreaNode(treeData, areaId); |
| | | deviceOptions.value = currentNode ? collectDevices(currentNode) : []; |
| | | }; |
| | | |
| | | const syncDeviceFields = (deviceIds) => { |
| | | const selectedIds = normalizeIdList(deviceIds); |
| | | const selectedDevices = selectedIds |
| | | .map((deviceId) => |
| | | deviceOptions.value.find((item) => Number(item.id) === Number(deviceId)) |
| | | ) |
| | | .filter(Boolean); |
| | | |
| | | form.deviceLedgerIds = selectedIds; |
| | | form.deviceLedgerId = selectedIds[0]; |
| | | form.deviceLedgerIdsStr = selectedIds.join(","); |
| | | form.deviceName = selectedDevices |
| | | .map((item) => item.deviceName) |
| | | .filter(Boolean) |
| | | .join(","); |
| | | form.deviceModel = selectedDevices |
| | | .map((item) => item.deviceModel || "-") |
| | | .join(","); |
| | | }; |
| | | |
| | | const setDeviceModels = (deviceIds) => { |
| | | syncDeviceFields(deviceIds); |
| | | }; |
| | | |
| | | const setForm = (data) => { |
| | | form.areaId = data.areaId; |
| | | form.deviceLedgerIds = normalizeIdList( |
| | | data.deviceLedgerIds ?? data.deviceLedgerIdsStr ?? data.deviceLedgerId |
| | | ); |
| | | form.deviceLedgerId = form.deviceLedgerIds[0]; |
| | | form.deviceLedgerIdsStr = |
| | | data.deviceLedgerIdsStr ?? form.deviceLedgerIds.join(","); |
| | | form.deviceName = data.deviceName; |
| | | form.deviceModel = data.deviceModel; |
| | | form.repairTime = data.repairTime; |
| | | form.repairName = data.repairName; |
| | | form.remark = data.remark; |
| | | form.status = data.status; |
| | | }; |
| | | |
| | | const handleAreaChange = async (areaId) => { |
| | | form.deviceLedgerId = undefined; |
| | | form.deviceLedgerIds = []; |
| | | form.deviceLedgerIdsStr = undefined; |
| | | form.deviceName = undefined; |
| | | form.deviceModel = undefined; |
| | | await loadDevicesByArea(areaId); |
| | | }; |
| | | |
| | | const sendForm = async () => { |
| | | loading.value = true; |
| | | try { |
| | | syncDeviceFields(form.deviceLedgerIds); |
| | | const payload = { |
| | | ...form, |
| | | deviceLedgerId: form.deviceLedgerIds[0], |
| | | deviceLedgerIds: [...form.deviceLedgerIds], |
| | | deviceLedgerIdsStr: form.deviceLedgerIds.join(","), |
| | | deviceModel: form.deviceModel || "-", |
| | | }; |
| | | const { code } = id.value |
| | | ? await editRepair({ id: unref(id), ...payload }) |
| | | : await addRepair(payload); |
| | | if (code === 200) { |
| | | ElMessage.success(`${id.value ? "编辑" : "新增"}报修成功`); |
| | | visible.value = false; |
| | | emits("ok"); |
| | | } |
| | | } finally { |
| | | loading.value = false; |
| | | } |
| | | }; |
| | | |
| | | const handleCancel = () => { |
| | | resetForm(); |
| | | visible.value = false; |
| | | }; |
| | | |
| | | const handleClose = () => { |
| | | resetForm(); |
| | | visible.value = false; |
| | | }; |
| | | |
| | | const openAdd = async () => { |
| | | id.value = undefined; |
| | | visible.value = true; |
| | | await nextTick(); |
| | | await loadAreaTree(); |
| | | deviceOptions.value = []; |
| | | }; |
| | | |
| | | const openEdit = async (editId) => { |
| | | const { data } = await getRepairById(editId); |
| | | id.value = editId; |
| | | visible.value = true; |
| | | await nextTick(); |
| | | await loadAreaTree(); |
| | | setForm(data); |
| | | await loadDevicesByArea(form.areaId); |
| | | syncDeviceFields(form.deviceLedgerIds); |
| | | }; |
| | | |
| | | defineExpose({ |
| | | openAdd, |
| | | openEdit, |
| | | }); |
| | | </script> |
| | | |
| | | <style lang="scss" scoped></style> |