<template>
|
<div class="app-container">
|
<el-tabs v-model="activeTab">
|
<el-tab-pane label="设备台账" name="ledger" />
|
<el-tab-pane label="远程控制" name="control" />
|
<el-tab-pane label="异常报警" name="alarm">
|
<template #label>
|
<span>异常报警<el-badge v-if="unhandledCount > 0" :value="unhandledCount" style="margin-left: 6px" /></span>
|
</template>
|
</el-tab-pane>
|
</el-tabs>
|
|
<!-- 远程控制 -->
|
<div v-if="activeTab === 'ledger'">
|
<LedgerPage />
|
</div>
|
|
<div v-else-if="activeTab === 'control'">
|
<div class="section-title">设备列表(远程启停)</div>
|
<el-table :data="deviceList" border v-loading="deviceLoading" height="300">
|
<el-table-column align="center" label="序号" type="index" width="60" />
|
<el-table-column label="设备名称" prop="deviceName" show-overflow-tooltip />
|
<el-table-column label="规格型号" prop="deviceModel" show-overflow-tooltip />
|
<el-table-column label="单位" prop="unit" width="80" />
|
<el-table-column fixed="right" label="远程控制" width="180" align="center">
|
<template #default="scope">
|
<el-button link type="success" size="small" @click="handleSend(scope.row, 'start')">启动</el-button>
|
<el-button link type="danger" size="small" @click="handleSend(scope.row, 'stop')">停止</el-button>
|
</template>
|
</el-table-column>
|
</el-table>
|
|
<div class="section-title" style="margin-top: 16px">指令记录</div>
|
<el-table :data="commandList" border v-loading="commandLoading" height="300">
|
<el-table-column align="center" label="序号" type="index" width="60" />
|
<el-table-column label="设备名称" prop="deviceName" show-overflow-tooltip />
|
<el-table-column label="指令" prop="commandType" width="90" align="center">
|
<template #default="scope">
|
<el-tag :type="scope.row.commandType === 'start' ? 'success' : 'danger'">
|
{{ scope.row.commandType === 'start' ? '启动' : '停止' }}
|
</el-tag>
|
</template>
|
</el-table-column>
|
<el-table-column label="状态" prop="commandStatus" width="100" align="center">
|
<template #default="scope">
|
<el-tag :type="scope.row.commandStatus === 'success' ? 'success' : (scope.row.commandStatus === 'failed' ? 'danger' : 'info')">
|
{{ scope.row.commandStatus === 'success' ? '成功' : (scope.row.commandStatus === 'failed' ? '失败' : '下发中') }}
|
</el-tag>
|
</template>
|
</el-table-column>
|
<el-table-column label="操作人" prop="operator" width="110" />
|
<el-table-column label="下发时间" prop="commandTime" width="170" />
|
<el-table-column label="执行结果" prop="resultMsg" show-overflow-tooltip />
|
</el-table>
|
<pagination v-show="commandPage.total > 0" :total="commandPage.total" layout="total, prev, pager, next"
|
:page="commandPage.current" :limit="commandPage.size" @pagination="commandPageChange" />
|
</div>
|
|
<!-- 异常报警 -->
|
<div v-else>
|
<el-alert type="info" :closable="false" show-icon style="margin-bottom: 10px"
|
title="系统每 60 秒自动检查一次新报警,发现未处理报警会弹窗提醒(站内推送);报警来源为「设备台账 → 设备故障」登记的故障记录,故障未消除即视为未处理报警" />
|
<el-table :data="alarmList" border v-loading="alarmLoading" height="calc(100vh - 16em)">
|
<el-table-column align="center" label="序号" type="index" width="60" />
|
<el-table-column label="设备名称" prop="deviceName" show-overflow-tooltip width="220">
|
<template #default="scope">{{ scope.row.deviceName || '-' }}</template>
|
</el-table-column>
|
<el-table-column label="故障描述" prop="defectDescription" show-overflow-tooltip />
|
<el-table-column label="设备状态" prop="status" width="120" />
|
<el-table-column label="是否处理" width="110" align="center">
|
<template #default="scope">
|
<el-tag :type="scope.row.handled ? 'success' : 'danger'">{{ scope.row.handled ? '已消除' : '未处理' }}</el-tag>
|
</template>
|
</el-table-column>
|
<el-table-column label="发生时间" prop="createTime" width="170" />
|
<el-table-column label="消除时间" prop="eliminateTime" width="170" />
|
</el-table>
|
</div>
|
</div>
|
</template>
|
|
<script setup>
|
import { ref, onMounted, onUnmounted, computed } from "vue";
|
import { ElNotification, ElMessageBox, ElMessage } from "element-plus";
|
import pagination from "@/components/PIMTable/Pagination.vue";
|
import LedgerPage from "@/views/equipmentManagement/ledger/index.vue";
|
import { getDeviceList, getAlarmList, getCommandPage, sendCommand } from "@/api/environmentAccess/deviceCommand.js";
|
|
defineOptions({ name: "设备远程监控" });
|
|
const activeTab = ref("ledger");
|
const deviceList = ref([]);
|
const deviceLoading = ref(false);
|
const commandList = ref([]);
|
const commandLoading = ref(false);
|
const commandPage = ref({ current: 1, size: 10, total: 0 });
|
const alarmList = ref([]);
|
const alarmLoading = ref(false);
|
|
const unhandledCount = computed(() => alarmList.value.filter((a) => !a.handled).length);
|
|
/* ---------- 远程控制 ---------- */
|
const loadDevices = () => {
|
deviceLoading.value = true;
|
getDeviceList().then((res) => {
|
deviceList.value = res.data || [];
|
}).finally(() => { deviceLoading.value = false; });
|
};
|
|
const loadCommands = () => {
|
commandLoading.value = true;
|
getCommandPage({ current: commandPage.value.current, size: commandPage.value.size }).then((res) => {
|
commandList.value = (res.data && res.data.records) || [];
|
commandPage.value.total = (res.data && res.data.total) || 0;
|
}).finally(() => { commandLoading.value = false; });
|
};
|
|
const commandPageChange = (obj) => {
|
commandPage.value.current = obj.page;
|
commandPage.value.size = obj.limit;
|
loadCommands();
|
};
|
|
const handleSend = (row, type) => {
|
const label = type === "start" ? "启动" : "停止";
|
ElMessageBox.confirm(`确认对「${row.deviceName || '该设备'}」下发${label}指令?`, "远程控制", { type: "warning" })
|
.then(() => {
|
sendCommand({ deviceLedgerId: row.id, deviceName: row.deviceName, commandType: type }).then((res) => {
|
ElMessage.success(res.msg || `${label}指令已下发`);
|
commandPage.value.current = 1;
|
loadCommands();
|
});
|
})
|
.catch(() => {});
|
};
|
|
/* ---------- 异常报警(含站内弹窗提醒) ---------- */
|
let alarmTimer = null;
|
let lastMaxAlarmId = null;
|
|
const loadAlarms = (notify) => {
|
alarmLoading.value = true;
|
return getAlarmList().then((res) => {
|
const list = res.data || [];
|
alarmList.value = list;
|
const maxId = list.reduce((m, a) => Math.max(m, Number(a.id) || 0), 0);
|
if (notify && lastMaxAlarmId !== null && maxId > lastMaxAlarmId) {
|
const fresh = list.filter((a) => Number(a.id) > lastMaxAlarmId && !a.handled);
|
fresh.slice(0, 3).forEach((a) => {
|
ElNotification({
|
title: "设备异常报警",
|
message: `【${a.deviceName || '未知设备'}】${a.defectDescription || '发生设备故障'},请及时处理`,
|
type: "error",
|
duration: 15000,
|
position: "bottom-right",
|
});
|
});
|
}
|
lastMaxAlarmId = maxId;
|
}).finally(() => { alarmLoading.value = false; });
|
};
|
|
const startAlarmPolling = () => {
|
loadAlarms(false);
|
alarmTimer = setInterval(() => loadAlarms(true), 60000);
|
};
|
|
onMounted(() => {
|
loadDevices();
|
loadCommands();
|
startAlarmPolling();
|
});
|
|
onUnmounted(() => {
|
if (alarmTimer) {
|
clearInterval(alarmTimer);
|
alarmTimer = null;
|
}
|
});
|
</script>
|
|
<style scoped lang="scss">
|
.section-title {
|
font-size: 14px;
|
font-weight: 600;
|
color: #303133;
|
margin-bottom: 8px;
|
}
|
</style>
|