|
@@ -1,4 +1,4 @@
|
|
|
-<!--设备故障工单(故障维修 orderType=1,参考排水/燃气工单形态)-->
|
|
|
|
|
|
|
+<!--设备故障工单(故障维修 orderType=1,参考排水/燃气工单形态)-->
|
|
|
<!--数据源:/api/work-order/*(orderType=1 过滤;equipmentType 为空 = 所有设备)-->
|
|
<!--数据源:/api/work-order/*(orderType=1 过滤;equipmentType 为空 = 所有设备)-->
|
|
|
<!--需求 5.2.4.4.1:手动新增字段=设备类型/设备ID/设备位置/设备厂家/维护人员/联系方式/故障时间/故障描述-->
|
|
<!--需求 5.2.4.4.1:手动新增字段=设备类型/设备ID/设备位置/设备厂家/维护人员/联系方式/故障时间/故障描述-->
|
|
|
<template>
|
|
<template>
|
|
@@ -6,7 +6,7 @@
|
|
|
<!-- 顶部搜索区(参考排水/燃气工单) -->
|
|
<!-- 顶部搜索区(参考排水/燃气工单) -->
|
|
|
<el-card class="search-card" shadow="never">
|
|
<el-card class="search-card" shadow="never">
|
|
|
<div class="search-form">
|
|
<div class="search-form">
|
|
|
- <el-form :model="queryParams" ref="queryFormRef" :inline>
|
|
|
|
|
|
|
+ <el-form :model="queryParams" ref="queryFormRef" inline>
|
|
|
<el-form-item label="优先级">
|
|
<el-form-item label="优先级">
|
|
|
<el-select v-model="queryParams.orderLevel" placeholder="全部优先级" clearable style="width: 120px">
|
|
<el-select v-model="queryParams.orderLevel" placeholder="全部优先级" clearable style="width: 120px">
|
|
|
<el-option v-for="(v, k) in ORDER_LEVEL_MAP" :key="k" :label="v.text" :value="Number(k)"/>
|
|
<el-option v-for="(v, k) in ORDER_LEVEL_MAP" :key="k" :label="v.text" :value="Number(k)"/>
|
|
@@ -136,13 +136,7 @@
|
|
|
</el-descriptions>
|
|
</el-descriptions>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
- <!-- 工单图片 -->
|
|
|
|
|
- <div v-if="workImageList.length > 0" class="image-section">
|
|
|
|
|
- <h4 class="section-title">工单图片</h4>
|
|
|
|
|
- <div class="image-list">
|
|
|
|
|
- <image-preview v-for="(img, index) in workImageList" :key="index" :src="img" :width="100" :height="100"/>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
|
|
+ <RepairImagePanel :before-images="selectedOrder.maintenanceBeforeImg" :after-images="selectedOrder.maintenanceAfterImg" />
|
|
|
|
|
|
|
|
<!-- 工单操作(参考排水/燃气工单按钮组) -->
|
|
<!-- 工单操作(参考排水/燃气工单按钮组) -->
|
|
|
<div class="action-section">
|
|
<div class="action-section">
|
|
@@ -294,6 +288,9 @@
|
|
|
<!-- 核查/处理弹窗 -->
|
|
<!-- 核查/处理弹窗 -->
|
|
|
<el-dialog v-model="actionDialogVisible" :title="actionTitle" width="600px" append-to-body>
|
|
<el-dialog v-model="actionDialogVisible" :title="actionTitle" width="600px" append-to-body>
|
|
|
<el-form label-width="90px">
|
|
<el-form label-width="90px">
|
|
|
|
|
+ <el-form-item v-if="actionTitle === '处理工单'" label="处理前照片">
|
|
|
|
|
+ <ImageUpload v-model="processBeforeImages" :limit="9" :isShowTip="true" :upload-url="imageUploadUrl" />
|
|
|
|
|
+ </el-form-item>
|
|
|
<el-form-item label="结果说明" required>
|
|
<el-form-item label="结果说明" required>
|
|
|
<el-input v-model="actionFormData.solution" type="textarea" :rows="5" :placeholder="actionTitle === '核查工单' ? '请输入核查结论(属实/不属实、现场情况)' : '请输入故障原因、处理结果及处理措施'" maxlength="500" show-word-limit/>
|
|
<el-input v-model="actionFormData.solution" type="textarea" :rows="5" :placeholder="actionTitle === '核查工单' ? '请输入核查结论(属实/不属实、现场情况)' : '请输入故障原因、处理结果及处理措施'" maxlength="500" show-word-limit/>
|
|
|
</el-form-item>
|
|
</el-form-item>
|
|
@@ -305,8 +302,11 @@
|
|
|
</el-dialog>
|
|
</el-dialog>
|
|
|
|
|
|
|
|
<!-- 提交验收弹窗 -->
|
|
<!-- 提交验收弹窗 -->
|
|
|
- <el-dialog v-model="completeDialogVisible" title="提交验收" width="500px" append-to-body>
|
|
|
|
|
|
|
+ <el-dialog v-model="completeDialogVisible" title="提交验收" width="600px" append-to-body>
|
|
|
<el-form label-width="80px">
|
|
<el-form label-width="80px">
|
|
|
|
|
+ <el-form-item label="维修后照片">
|
|
|
|
|
+ <ImageUpload v-model="maintenanceAfterImages" :limit="9" :isShowTip="true" :upload-url="imageUploadUrl" />
|
|
|
|
|
+ </el-form-item>
|
|
|
<el-form-item label="验收意见">
|
|
<el-form-item label="验收意见">
|
|
|
<el-input v-model="completeForm.result" type="textarea" :rows="4" placeholder="请填写维修处置结果说明" maxlength="500" show-word-limit/>
|
|
<el-input v-model="completeForm.result" type="textarea" :rows="4" placeholder="请填写维修处置结果说明" maxlength="500" show-word-limit/>
|
|
|
</el-form-item>
|
|
</el-form-item>
|
|
@@ -335,7 +335,7 @@
|
|
|
<script setup>
|
|
<script setup>
|
|
|
import { ref, reactive, computed, watch, onMounted } from 'vue'
|
|
import { ref, reactive, computed, watch, onMounted } from 'vue'
|
|
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
|
|
-import ImagePreview from '@/components/ImagePreview'
|
|
|
|
|
|
|
+import RepairImagePanel from '@/components/RepairImagePanel'
|
|
|
import { listWorkOrder, getWorkOrderDetail, addWorkOrder, dispatchWorkOrder, verifyWorkOrder, processWorkOrder, completeWorkOrder, closeWorkOrder, cancelWorkOrder } from '@/api/work/order'
|
|
import { listWorkOrder, getWorkOrderDetail, addWorkOrder, dispatchWorkOrder, verifyWorkOrder, processWorkOrder, completeWorkOrder, closeWorkOrder, cancelWorkOrder } from '@/api/work/order'
|
|
|
import { getEquipmentFullPage } from '@/api/pipeNetwork/basic'
|
|
import { getEquipmentFullPage } from '@/api/pipeNetwork/basic'
|
|
|
import { listDept } from '@/api/system/dept'
|
|
import { listDept } from '@/api/system/dept'
|
|
@@ -389,11 +389,6 @@ const currentOrderLogs = ref([])
|
|
|
const detailLoading = ref(false)
|
|
const detailLoading = ref(false)
|
|
|
const detailDevice = ref(null)
|
|
const detailDevice = ref(null)
|
|
|
|
|
|
|
|
-const workImageList = computed(() => {
|
|
|
|
|
- if (!selectedOrder.value.workImage) return []
|
|
|
|
|
- return selectedOrder.value.workImage.split(',').filter(img => img && img.trim())
|
|
|
|
|
-})
|
|
|
|
|
-
|
|
|
|
|
async function handleSelectOrder(order) {
|
|
async function handleSelectOrder(order) {
|
|
|
selectedOrderId.value = order.orderId
|
|
selectedOrderId.value = order.orderId
|
|
|
selectedOrder.value = { ...order }
|
|
selectedOrder.value = { ...order }
|
|
@@ -599,6 +594,8 @@ async function submitDispatch() {
|
|
|
const actionDialogVisible = ref(false)
|
|
const actionDialogVisible = ref(false)
|
|
|
const actionTitle = ref('')
|
|
const actionTitle = ref('')
|
|
|
const actionFormData = reactive({ solution: '' })
|
|
const actionFormData = reactive({ solution: '' })
|
|
|
|
|
+const processBeforeImages = ref('')
|
|
|
|
|
+const imageUploadUrl = import.meta.env.VITE_APP_BASE_API + '/minio/upload'
|
|
|
|
|
|
|
|
function handleVerify() {
|
|
function handleVerify() {
|
|
|
if (!canOperate.verify(selectedOrder.value)) {
|
|
if (!canOperate.verify(selectedOrder.value)) {
|
|
@@ -607,6 +604,7 @@ function handleVerify() {
|
|
|
}
|
|
}
|
|
|
actionTitle.value = '核查工单'
|
|
actionTitle.value = '核查工单'
|
|
|
actionFormData.solution = ''
|
|
actionFormData.solution = ''
|
|
|
|
|
+ processBeforeImages.value = ''
|
|
|
actionDialogVisible.value = true
|
|
actionDialogVisible.value = true
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -615,9 +613,26 @@ function handleProcess() {
|
|
|
ElMessage.warning('当前工单不允许处理')
|
|
ElMessage.warning('当前工单不允许处理')
|
|
|
return
|
|
return
|
|
|
}
|
|
}
|
|
|
- actionTitle.value = '处理工单'
|
|
|
|
|
- actionFormData.solution = ''
|
|
|
|
|
- actionDialogVisible.value = true
|
|
|
|
|
|
|
+
|
|
|
|
|
+ ElMessageBox.alert(
|
|
|
|
|
+ '<div style="padding: 10px; color: #666;">' +
|
|
|
|
|
+ '<strong>维修操作指引:</strong><br/><br/>' +
|
|
|
|
|
+ '• 在下方表格中可以上传处理前的照片(最多9张)<br/>' +
|
|
|
|
|
+ '• 请选择本地图片或拍照上传<br/>' +
|
|
|
|
|
+ '• 填写处理说明后点击"确定"提交<br/>' +
|
|
|
|
|
+ '</div>',
|
|
|
|
|
+ '开始维修',
|
|
|
|
|
+ {
|
|
|
|
|
+ dangerouslyUseHTMLString: true,
|
|
|
|
|
+ confirmButtonText: '我已了解',
|
|
|
|
|
+ center: false
|
|
|
|
|
+ }
|
|
|
|
|
+ ).then(() => {
|
|
|
|
|
+ actionTitle.value = '处理工单'
|
|
|
|
|
+ actionFormData.solution = ''
|
|
|
|
|
+ processBeforeImages.value = ''
|
|
|
|
|
+ actionDialogVisible.value = true
|
|
|
|
|
+ }).catch(() => {})
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
async function submitAction() {
|
|
async function submitAction() {
|
|
@@ -632,6 +647,9 @@ async function submitAction() {
|
|
|
handleResult: 'solved',
|
|
handleResult: 'solved',
|
|
|
solution: actionFormData.solution
|
|
solution: actionFormData.solution
|
|
|
}
|
|
}
|
|
|
|
|
+ if (actionTitle.value === '处理工单' && processBeforeImages.value) {
|
|
|
|
|
+ data.maintenanceBeforeImg = processBeforeImages.value
|
|
|
|
|
+ }
|
|
|
if (actionTitle.value === '核查工单') {
|
|
if (actionTitle.value === '核查工单') {
|
|
|
await verifyWorkOrder(data)
|
|
await verifyWorkOrder(data)
|
|
|
} else {
|
|
} else {
|
|
@@ -647,6 +665,7 @@ async function submitAction() {
|
|
|
// ========== 提交验收(后端 completeOrder 要求状态 4) ==========
|
|
// ========== 提交验收(后端 completeOrder 要求状态 4) ==========
|
|
|
const completeDialogVisible = ref(false)
|
|
const completeDialogVisible = ref(false)
|
|
|
const completeForm = reactive({ result: '' })
|
|
const completeForm = reactive({ result: '' })
|
|
|
|
|
+const maintenanceAfterImages = ref('')
|
|
|
|
|
|
|
|
function handleComplete() {
|
|
function handleComplete() {
|
|
|
if (!canOperate.complete(selectedOrder.value)) {
|
|
if (!canOperate.complete(selectedOrder.value)) {
|
|
@@ -654,6 +673,7 @@ function handleComplete() {
|
|
|
return
|
|
return
|
|
|
}
|
|
}
|
|
|
completeForm.result = ''
|
|
completeForm.result = ''
|
|
|
|
|
+ maintenanceAfterImages.value = ''
|
|
|
completeDialogVisible.value = true
|
|
completeDialogVisible.value = true
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -664,7 +684,11 @@ async function submitComplete() {
|
|
|
}
|
|
}
|
|
|
submitting.value = true
|
|
submitting.value = true
|
|
|
try {
|
|
try {
|
|
|
- await completeWorkOrder(selectedOrder.value.orderId, completeForm.result)
|
|
|
|
|
|
|
+ await completeWorkOrder({
|
|
|
|
|
+ orderId: selectedOrder.value.orderId,
|
|
|
|
|
+ result: completeForm.result,
|
|
|
|
|
+ maintenanceAfterImg: maintenanceAfterImages.value
|
|
|
|
|
+ })
|
|
|
ElMessage.success('提交验收成功')
|
|
ElMessage.success('提交验收成功')
|
|
|
completeDialogVisible.value = false
|
|
completeDialogVisible.value = false
|
|
|
refreshAfterAction()
|
|
refreshAfterAction()
|
|
@@ -900,6 +924,17 @@ onMounted(() => {
|
|
|
gap: 12px;
|
|
gap: 12px;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ .image-group + .image-group {
|
|
|
|
|
+ margin-top: 16px;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .image-label {
|
|
|
|
|
+ display: block;
|
|
|
|
|
+ margin-bottom: 8px;
|
|
|
|
|
+ color: #606266;
|
|
|
|
|
+ font-size: 13px;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
.action-buttons {
|
|
.action-buttons {
|
|
|
display: flex;
|
|
display: flex;
|
|
|
gap: 12px;
|
|
gap: 12px;
|