|
|
@@ -20,19 +20,25 @@
|
|
|
|
|
|
<el-card shadow="never" class="water-panel">
|
|
|
<div class="card-title"><span><el-icon><Monitor /></el-icon> {{ title }}清单</span><el-button link type="primary" @click="exportData">导出</el-button></div>
|
|
|
+ <el-alert v-if="loadError" :title="loadError" type="error" show-icon :closable="false" class="load-error"><el-button size="small" type="danger" plain @click="loadData">重试</el-button></el-alert>
|
|
|
+ <el-empty v-if="view === 'gis' && !loading && !loadError && !page.records.length" description="暂无设备 GIS 点位数据" />
|
|
|
<el-table :data="page.records" border stripe v-loading="loading" row-key="equipmentId">
|
|
|
<el-table-column type="index" label="#" width="55" /><el-table-column prop="equipmentCode" label="设备编码" min-width="130" /><el-table-column prop="equipmentName" label="设备名称" min-width="150" /><el-table-column prop="equipmentTypeName" label="设备类型" min-width="120" /><el-table-column prop="equipmentLocation" label="安装位置" min-width="180" show-overflow-tooltip />
|
|
|
- <el-table-column v-if="view !== 'maintain'" label="设备状态" width="100"><template #default="{ row }"><el-tag :type="Number(row.alarmStatus) === 1 ? 'danger' : 'success'">{{ row.deviceStatusText }}</el-tag></template></el-table-column>
|
|
|
+ <el-table-column v-if="view !== 'maintain'" label="设备状态" width="100"><template #default="{ row }"><el-tag :type="Number(row.currentStatus) === 3 ? 'danger' : 'success'">{{ row.currentStatusText }}</el-tag></template></el-table-column>
|
|
|
+ <el-table-column v-if="view !== 'maintain'" label="在线状态" width="100"><template #default="{ row }"><el-tag :type="Number(row.onlineStatus) === 1 ? 'success' : 'info'">{{ row.onlineStatusText }}</el-tag></template></el-table-column>
|
|
|
+ <el-table-column v-if="view !== 'maintain'" label="报警状态" width="100"><template #default="{ row }"><el-tag :type="Number(row.alarmStatus) === 1 ? 'danger' : 'success'">{{ row.alarmStatusText }}</el-tag></template></el-table-column>
|
|
|
<el-table-column v-if="view !== 'maintain'" label="报警等级" width="110"><template #default="{ row }"><el-tag :type="alarmLevelType(row.alertLevel)">{{ row.alarmLevelText }}</el-tag></template></el-table-column>
|
|
|
- <el-table-column label="关联维修单" min-width="190" show-overflow-tooltip><template #default="{ row }">{{ view === 'maintain' ? (row.orderNo || '-') : row.relatedOrderNo }}</template></el-table-column>
|
|
|
- <el-table-column label="维修状态" min-width="110"><template #default="{ row }">{{ view === 'maintain' ? (row.status || '暂无') : row.workOrderStatusText }}</template></el-table-column>
|
|
|
- <el-table-column label="操作" width="190" fixed="right"><template #default="{ row }"><el-button link type="primary" @click="selectPoint(row)">详情</el-button><el-button v-if="view === 'dispatch'" link type="warning" @click="openOrder(row)">维修派单</el-button><el-button v-if="view === 'maintain'" link type="danger" @click="removeRecord(row)">删除</el-button></template></el-table-column>
|
|
|
+ <el-table-column v-if="view === 'abnormal' || view === 'dispatch'" label="异常原因" min-width="150" show-overflow-tooltip><template #default="{ row }">{{ row.abnormalReasonText || '-' }}</template></el-table-column>
|
|
|
+ <el-table-column label="关联工单" min-width="190" show-overflow-tooltip><template #default="{ row }">{{ view === 'maintain' ? (row.orderNo || '-') : row.relatedOrderNo }}</template></el-table-column>
|
|
|
+ <el-table-column label="工单状态" min-width="110"><template #default="{ row }"><el-tag v-if="view !== 'maintain' && row.workOrderStatusText !== '暂无工单'" :type="workOrderStatusType(row.workOrderStatusCode)">{{ row.workOrderStatusText }}</el-tag><span v-else>{{ view === 'maintain' ? (row.status || '暂无') : row.workOrderStatusText }}</span></template></el-table-column>
|
|
|
+ <el-table-column v-if="view === 'abnormal' || view === 'dispatch'" label="接单责任人" min-width="110"><template #default="{ row }">{{ view === 'maintain' ? (row.maintainPerson || '-') : (row.relatedWorkOrderPerson || '-') }}</template></el-table-column>
|
|
|
+ <el-table-column label="操作" width="190" fixed="right"><template #default="{ row }"><el-button link type="primary" @click="selectPoint(row)">详情</el-button><el-button v-if="canDispatch(row)" link type="warning" @click="openOrder(row)">维修派单</el-button><el-button v-if="view === 'maintain'" link type="danger" @click="removeRecord(row)">删除</el-button></template></el-table-column>
|
|
|
</el-table>
|
|
|
<el-pagination v-model:current-page="query.pageNum" v-model:page-size="query.pageSize" :total="page.total" layout="total, sizes, prev, pager, next" :page-sizes="[10, 20, 50]" @change="loadData" />
|
|
|
</el-card>
|
|
|
|
|
|
<el-drawer v-model="detailVisible" class="detail-drawer device-detail-drawer" title="设备详情" direction="rtl" size="680px" append-to-body>
|
|
|
- <div class="detail-summary"><span class="detail-name">{{ detail.equipmentName || '-' }}</span><el-tag :type="Number(detail.alarmStatus) === 1 ? 'danger' : 'success'">{{ detail.deviceStatusText || '-' }}</el-tag></div>
|
|
|
+ <div class="detail-summary"><span class="detail-name">{{ detail.equipmentName || '-' }}</span><el-tag :type="Number(detail.currentStatus) === 3 ? 'danger' : 'success'">{{ detail.currentStatusText || '-' }}</el-tag><el-tag :type="Number(detail.alarmStatus) === 1 ? 'danger' : 'success'">{{ detail.alarmStatusText || '-' }}</el-tag><el-tag v-if="detail.workOrderStatusText && detail.workOrderStatusText !== '暂无工单'" :type="workOrderStatusType(detail.workOrderStatusCode)">{{ detail.workOrderStatusText }}</el-tag></div>
|
|
|
<el-descriptions :column="2" border>
|
|
|
<el-descriptions-item v-for="item in detailFields" :key="item.label" :label="item.label">{{ item.value }}</el-descriptions-item>
|
|
|
</el-descriptions>
|
|
|
@@ -47,25 +53,42 @@ import { computed, onMounted, ref } from 'vue'
|
|
|
import { ElMessage } from 'element-plus'
|
|
|
import { Monitor, Refresh } from '@element-plus/icons-vue'
|
|
|
import { listUser } from '@/api/system/user'
|
|
|
-import { createAbnormalOrder, exportAbnormalDevices, exportDeviceLedger, listAbnormalDevices, listDeviceLedger, listMaintainRecords, deleteMaintainRecord } from '@/api/pipeNetwork/waterSupply'
|
|
|
-import { normalizePage } from '@/utils/waterSupplyModel'
|
|
|
-import { buildMaintainOrderPayload, normalizeDeviceRow } from '@/utils/waterSupplyUiModel'
|
|
|
+import { createAbnormalOrder, exportAbnormalDevices, exportDeviceLedger, listAbnormalDevices, listDeviceLedger, listDeviceGisPoints, listMaintainRecords, deleteMaintainRecord } from '@/api/pipeNetwork/waterSupply'
|
|
|
+import { normalizePage, readMonitoringExportError } from '@/utils/waterSupplyModel'
|
|
|
+import { buildMaintainOrderPayload, normalizeDeviceRow, canDispatchDevice, normalizeDeviceGisPoints, preserveDevicePageOnError } from '@/utils/waterSupplyUiModel'
|
|
|
+import { saveAs } from 'file-saver'
|
|
|
|
|
|
const props = defineProps({ title: { type: String, required: true }, subtitle: { type: String, default: '设备信息、运行状态与维护过程管理' }, view: { type: String, default: 'ledger' } })
|
|
|
const { title, subtitle, view } = props
|
|
|
const query = ref({ pageNum: 1, pageSize: 10, equipmentName: '', equipmentCode: '', alarmStatus: undefined, alertLevel: undefined })
|
|
|
-const page = ref({ records: [], total: 0 }); const loading = ref(false); const detailVisible = ref(false); const detail = ref({}); const dispatchVisible = ref(false); const dispatching = ref(false); const dispatchDevice = ref({}); const dispatchForm = ref({ description: '', receiveUserId: undefined }); const users = ref([]); const userLoading = ref(false)
|
|
|
+const page = ref({ records: [], total: 0 }); const loading = ref(false); const loadError = ref(''); const detailVisible = ref(false); const detail = ref({}); const dispatchVisible = ref(false); const dispatching = ref(false); const dispatchDevice = ref({}); const dispatchForm = ref({ description: '', receiveUserId: undefined }); const users = ref([]); const userLoading = ref(false)
|
|
|
const levels = [{ label: '一级', value: 1 }, { label: '二级', value: 2 }, { label: '三级', value: 3 }, { label: '四级', value: 4 }]; const pageIcon = Monitor; const alarmLevelType = level => ({ 1: 'danger', 2: 'warning', 3: 'primary', 4: 'success' }[Number(level)] || 'info')
|
|
|
-const detailFields = computed(() => [['设备编码', detail.value.equipmentCode], ['设备类型', detail.value.equipmentTypeName || detail.value.typeName], ['安装位置', detail.value.equipmentLocation], ['设备状态', detail.value.deviceStatusText], ['报警等级', detail.value.alarmLevelText], ['在线状态', Number(detail.value.onlineStatus) === 1 ? '在线' : '离线'], ['关联维修单', detail.value.relatedOrderNo || detail.value.orderNo], ['维修状态', detail.value.workOrderStatusText || detail.value.status], ['状态更新时间', detail.value.statusUpdateTime]].map(([label, value]) => ({ label, value: value ?? '-' })))
|
|
|
+function canDispatch(row) {
|
|
|
+ if (view !== 'dispatch' && view !== 'abnormal') return false
|
|
|
+ return canDispatchDevice(row)
|
|
|
+}
|
|
|
+function workOrderStatusType(code) { return ({ 1: 'info', 2: 'warning', 3: 'primary', 4: 'warning', 5: 'danger', 6: 'success', 7: 'info', 8: 'info' })[Number(code)] || 'info' }
|
|
|
+const detailFields = computed(() => [['设备编码', detail.value.equipmentCode], ['设备类型', detail.value.equipmentTypeName || detail.value.typeName], ['安装位置', detail.value.equipmentLocation], ['设备状态', detail.value.currentStatusText], ['在线状态', detail.value.onlineStatusText], ['报警状态', detail.value.alarmStatusText], ['报警等级', detail.value.alarmLevelText], ['异常原因', detail.value.abnormalReasonText], ['关联工单', detail.value.relatedOrderNo || detail.value.orderNo], ['工单状态', detail.value.workOrderStatusText || detail.value.status], ['接单责任人', detail.value.relatedWorkOrderPerson || detail.value.maintainPerson], ['状态更新时间', detail.value.statusUpdateTime]].map(([label, value]) => ({ label, value: value ?? '-' })))
|
|
|
|
|
|
-async function loadData() { loading.value = true; try { let response; if (view === 'maintain') response = await listMaintainRecords({ ...query.value }); else if (view === 'dispatch' || view === 'abnormal') response = await listAbnormalDevices({ ...query.value }); else response = await listDeviceLedger({ ...query.value }); const normalized = normalizePage(response); page.value = { ...normalized, records: normalized.records.map(normalizeDeviceRow) } } catch (error) { page.value = { records: [], total: 0 }; console.warn(`[${title}] 数据加载失败`, error) } finally { loading.value = false } }
|
|
|
+async function loadData() { loading.value = true; loadError.value = ''; try { if (view === 'gis') { const response = await listDeviceGisPoints({ ...query.value }); const records = normalizeDeviceGisPoints(response).map(normalizeDeviceRow); page.value = { records, total: records.length, current: 1, size: records.length || 10 }; return } let response; if (view === 'maintain') response = await listMaintainRecords({ ...query.value }); else if (view === 'dispatch' || view === 'abnormal') response = await listAbnormalDevices({ ...query.value }); else response = await listDeviceLedger({ ...query.value }); const normalized = normalizePage(response); page.value = { ...normalized, records: normalized.records.map(normalizeDeviceRow) } } catch (error) { const retained = preserveDevicePageOnError(page.value); page.value = retained.page; loadError.value = retained.error; console.warn(`[${title}] 数据加载失败`, error) } finally { loading.value = false } }
|
|
|
function reset() { query.value = { pageNum: 1, pageSize: 10, equipmentName: '', equipmentCode: '', alarmStatus: undefined, alertLevel: undefined }; loadData() }
|
|
|
function selectPoint(row) { detail.value = normalizeDeviceRow(row); detailVisible.value = true }
|
|
|
async function loadUsers() { if (users.value.length) return; userLoading.value = true; try { const response = await listUser({ pageNum: 1, pageSize: 200 }); users.value = response.rows || response.data?.rows || [] } catch (error) { ElMessage.error('责任人列表加载失败') } finally { userLoading.value = false } }
|
|
|
-async function openOrder(row) { dispatchDevice.value = row; dispatchForm.value = { description: row.abnormalDescription || row.description || '', receiveUserId: undefined }; await loadUsers(); dispatchVisible.value = true }
|
|
|
-async function submitDispatch() { if (!dispatchForm.value.description?.trim()) return ElMessage.warning('请填写问题描述'); if (!dispatchForm.value.receiveUserId) return ElMessage.warning('请选择接单责任人'); dispatching.value = true; try { await createAbnormalOrder(buildMaintainOrderPayload(dispatchDevice.value, dispatchForm.value)); ElMessage.success('维修派单已提交'); dispatchVisible.value = false; await loadData() } catch (error) { ElMessage.error('派单失败,请检查权限或服务状态') } finally { dispatching.value = false } }
|
|
|
+async function openOrder(row) { dispatchDevice.value = row; dispatchForm.value = { description: row.abnormalReason || row.abnormalReasonText || row.description || '', receiveUserId: undefined }; await loadUsers(); dispatchVisible.value = true }
|
|
|
+async function submitDispatch() { if (!dispatchForm.value.description?.trim()) return ElMessage.warning('请填写问题描述'); if (!dispatchForm.value.receiveUserId) return ElMessage.warning('请选择接单责任人'); dispatching.value = true; try { const response = await createAbnormalOrder(buildMaintainOrderPayload(dispatchDevice.value, dispatchForm.value)); const summary = response?.data?.data || response?.data || response || {}; const orderNo = summary.orderNo || summary.orderId; ElMessage.success(orderNo ? `已派单,等待接单(${orderNo})` : '已派单,等待接单'); dispatchVisible.value = false; await loadData() } catch (error) { ElMessage.error(error?.response?.data?.msg || '派单失败,请检查权限或服务状态') } finally { dispatching.value = false } }
|
|
|
async function removeRecord(row) { try { await deleteMaintainRecord(row.maintainId || row.id); ElMessage.success('记录已删除'); await loadData() } catch (error) { ElMessage.error('删除失败') } }
|
|
|
-async function exportData() { try { await (view === 'dispatch' || view === 'abnormal' ? exportAbnormalDevices : exportDeviceLedger)({ ...query.value }); ElMessage.success('导出请求已提交') } catch (error) { ElMessage.error('导出失败') } }
|
|
|
+async function exportData() {
|
|
|
+ try {
|
|
|
+ const response = await (view === 'dispatch' || view === 'abnormal' ? exportAbnormalDevices : exportDeviceLedger)({ ...query.value })
|
|
|
+ const errorMessage = await readMonitoringExportError(response)
|
|
|
+ if (errorMessage) throw new Error(errorMessage)
|
|
|
+ const blob = response instanceof Blob ? response : new Blob([response], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' })
|
|
|
+ saveAs(blob, `${title}_${new Date().toISOString().slice(0, 10)}.xlsx`)
|
|
|
+ ElMessage.success('导出成功')
|
|
|
+ } catch (error) {
|
|
|
+ ElMessage.error(error?.message || '导出失败,请稍后重试')
|
|
|
+ }
|
|
|
+}
|
|
|
onMounted(loadData)
|
|
|
</script>
|
|
|
|