| src/api/alarmManagement/alarmAnalysis.js | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/api/alarmManagement/alarmOptimization.js | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/api/alarmManagement/dataCollection.js | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/alarmManagement/alarmAnalysis/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/alarmManagement/alarmOptimization/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/alarmManagement/dataCollection/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
src/api/alarmManagement/alarmAnalysis.js
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,77 @@ import request from '@/utils/request'; // ==================== æ¥è¦åæè¯ä¼°æ¨¡å API ==================== /** * 宿¶æ¥è¦ç»è®¡ */ export function getRealtimeAlarmStats() { return request({ url: '/alarm/analysis/realtime/stats', method: 'get' }); } /** * 宿¶æ¥è¦å表 */ export function listRealtimeAlarms(query) { return request({ url: '/alarm/analysis/realtime/list', method: 'get', params: query }); } /** * 确认æ¥è¦ */ export function confirmAlarm(alarmId) { return request({ url: '/alarm/analysis/confirm/' + alarmId, method: 'post' }); } /** * åææ¥è¦ */ export function analyzeAlarm(alarmId) { return request({ url: '/alarm/analysis/analyze/' + alarmId, method: 'get' }); } /** * æ¥è¦è¶å¿æ°æ® */ export function getAlarmTrend(query) { return request({ url: '/alarm/analysis/trend', method: 'get', params: query }); } /** * æ¥è¦ç±»ååå¸ */ export function getAlarmTypeDistribution(query) { return request({ url: '/alarm/analysis/type/distribution', method: 'get', params: query }); } /** * æ éè¯æå表 */ export function getFaultDiagnosisList(query) { return request({ url: '/alarm/analysis/fault/list', method: 'get', params: query }); } src/api/alarmManagement/alarmOptimization.js
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,141 @@ import request from '@/utils/request'; // ==================== æ¥è¦ä¼åç®¡çæ¨¡å API ==================== /** * ä¼åææç»è®¡ */ export function getOptimizationStatistics() { return request({ url: '/alarm/optimization/statistics', method: 'get' }); } /** * æ»æ°æ¥è¦çç¥å表 */ export function listNuisanceStrategies(query) { return request({ url: '/alarm/optimization/strategy/list', method: 'get', params: query }); } /** * æ°å¢æ»æ°æ¥è¦çç¥ */ export function addNuisanceStrategy(data) { return request({ url: '/alarm/optimization/strategy', method: 'post', data: data }); } /** * ä¿®æ¹æ»æ°æ¥è¦çç¥ */ export function updateNuisanceStrategy(data) { return request({ url: '/alarm/optimization/strategy', method: 'put', data: data }); } /** * å 餿»æ°æ¥è¦çç¥ */ export function delNuisanceStrategy(strategyId) { return request({ url: '/alarm/optimization/strategy/' + strategyId, method: 'delete' }); } /** * ä¿®æ¹çç¥ç¶æ */ export function changeStrategyStatus(strategyId, status) { return request({ url: '/alarm/optimization/strategy/changeStatus', method: 'put', data: { strategyId, status } }); } /** * æ²»çååå¯¹æ¯æ°æ® */ export function getOptimizationCompareData(query) { return request({ url: '/alarm/optimization/compare', method: 'get', params: query }); } /** * é«é¢æ¥è¦ç¹ä½å表 */ export function listHighFreqAlarms(query) { return request({ url: '/alarm/optimization/highfreq/list', method: 'get', params: query }); } /** * æ¥è¦åé¤å®¡æ¹å表 */ export function listRemoveApprovals(query) { return request({ url: '/alarm/optimization/approval/list', method: 'get', params: query }); } /** * æäº¤åé¤ç³è¯· */ export function submitRemoveApply(data) { return request({ url: '/alarm/optimization/approval', method: 'post', data: data }); } /** * 审æ¹éè¿ */ export function approveRemoveApply(applyNo) { return request({ url: '/alarm/optimization/approval/approve/' + applyNo, method: 'post' }); } /** * 审æ¹é©³å */ export function rejectRemoveApply(applyNo) { return request({ url: '/alarm/optimization/approval/reject/' + applyNo, method: 'post' }); } /** * æ¥è¦ç¹ä½é项 */ export function listAlarmPointOptions() { return request({ url: '/alarm/optimization/point/options', method: 'get' }); } src/api/alarmManagement/dataCollection.js
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,163 @@ import request from '@/utils/request'; // ==================== æ°æ®ééä¸è§£ææ¨¡å API ==================== /** * ééç»è®¡æ¦è§ */ export function getCollectionStatistics() { return request({ url: '/alarm/collection/statistics', method: 'get' }); } /** * æ¥è¦ç¹ä½å°è´¦å表 */ export function listAlarmPointLedger(query) { return request({ url: '/alarm/point/ledger/list', method: 'get', params: query }); } /** * æ°å¢æ¥è¦ç¹ä½ */ export function addAlarmPoint(data) { return request({ url: '/alarm/point/ledger', method: 'post', data: data }); } /** * ä¿®æ¹æ¥è¦ç¹ä½ */ export function updateAlarmPoint(data) { return request({ url: '/alarm/point/ledger', method: 'put', data: data }); } /** * å 餿¥è¦ç¹ä½ */ export function delAlarmPoint(pointId) { return request({ url: '/alarm/point/ledger/' + pointId, method: 'delete' }); } /** * ä¿®æ¹ç¹ä½ç¶æ */ export function changePointStatus(pointId, status) { return request({ url: '/alarm/point/ledger/changeStatus', method: 'put', data: { pointId, status } }); } /** * 导åºå°è´¦æ°æ® */ export function exportPointLedger(query) { return request({ url: '/alarm/point/ledger/export', method: 'get', params: query, responseType: 'blob' }); } /** * æ°æ®é鿥å£å表 */ export function listDataInterface(query) { return request({ url: '/alarm/collection/interface/list', method: 'get', params: query }); } /** * å¯å¨æ°æ®éé */ export function startDataCollection(interfaceId) { return request({ url: '/alarm/collection/interface/start/' + interfaceId, method: 'post' }); } /** * åæ¢æ°æ®éé */ export function stopDataCollection(interfaceId) { return request({ url: '/alarm/collection/interface/stop/' + interfaceId, method: 'post' }); } /** * æ°å¢æ°æ®ééæ¥å£ */ export function addDataInterface(data) { return request({ url: '/alarm/collection/interface', method: 'post', data: data }); } /** * ä¿®æ¹æ°æ®ééæ¥å£ */ export function updateDataInterface(data) { return request({ url: '/alarm/collection/interface', method: 'post', data: data }); } /** * å 餿°æ®ééæ¥å£ */ export function delDataInterface(interfaceId) { return request({ url: '/alarm/collection/interface/' + interfaceId, method: 'delete' }); } /** * ä¿®æ¹æ¥å£ç¶æ */ export function changeInterfaceStatus(interfaceId, status) { return request({ url: '/alarm/collection/interface/changeStatus', method: 'put', data: { interfaceId, status } }); } /** * è·åæ°æ®é鿥å£è¯¦æ */ export function getDataInterfaceDetail(interfaceId) { return request({ url: '/alarm/collection/interface/' + interfaceId, method: 'get' }); } src/views/alarmManagement/alarmAnalysis/index.vue
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,374 @@ <template> <div class="app-container"> <!-- 宿¶æ¥è¦ç¶æ --> <el-row :gutter="20" class="stat-row"> <el-col :span="6"> <el-card class="status-card danger"> <div class="status-title">ç´§æ¥æ¥è¦</div> <div class="status-value">{{ alarmStats.urgent }}</div> </el-card> </el-col> <el-col :span="6"> <el-card class="status-card warning"> <div class="status-title">éè¦æ¥è¦</div> <div class="status-value">{{ alarmStats.important }}</div> </el-card> </el-col> <el-col :span="6"> <el-card class="status-card info"> <div class="status-title">ä¸è¬æ¥è¦</div> <div class="status-value">{{ alarmStats.normal }}</div> </el-card> </el-col> <el-col :span="6"> <el-card class="status-card success"> <div class="status-title">仿¥ç´¯è®¡</div> <div class="status-value">{{ alarmStats.total }}</div> </el-card> </el-col> </el-row> <!-- 宿¶æ¥è¦çæµ --> <el-card class="box-card"> <template #header> <div class="card-header"> <span>宿¶æ¥è¦çæµ</span> <el-radio-group v-model="refreshInterval" size="small"> <el-radio-button :label="5">5ç§å·æ°</el-radio-button> <el-radio-button :label="10">10ç§å·æ°</el-radio-button> <el-radio-button :label="30">30ç§å·æ°</el-radio-button> </el-radio-group> </div> </template> <el-table :data="realtimeAlarms" v-loading="loading" border stripe> <el-table-column prop="alarmTime" label="æ¥è¦æ¶é´" width="160" align="center" /> <el-table-column prop="alarmLevel" label="级å«" width="80" align="center"> <template #default="{ row }"> <el-tag :type="row.alarmLevel === 'ç´§æ¥' ? 'danger' : row.alarmLevel === 'éè¦' ? 'warning' : 'info'" size="small"> {{ row.alarmLevel }} </el-tag> </template> </el-table-column> <el-table-column prop="pointName" label="æ¥è¦ç¹ä½" min-width="180" /> <el-table-column prop="alarmType" label="æ¥è¦ç±»å" width="120" align="center" /> <el-table-column prop="alarmValue" label="æ¥è¦å¼" width="100" align="center" /> <el-table-column prop="thresholdValue" label="éå¼" width="100" align="center" /> <el-table-column prop="area" label="æå±åºå" width="120" align="center" /> <el-table-column prop="status" label="ç¶æ" width="100" align="center"> <template #default="{ row }"> <el-tag :type="row.status === 'æªç¡®è®¤' ? 'danger' : 'success'" size="small"> {{ row.status }} </el-tag> </template> </el-table-column> <el-table-column label="æä½" width="150" align="center" fixed="right"> <template #default="{ row }"> <el-button type="primary" link size="small" @click="handleConfirm(row)">确认</el-button> <el-button type="warning" link size="small" @click="handleAnalyze(row)">åæ</el-button> </template> </el-table-column> </el-table> <pagination v-show="alarmTotal > 0" :total="alarmTotal" v-model:page="alarmQuery.pageNum" v-model:limit="alarmQuery.pageSize" @pagination="getRealtimeAlarms" /> </el-card> <!-- æ¥è¦åæä¸æ éè¯æ --> <el-row :gutter="20" style="margin-top: 20px;"> <el-col :span="12"> <el-card class="box-card"> <template #header> <span>æ¥è¦è¶å¿åæ</span> </template> <Echarts :xAxis="trendXAxis" :yAxis="trendYAxis" :grid="trendGrid" :series="trendSeries" :legend="trendLegend" :tooltip="trendTooltip" :chartStyle="{ height: '300px', width: '100%' }" /> </el-card> </el-col> <el-col :span="12"> <el-card class="box-card"> <template #header> <span>æ¥è¦ç±»ååå¸</span> </template> <Echarts :series="typeSeries" :legend="typeLegend" :tooltip="typeTooltip" :chartStyle="{ height: '300px', width: '100%' }" /> </el-card> </el-col> </el-row> <!-- æ éè¯æä¸å¤ç½®æå¯¼ --> <el-card class="box-card" style="margin-top: 20px;"> <template #header> <div class="card-header"> <span>æ éè¯æä¸å¤ç½®æå¯¼</span> <el-button type="primary" size="small" icon="Search" @click="handleFaultDiagnosis">æºè½è¯æ</el-button> </div> </template> <el-table :data="faultList" border> <el-table-column type="index" label="åºå·" width="60" align="center" /> <el-table-column prop="faultType" label="æ éç±»å" width="150" align="center"> <template #default="{ row }"> <el-tag type="danger" size="small">{{ row.faultType }}</el-tag> </template> </el-table-column> <el-table-column prop="alarmPoint" label="å ³èæ¥è¦ç¹ä½" min-width="180" /> <el-table-column prop="occurrenceCount" label="åçæ¬¡æ°" width="100" align="center" /> <el-table-column prop="faultReason" label="å¯è½åå " min-width="200" /> <el-table-column prop="solution" label="å¤ç½®å»ºè®®" min-width="250" /> <el-table-column label="æä½" width="100" align="center"> <template #default="{ row }"> <el-button type="primary" link size="small" @click="viewDetail(row)">详æ </el-button> </template> </el-table-column> </el-table> </el-card> <!-- æ¥è¦åæå¼¹çª --> <el-dialog title="æ¥è¦è¯¦æ åæ" v-model="analyzeVisible" width="700px" append-to-body> <el-descriptions :column="2" border> <el-descriptions-item label="æ¥è¦ç¹ä½">{{ currentAlarm.pointName }}</el-descriptions-item> <el-descriptions-item label="æ¥è¦æ¶é´">{{ currentAlarm.alarmTime }}</el-descriptions-item> <el-descriptions-item label="æ¥è¦çº§å«"> <el-tag :type="currentAlarm.alarmLevel === 'ç´§æ¥' ? 'danger' : currentAlarm.alarmLevel === 'éè¦' ? 'warning' : 'info'"> {{ currentAlarm.alarmLevel }} </el-tag> </el-descriptions-item> <el-descriptions-item label="æ¥è¦ç±»å">{{ currentAlarm.alarmType }}</el-descriptions-item> <el-descriptions-item label="æ¥è¦å¼">{{ currentAlarm.alarmValue }}</el-descriptions-item> <el-descriptions-item label="æ¥è¦éå¼">{{ currentAlarm.thresholdValue }}</el-descriptions-item> </el-descriptions> <div class="analysis-section"> <h4>æ éåæ</h4> <el-alert :title="analysisResult.faultType" type="error" :description="analysisResult.faultReason" show-icon /> </div> <div class="analysis-section"> <h4>å¤ç½®æå¯¼</h4> <el-steps direction="vertical" :active="1"> <el-step v-for="(step, index) in analysisResult.steps" :key="index" :title="step.title" :description="step.desc" /> </el-steps> </div> <template #footer> <el-button @click="analyzeVisible = false">å ³é</el-button> <el-button type="primary" @click="handleConfirm(currentAlarm)">确认æ¥è¦</el-button> </template> </el-dialog> </div> </template> <script setup> import { ref, reactive, onMounted, onUnmounted } from 'vue'; import { ElMessage } from 'element-plus'; import Echarts from '@/components/Echarts/echarts.vue'; import Pagination from '@/components/Pagination/index.vue'; import { getRealtimeAlarmStats, listRealtimeAlarms, confirmAlarm, analyzeAlarm, getAlarmTrend, getAlarmTypeDistribution, getFaultDiagnosisList } from '@/api/alarmManagement/alarmAnalysis'; // æ¥è¦ç»è®¡ const alarmStats = reactive({ urgent: 0, important: 0, normal: 0, total: 0 }); // 宿¶æ¥è¦å表 const loading = ref(false); const realtimeAlarms = ref([]); const alarmTotal = ref(0); const alarmQuery = reactive({ pageNum: 1, pageSize: 10 }); // å·æ°é´é const refreshInterval = ref(10); let refreshTimer = null; // æ éå表 const faultList = ref([]); // åæå¼¹çª const analyzeVisible = ref(false); const currentAlarm = ref({}); const analysisResult = reactive({ faultType: '', faultReason: '', steps: [] }); // å¾è¡¨é ç½® const trendXAxis = ref([{ type: 'category', data: [] }]) const trendYAxis = ref([{ type: 'value' }]) const trendGrid = reactive({ left: '3%', right: '4%', bottom: '3%', containLabel: true }) const trendSeries = ref([ { name: 'ç´§æ¥', type: 'line', data: [] }, { name: 'éè¦', type: 'line', data: [] }, { name: 'ä¸è¬', type: 'line', data: [] }, ]) const trendLegend = reactive({ data: ['ç´§æ¥', 'éè¦', 'ä¸è¬'] }) const trendTooltip = reactive({ trigger: 'axis' }) const typeSeries = ref([{ type: 'pie', radius: '50%', data: [] }]) const typeLegend = reactive({ orient: 'vertical', left: 'left' }) const typeTooltip = reactive({ trigger: 'item' }) // è·åæ¥è¦ç»è®¡ async function getAlarmStats() { const res = await getRealtimeAlarmStats(); if (res.code === 200) { Object.assign(alarmStats, res.data); } } // è·å宿¶æ¥è¦å表 async function getRealtimeAlarms() { loading.value = true; const res = await listRealtimeAlarms(alarmQuery); if (res.code === 200) { realtimeAlarms.value = res.data.records; alarmTotal.value = res.data.total; } loading.value = false; } // 确认æ¥è¦ async function handleConfirm(row) { const res = await confirmAlarm(row.alarmId); if (res.code === 200) { ElMessage.success('确认æå'); getRealtimeAlarms(); } } // åææ¥è¦ async function handleAnalyze(row) { currentAlarm.value = row; const res = await analyzeAlarm(row.alarmId); if (res.code === 200) { Object.assign(analysisResult, res.data); } analyzeVisible.value = true; } // è·åæ¥è¦è¶å¿ async function getTrendData() { const res = await getAlarmTrend(); if (res.code === 200) { const data = res.data; trendXAxis.value[0].data = data.dates trendSeries.value[0].data = data.urgent trendSeries.value[0].itemStyle = { color: '#f56c6c' } trendSeries.value[1].data = data.important trendSeries.value[1].itemStyle = { color: '#e6a23c' } trendSeries.value[2].data = data.normal trendSeries.value[2].itemStyle = { color: '#909399' } } } // è·åæ¥è¦ç±»ååå¸ async function getTypeDistribution() { const res = await getAlarmTypeDistribution(); if (res.code === 200) { typeSeries.value[0].data = res.data typeSeries.value[0].emphasis = { itemStyle: { shadowBlur: 10, shadowOffsetX: 0, shadowColor: 'rgba(0, 0, 0, 0.5)' } } } } // è·åæ éè¯æå表 async function getFaultList() { const res = await getFaultDiagnosisList(); if (res.code === 200) { faultList.value = res.data; } } // æºè½è¯æ function handleFaultDiagnosis() { ElMessage.success('æºè½è¯æå®æ'); getFaultList(); } function viewDetail(row) { ElMessage.info('æ¥ç详æ : ' + row.faultType); } // 宿¶å·æ° function startAutoRefresh() { refreshTimer = setInterval(() => { getAlarmStats(); getRealtimeAlarms(); }, refreshInterval.value * 1000); } function stopAutoRefresh() { if (refreshTimer) { clearInterval(refreshTimer); refreshTimer = null; } } onMounted(() => { getAlarmStats(); getRealtimeAlarms(); getTrendData(); getTypeDistribution(); getFaultList(); startAutoRefresh(); }); onUnmounted(() => { stopAutoRefresh(); }); </script> <style scoped> .stat-row { margin-bottom: 20px; } .status-card { text-align: center; } .status-card.danger { border-left: 4px solid #f56c6c; } .status-card.warning { border-left: 4px solid #e6a23c; } .status-card.info { border-left: 4px solid #909399; } .status-card.success { border-left: 4px solid #67c23a; } .status-title { font-size: 14px; color: #666; margin-bottom: 10px; } .status-value { font-size: 32px; font-weight: bold; color: #303133; } .card-header { display: flex; justify-content: space-between; align-items: center; } .analysis-section { margin-top: 20px; } .analysis-section h4 { margin: 0 0 15px 0; font-size: 16px; color: #303133; } </style> src/views/alarmManagement/alarmOptimization/index.vue
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,458 @@ <template> <div class="app-container"> <!-- ä¼åææç»è®¡ --> <el-row :gutter="20" class="stat-row"> <el-col :span="6"> <el-statistic title="å·²è¿æ»¤æ ææ¥è¦" :value="optimizationStats.filteredCount" /> </el-col> <el-col :span="6"> <el-statistic title="æææ¥è¦ç(%)" :value="optimizationStats.validRate" /> </el-col> <el-col :span="6"> <el-statistic title="å¹³åååºæ¶é´(ç§)" :value="optimizationStats.responseTime" /> </el-col> <el-col :span="6"> <el-statistic title="æ²»çè¯å" :value="optimizationStats.score" /> </el-col> </el-row> <!-- æ»æ°æ¥è¦æ²»ççç¥ --> <el-card class="box-card"> <template #header> <div class="card-header"> <span>æ»æ°æ¥è¦æ²»ççç¥</span> <el-button type="primary" size="small" icon="Plus" @click="handleAddStrategy">æ°å¢çç¥</el-button> </div> </template> <el-table :data="strategyList" v-loading="loading" border> <el-table-column type="index" label="åºå·" width="60" align="center" /> <el-table-column prop="strategyName" label="çç¥åç§°" min-width="150" /> <el-table-column prop="strategyType" label="çç¥ç±»å" width="120" align="center"> <template #default="{ row }"> <el-tag size="small">{{ row.strategyType }}</el-tag> </template> </el-table-column> <el-table-column prop="description" label="çç¥è¯´æ" min-width="200" /> <el-table-column prop="filteredCount" label="å·²è¿æ»¤æ°" width="100" align="center" /> <el-table-column prop="status" label="ç¶æ" width="80" align="center"> <template #default="{ row }"> <el-tag :type="row.status === 1 ? 'success' : 'info'" size="small"> {{ row.status === 1 ? 'å¯ç¨' : 'åç¨' }} </el-tag> </template> </el-table-column> <el-table-column label="æä½" width="150" align="center"> <template #default="{ row }"> <el-button type="primary" link size="small" @click="handleEditStrategy(row)">ç¼è¾</el-button> <el-button type="danger" link size="small" @click="handleDeleteStrategy(row)">å é¤</el-button> </template> </el-table-column> </el-table> </el-card> <!-- å岿¥è¦æ°æ®åæ --> <el-row :gutter="20" style="margin-top: 20px;"> <el-col :span="12"> <el-card class="box-card"> <template #header> <span>æ²»çåå对æ¯</span> </template> <Echarts :xAxis="compareXAxis" :yAxis="compareYAxis" :series="compareSeries" :legend="compareLegend" :tooltip="compareTooltip" :chartStyle="{ height: '280px', width: '100%' }" /> </el-card> </el-col> <el-col :span="12"> <el-card class="box-card"> <template #header> <div class="card-header"> <span>é«é¢æ¥è¦ç¹ä½TOP5</span> </div> </template> <el-table :data="highFreqList" size="small" border> <el-table-column type="index" label="æå" width="60" align="center" /> <el-table-column prop="pointName" label="ç¹ä½åç§°" min-width="150" /> <el-table-column prop="deviceType" label="设å¤ç±»å" width="120" align="center" /> <el-table-column prop="alarmLevel" label="æ¥è¦çº§å«" width="100" align="center"> <template #default="{ row }"> <el-tag :type="row.alarmLevel === 'ç´§æ¥' ? 'danger' : row.alarmLevel === 'éè¦' ? 'warning' : 'info'" size="small"> {{ row.alarmLevel }} </el-tag> </template> </el-table-column> </el-table> </el-card> </el-col> </el-row> <!-- æ¥è¦åé¤å®¡æ¹ --> <el-card class="box-card" style="margin-top: 20px;"> <template #header> <div class="card-header"> <span>æ¥è¦åé¤å®¡æ¹</span> <el-button type="primary" size="small" icon="Plus" @click="handleApplyRemove">ç³è¯·åé¤</el-button> </div> </template> <el-form :inline="true" :model="approvalQuery"> <el-form-item label="审æ¹ç¶æ"> <el-select v-model="approvalQuery.status" placeholder="è¯·éæ©" clearable style="width: 120px"> <el-option label="å¾ å®¡æ¹" value="pending" /> <el-option label="å·²éè¿" value="approved" /> <el-option label="已驳å" value="rejected" /> </el-select> </el-form-item> <el-form-item> <el-button type="primary" icon="Search" @click="getApprovalList">æ¥è¯¢</el-button> <el-button icon="Refresh" @click="resetApprovalQuery">éç½®</el-button> </el-form-item> </el-form> <el-table :data="approvalList" border> <el-table-column type="index" label="åºå·" width="60" align="center" /> <el-table-column prop="applyNo" label="ç³è¯·ç¼å·" width="120" align="center" /> <el-table-column prop="pointName" label="æ¥è¦ç¹ä½" min-width="150" /> <el-table-column prop="removeReason" label="åé¤åå " min-width="180" /> <el-table-column prop="applicant" label="ç³è¯·äºº" width="100" align="center" /> <el-table-column prop="applyTime" label="ç³è¯·æ¶é´" width="160" align="center" /> <el-table-column prop="status" label="审æ¹ç¶æ" width="100" align="center"> <template #default="{ row }"> <el-tag :type="row.status === 'pending' ? 'warning' : row.status === 'approved' ? 'success' : 'danger'" size="small"> {{ row.status === 'pending' ? 'å¾ å®¡æ¹' : row.status === 'approved' ? 'å·²éè¿' : '已驳å' }} </el-tag> </template> </el-table-column> <el-table-column label="æä½" width="150" align="center"> <template #default="{ row }"> <template v-if="row.status === 'pending'"> <el-button type="success" link size="small" @click="handleApprove(row)">éè¿</el-button> <el-button type="danger" link size="small" @click="handleReject(row)">驳å</el-button> </template> <span v-else>-</span> </template> </el-table-column> </el-table> <pagination v-show="approvalTotal > 0" :total="approvalTotal" v-model:page="approvalQuery.pageNum" v-model:limit="approvalQuery.pageSize" @pagination="getApprovalList" /> </el-card> <!-- æ°å¢/ç¼è¾çç¥å¼¹çª --> <el-dialog :title="strategyDialogTitle" v-model="strategyDialogVisible" width="500px" append-to-body> <el-form ref="strategyFormRef" :model="strategyForm" :rules="strategyRules" label-width="100px"> <el-form-item label="çç¥åç§°" prop="strategyName"> <el-input v-model="strategyForm.strategyName" placeholder="请è¾å ¥çç¥åç§°" /> </el-form-item> <el-form-item label="çç¥ç±»å" prop="strategyType"> <el-select v-model="strategyForm.strategyType" placeholder="è¯·éæ©" style="width: 100%"> <el-option label="é夿¥è¦è¿æ»¤" value="é夿¥è¦è¿æ»¤" /> <el-option label="æå¨æ¥è¦è¿æ»¤" value="æå¨æ¥è¦è¿æ»¤" /> <el-option label="ç¬ææ¥è¦è¿æ»¤" value="ç¬ææ¥è¦è¿æ»¤" /> <el-option label="æ ææ¥è¦å±è½" value="æ ææ¥è¦å±è½" /> </el-select> </el-form-item> <el-form-item label="çç¥è¯´æ" prop="description"> <el-input v-model="strategyForm.description" type="textarea" :rows="3" placeholder="请è¾å ¥çç¥è¯´æ" /> </el-form-item> <el-form-item label="è§åé ç½®" prop="ruleConfig"> <el-input v-model="strategyForm.ruleConfig" type="textarea" :rows="3" placeholder="请è¾å ¥è§åé ç½®JSON" /> </el-form-item> <el-form-item label="ç¶æ" prop="status"> <el-radio-group v-model="strategyForm.status"> <el-radio :label="1">å¯ç¨</el-radio> <el-radio :label="0">åç¨</el-radio> </el-radio-group> </el-form-item> </el-form> <template #footer> <el-button @click="strategyDialogVisible = false">åæ¶</el-button> <el-button type="primary" @click="submitStrategyForm">ç¡®å®</el-button> </template> </el-dialog> <!-- ç³è¯·åé¤å¼¹çª --> <el-dialog title="ç³è¯·æ¥è¦åé¤" v-model="applyDialogVisible" width="500px" append-to-body> <el-form ref="applyFormRef" :model="applyForm" :rules="applyRules" label-width="100px"> <el-form-item label="æ¥è¦ç¹ä½" prop="pointId"> <el-select v-model="applyForm.pointId" placeholder="è¯·éæ©æ¥è¦ç¹ä½" style="width: 100%"> <el-option v-for="item in pointOptions" :key="item.pointId" :label="item.pointName" :value="item.pointId" /> </el-select> </el-form-item> <el-form-item label="åé¤åå " prop="removeReason"> <el-select v-model="applyForm.removeReason" placeholder="è¯·éæ©åé¤åå " style="width: 100%"> <el-option label="误æ¥è¦" value="误æ¥è¦" /> <el-option label="è®¾å¤æ é已修å¤" value="è®¾å¤æ é已修å¤" /> <el-option label="å·¥èºè°æ´" value="å·¥èºè°æ´" /> <el-option label="å ¶ä»åå " value="å ¶ä»åå " /> </el-select> </el-form-item> <el-form-item label="详ç»è¯´æ" prop="description"> <el-input v-model="applyForm.description" type="textarea" :rows="3" placeholder="请详ç»è¯´æåé¤åå " /> </el-form-item> </el-form> <template #footer> <el-button @click="applyDialogVisible = false">åæ¶</el-button> <el-button type="primary" @click="submitApplyForm">æäº¤ç³è¯·</el-button> </template> </el-dialog> </div> </template> <script setup> import { ref, reactive, onMounted } from 'vue'; import { ElMessage, ElMessageBox } from 'element-plus'; import Echarts from '@/components/Echarts/echarts.vue'; import Pagination from '@/components/Pagination/index.vue'; import { getOptimizationStatistics, listNuisanceStrategies, addNuisanceStrategy, updateNuisanceStrategy, delNuisanceStrategy, changeStrategyStatus, getOptimizationCompareData, listRemoveApprovals, submitRemoveApply, approveRemoveApply, rejectRemoveApply } from '@/api/alarmManagement/alarmOptimization'; import { listAlarmPointLedger } from '@/api/alarmManagement/dataCollection'; // ä¼åç»è®¡ const optimizationStats = reactive({ filteredCount: 0, validRate: 0, responseTime: 0, score: 0 }); // çç¥å表 const loading = ref(false); const strategyList = ref([]); // 审æ¹å表 const approvalList = ref([]); const approvalTotal = ref(0); const approvalQuery = reactive({ pageNum: 1, pageSize: 10, status: '' }); // é«é¢æ¥è¦å表 const highFreqList = ref([]); // çç¥å¼¹çª const strategyDialogVisible = ref(false); const strategyDialogTitle = ref(''); const strategyFormRef = ref(null); const strategyForm = reactive({ strategyId: undefined, strategyName: '', strategyType: '', description: '', ruleConfig: '', status: 1 }); const strategyRules = { strategyName: [{ required: true, message: 'çç¥åç§°ä¸è½ä¸ºç©º', trigger: 'blur' }], strategyType: [{ required: true, message: 'çç¥ç±»åä¸è½ä¸ºç©º', trigger: 'change' }], description: [{ required: true, message: 'çç¥è¯´æä¸è½ä¸ºç©º', trigger: 'blur' }] }; // ç³è¯·å¼¹çª const applyDialogVisible = ref(false); const applyFormRef = ref(null); const applyForm = reactive({ pointId: '', removeReason: '', description: '' }); const applyRules = { pointId: [{ required: true, message: 'è¯·éæ©æ¥è¦ç¹ä½', trigger: 'change' }], removeReason: [{ required: true, message: 'è¯·éæ©åé¤åå ', trigger: 'change' }], description: [{ required: true, message: '请填å详ç»è¯´æ', trigger: 'blur' }] }; const pointOptions = ref([]); // å¾è¡¨é ç½® const compareXAxis = ref([{ type: 'category', data: [] }]) const compareYAxis = ref([{ type: 'value' }]) const compareSeries = ref([ { name: 'æ²»çå', type: 'bar', data: [], itemStyle: { color: '#f56c6c' } }, { name: 'æ²»çå', type: 'bar', data: [], itemStyle: { color: '#67c23a' } }, ]) const compareLegend = reactive({ data: ['æ²»çå', 'æ²»çå'] }) const compareTooltip = reactive({ trigger: 'axis', axisPointer: { type: 'shadow' } }) // è·åä¼åç»è®¡ async function getStatistics() { const res = await getOptimizationStatistics(); if (res.code === 200) { Object.assign(optimizationStats, res.data); } } // è·åçç¥å表 async function getStrategyList() { loading.value = true; const res = await listNuisanceStrategies(); if (res.code === 200) { strategyList.value = res.data; } loading.value = false; } // è·å审æ¹å表 async function getApprovalList() { const res = await listRemoveApprovals(approvalQuery); if (res.code === 200) { approvalList.value = res.data.records; approvalTotal.value = res.data.total; } } // è·åé«é¢æ¥è¦å表ï¼è°ç¨æ°æ®é鿍¡åçæ¥è¯¢æ¥å£ï¼ async function getHighFreqList() { const res = await listAlarmPointLedger({ current: 1, size: 5 }); if (res.code === 200) { highFreqList.value = res.data.records || res.data || []; } } // è·åå¯¹æ¯æ°æ® async function getCompareData() { const res = await getOptimizationCompareData(); if (res.code === 200) { const data = res.data; compareXAxis.value[0].data = data.categories compareSeries.value[0].data = data.before compareSeries.value[1].data = data.after } } // è·åç¹ä½é项ï¼è°ç¨æ°æ®é鿍¡åçæ¥è¯¢æ¥å£ï¼ async function getPointOptions() { const res = await listAlarmPointLedger({ current: 1, size: 1000 }); if (res.code === 200) { pointOptions.value = res.data.records || res.data || []; } } function handleAddStrategy() { strategyDialogTitle.value = 'æ°å¢çç¥'; Object.keys(strategyForm).forEach(key => strategyForm[key] = key === 'strategyId' ? undefined : ''); strategyDialogVisible.value = true; } function handleEditStrategy(row) { strategyDialogTitle.value = 'ç¼è¾çç¥'; Object.assign(strategyForm, row); strategyDialogVisible.value = true; } async function submitStrategyForm() { strategyFormRef.value.validate(async (valid) => { if (valid) { const api = strategyForm.strategyId ? updateNuisanceStrategy : addNuisanceStrategy; const res = await api(strategyForm); if (res.code === 200) { ElMessage.success(strategyForm.strategyId ? 'ä¿®æ¹æå' : 'æ°å¢æå'); strategyDialogVisible.value = false; getStrategyList(); } } }); } async function handleDeleteStrategy(row) { await ElMessageBox.confirm('确认å é¤è¯¥çç¥åï¼', 'æç¤º', { type: 'warning' }); const res = await delNuisanceStrategy(row.strategyId); if (res.code === 200) { ElMessage.success('å 餿å'); getStrategyList(); } } async function handleStrategyStatusChange(row) { const res = await changeStrategyStatus(row.strategyId, row.status); if (res.code === 200) { ElMessage.success('ç¶æä¿®æ¹æå'); } } function handleViewMore() { ElMessage.info('æ¥çæ´å¤é«é¢æ¥è¦ç¹ä½'); } function handleApplyRemove() { Object.keys(applyForm).forEach(key => applyForm[key] = ''); applyDialogVisible.value = true; } async function submitApplyForm() { applyFormRef.value.validate(async (valid) => { if (valid) { const res = await submitRemoveApply(applyForm); if (res.code === 200) { ElMessage.success('ç³è¯·æäº¤æå'); applyDialogVisible.value = false; getApprovalList(); } } }); } async function handleApprove(row) { const res = await approveRemoveApply(row.applyNo); if (res.code === 200) { ElMessage.success('审æ¹éè¿'); getApprovalList(); } } async function handleReject(row) { const res = await rejectRemoveApply(row.applyNo); if (res.code === 200) { ElMessage.success('已驳å'); getApprovalList(); } } function viewDetail(row) { ElMessage.info('æ¥ç详æ : ' + row.applyNo); } function resetApprovalQuery() { approvalQuery.status = ''; getApprovalList(); } onMounted(() => { getStatistics(); getStrategyList(); getApprovalList(); getHighFreqList(); getCompareData(); getPointOptions(); }); </script> <style scoped> .stat-row { margin-bottom: 20px; } .stat-row :deep(.el-statistic__content) { font-size: 28px; font-weight: 600; color: #303133; } .stat-row :deep(.el-statistic__title) { font-size: 14px; color: #606266; margin-bottom: 8px; } .card-header { display: flex; justify-content: space-between; align-items: center; } </style> src/views/alarmManagement/dataCollection/index.vue
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,457 @@ <template> <div class="app-container"> <!-- ç»è®¡å¡ç --> <el-row :gutter="20" class="stat-row"> <el-col :span="6"> <el-statistic title="æ¥è¦ç¹ä½æ»æ°" :value="statistics.totalPoints" /> </el-col> <el-col :span="6"> <el-statistic title="å·²è¿æ¥è®¾å¤" :value="statistics.connectedDevices" /> </el-col> <el-col :span="6"> <el-statistic title="仿¥æ°æ®é(䏿¡)" :value="statistics.todayDataVolume" /> </el-col> <el-col :span="6"> <el-statistic title="è§£ææåç(%)" :value="statistics.parseSuccessRate" /> </el-col> </el-row> <!-- æ¥è¦ç¹ä½å°è´¦ --> <el-card class="box-card"> <template #header> <div class="card-header"> <span>æ¥è¦ç¹ä½å°è´¦</span> <div> <el-button type="primary" size="small" icon="Plus" @click="handleAdd">æ°å¢</el-button> <!-- <el-button size="small" icon="Download" @click="handleExport">导åº</el-button> --> </div> </div> </template> <el-form :inline="true" :model="queryParams"> <el-form-item label="ç¹ä½åç§°"> <el-input v-model="queryParams.pointName" placeholder="请è¾å ¥" clearable /> </el-form-item> <el-form-item label="设å¤ç±»å"> <el-select v-model="queryParams.deviceType" placeholder="è¯·éæ©" clearable style="width: 150px"> <el-option label="æ¸©åº¦ä¼ æå¨" value="æ¸©åº¦ä¼ æå¨" /> <el-option label="ååä¼ æå¨" value="ååä¼ æå¨" /> <el-option label="æµéä¼ æå¨" value="æµéä¼ æå¨" /> <el-option label="æ¶²ä½ä¼ æå¨" value="æ¶²ä½ä¼ æå¨" /> </el-select> </el-form-item> <el-form-item> <el-button type="primary" icon="Search" @click="getList">æ¥è¯¢</el-button> <el-button icon="Refresh" @click="resetQuery">éç½®</el-button> </el-form-item> </el-form> <el-table :data="pointList" v-loading="loading" border> <el-table-column type="index" label="åºå·" width="60" align="center" /> <el-table-column prop="pointCode" label="ç¹ä½ç¼ç " width="120" align="center" /> <el-table-column prop="pointName" label="ç¹ä½åç§°" min-width="150" /> <el-table-column prop="deviceType" label="设å¤ç±»å" width="120" align="center" /> <el-table-column prop="alarmLevel" label="æ¥è¦çº§å«" width="100" align="center"> <template #default="{ row }"> <el-tag :type="row.alarmLevel === 'ç´§æ¥' ? 'danger' : row.alarmLevel === 'éè¦' ? 'warning' : 'info'" size="small"> {{ row.alarmLevel }} </el-tag> </template> </el-table-column> <el-table-column prop="thresholdValue" label="æ¥è¦éå¼" width="120" align="center" /> <el-table-column prop="area" label="æå±åºå" width="120" align="center" /> <el-table-column prop="status" label="ç¶æ" width="80" align="center"> <template #default="{ row }"> <el-tag :type="row.status === 1 ? 'success' : 'info'" size="small"> {{ row.status === 1 ? 'å¯ç¨' : 'åç¨' }} </el-tag> </template> </el-table-column> <el-table-column label="æä½" width="150" align="center" fixed="right"> <template #default="{ row }"> <el-button type="primary" link size="small" @click="handleEdit(row)">ç¼è¾</el-button> <el-button type="danger" link size="small" @click="handleDelete(row)">å é¤</el-button> </template> </el-table-column> </el-table> <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" /> </el-card> <!-- æ°æ®ééé ç½® --> <el-card class="box-card" style="margin-top: 20px;"> <template #header> <div class="card-header"> <span>æ°æ®ééé ç½®</span> <el-button type="primary" size="small" icon="Plus" @click="handleAddInterface">æ°å¢æ¥å£</el-button> </div> </template> <el-table :data="interfaceList" border> <el-table-column type="index" label="åºå·" width="60" align="center" /> <el-table-column prop="interfaceName" label="æ¥å£åç§°" min-width="150" /> <el-table-column prop="interfaceType" label="æ¥å£ç±»å" width="120" align="center"> <template #default="{ row }"> <el-tag size="small">{{ row.interfaceType }}</el-tag> </template> </el-table-column> <el-table-column prop="serverAddress" label="æå¡å¨å°å" width="180" /> <el-table-column prop="collectFreq" label="ééé¢ç" width="100" align="center" /> <el-table-column label="æä½" width="250" align="center"> <template #default="{ row }"> <el-button type="primary" link size="small" @click="handleEditInterface(row)">ç¼è¾</el-button> <el-button type="danger" link size="small" @click="handleDeleteInterface(row)">å é¤</el-button> </template> </el-table-column> </el-table> </el-card> <!-- æ°å¢/ç¼è¾ç¹ä½å¼¹çª --> <el-dialog :title="dialogTitle" v-model="dialogVisible" width="500px" append-to-body> <el-form ref="formRef" :model="form" :rules="rules" label-width="100px"> <el-form-item label="ç¹ä½ç¼ç " prop="pointCode"> <el-input v-model="form.pointCode" placeholder="请è¾å ¥ç¹ä½ç¼ç " /> </el-form-item> <el-form-item label="ç¹ä½åç§°" prop="pointName"> <el-input v-model="form.pointName" placeholder="请è¾å ¥ç¹ä½åç§°" /> </el-form-item> <el-form-item label="设å¤ç±»å" prop="deviceType"> <el-select v-model="form.deviceType" placeholder="è¯·éæ©" style="width: 100%"> <el-option label="æ¸©åº¦ä¼ æå¨" value="æ¸©åº¦ä¼ æå¨" /> <el-option label="ååä¼ æå¨" value="ååä¼ æå¨" /> <el-option label="æµéä¼ æå¨" value="æµéä¼ æå¨" /> <el-option label="æ¶²ä½ä¼ æå¨" value="æ¶²ä½ä¼ æå¨" /> </el-select> </el-form-item> <el-form-item label="æ¥è¦çº§å«" prop="alarmLevel"> <el-select v-model="form.alarmLevel" placeholder="è¯·éæ©" style="width: 100%"> <el-option label="ç´§æ¥" value="ç´§æ¥" /> <el-option label="éè¦" value="éè¦" /> <el-option label="ä¸è¬" value="ä¸è¬" /> </el-select> </el-form-item> <el-form-item label="æ¥è¦éå¼" prop="thresholdValue"> <el-input v-model="form.thresholdValue" placeholder="请è¾å ¥æ¥è¦éå¼" /> </el-form-item> <el-form-item label="æå±åºå" prop="area"> <el-input v-model="form.area" placeholder="请è¾å ¥æå±åºå" /> </el-form-item> <el-form-item label="ç¶æ" prop="status"> <el-radio-group v-model="form.status"> <el-radio :label="1">å¯ç¨</el-radio> <el-radio :label="0">åç¨</el-radio> </el-radio-group> </el-form-item> </el-form> <template #footer> <el-button @click="dialogVisible = false">åæ¶</el-button> <el-button type="primary" @click="submitForm">ç¡®å®</el-button> </template> </el-dialog> <!-- æ°å¢/ç¼è¾æ¥å£å¼¹çª --> <el-dialog :title="interfaceDialogTitle" v-model="interfaceDialogVisible" width="550px" append-to-body> <el-form ref="interfaceFormRef" :model="interfaceForm" :rules="interfaceRules" label-width="100px"> <el-form-item label="æ¥å£åç§°" prop="interfaceName"> <el-input v-model="interfaceForm.interfaceName" placeholder="请è¾å ¥æ¥å£åç§°" /> </el-form-item> <el-form-item label="æ¥å£ç±»å" prop="interfaceType"> <el-select v-model="interfaceForm.interfaceType" placeholder="è¯·éæ©" style="width: 100%"> <el-option label="OPC UA" value="OPC UA" /> <el-option label="Modbus TCP" value="Modbus TCP" /> <el-option label="Modbus RTU" value="Modbus RTU" /> <el-option label="MQTT" value="MQTT" /> <el-option label="HTTP API" value="HTTP API" /> </el-select> </el-form-item> <el-form-item label="æå¡å¨å°å" prop="serverAddress"> <el-input v-model="interfaceForm.serverAddress" placeholder="å¦: opc.tcp://192.168.1.100:4840" /> </el-form-item> <el-form-item label="ééé¢ç" prop="collectFreq"> <el-input v-model="interfaceForm.collectFreq" placeholder="å¦: 1ç§ã5ç§ã1åé" /> </el-form-item> <el-form-item label="ç¨æ·å"> <el-input v-model="interfaceForm.username" placeholder="请è¾å ¥ç¨æ·åï¼å¯éï¼" /> </el-form-item> <el-form-item label="å¯ç "> <el-input v-model="interfaceForm.password" type="password" placeholder="请è¾å ¥å¯ç ï¼å¯éï¼" show-password /> </el-form-item> <el-form-item label="æè¿°"> <el-input v-model="interfaceForm.description" type="textarea" :rows="3" placeholder="请è¾å ¥æ¥å£æè¿°ï¼å¯éï¼" /> </el-form-item> </el-form> <template #footer> <el-button @click="interfaceDialogVisible = false">åæ¶</el-button> <el-button type="primary" @click="submitInterfaceForm">ç¡®å®</el-button> </template> </el-dialog> </div> </template> <script setup> import { ref, reactive, onMounted } from 'vue'; import { ElMessage, ElMessageBox } from 'element-plus'; import Pagination from '@/components/Pagination/index.vue'; import { listAlarmPointLedger, addAlarmPoint, updateAlarmPoint, delAlarmPoint, changePointStatus, exportPointLedger, listDataInterface, startDataCollection, stopDataCollection, getCollectionStatistics, addDataInterface, delDataInterface, changeInterfaceStatus } from '@/api/alarmManagement/dataCollection'; // ç»è®¡æ°æ® const statistics = reactive({ totalPoints: 0, connectedDevices: 0, todayDataVolume: 0, parseSuccessRate: 0 }); // æ¥è¯¢åæ° const queryParams = reactive({ pageNum: 1, pageSize: 10, pointName: '', deviceType: '' }); const loading = ref(false); const pointList = ref([]); const total = ref(0); // æ¥å£å表 const interfaceList = ref([]); // ç¹ä½å¼¹çªç¸å ³ const dialogVisible = ref(false); const dialogTitle = ref(''); const formRef = ref(null); const form = reactive({ pointId: undefined, pointCode: '', pointName: '', deviceType: '', alarmLevel: '', thresholdValue: '', area: '', status: 1 }); const rules = { pointCode: [{ required: true, message: 'ç¹ä½ç¼ç ä¸è½ä¸ºç©º', trigger: 'blur' }], pointName: [{ required: true, message: 'ç¹ä½åç§°ä¸è½ä¸ºç©º', trigger: 'blur' }], deviceType: [{ required: true, message: '设å¤ç±»åä¸è½ä¸ºç©º', trigger: 'change' }], alarmLevel: [{ required: true, message: 'æ¥è¦çº§å«ä¸è½ä¸ºç©º', trigger: 'change' }], thresholdValue: [{ required: true, message: 'æ¥è¦éå¼ä¸è½ä¸ºç©º', trigger: 'blur' }], area: [{ required: true, message: 'æå±åºåä¸è½ä¸ºç©º', trigger: 'blur' }], status: [{ required: true, message: 'ç¶æä¸è½ä¸ºç©º', trigger: 'change' }] }; // æ¥å£å¼¹çªç¸å ³ const interfaceDialogVisible = ref(false); const interfaceDialogTitle = ref(''); const interfaceFormRef = ref(null); const interfaceForm = reactive({ interfaceId: undefined, interfaceName: '', interfaceType: '', serverAddress: '', collectFreq: '', username: '', password: '', description: '' }); const interfaceRules = { interfaceName: [{ required: true, message: 'æ¥å£åç§°ä¸è½ä¸ºç©º', trigger: 'blur' }], interfaceType: [{ required: true, message: 'æ¥å£ç±»åä¸è½ä¸ºç©º', trigger: 'change' }], serverAddress: [{ required: true, message: 'æå¡å¨å°åä¸è½ä¸ºç©º', trigger: 'blur' }], collectFreq: [{ required: true, message: 'ééé¢çä¸è½ä¸ºç©º', trigger: 'blur' }] }; // è·åç»è®¡æ°æ® async function getStatistics() { const res = await getCollectionStatistics(); if (res.code === 200) { Object.assign(statistics, res.data); } } // è·åç¹ä½å表 async function getList() { loading.value = true; const res = await listAlarmPointLedger(queryParams); if (res.code === 200) { pointList.value = res.data.records || res.rows; total.value = res.data.total || res.total; } loading.value = false; } // è·åæ¥å£å表 async function getInterfaceList() { const res = await listDataInterface(); if (res.code === 200) { interfaceList.value = res.data; } } function resetQuery() { queryParams.pointName = ''; queryParams.deviceType = ''; getList(); } function handleAdd() { dialogTitle.value = 'æ°å¢ç¹ä½'; Object.keys(form).forEach(key => form[key] = key === 'pointId' ? undefined : ''); dialogVisible.value = true; } function handleEdit(row) { dialogTitle.value = 'ç¼è¾ç¹ä½'; Object.assign(form, row); dialogVisible.value = true; } async function submitForm() { formRef.value.validate(async (valid) => { if (valid) { const api = form.pointId ? updateAlarmPoint : addAlarmPoint; const res = await api(form); if (res.code === 200) { ElMessage.success(form.pointId ? 'ä¿®æ¹æå' : 'æ°å¢æå'); dialogVisible.value = false; getList(); } } }); } async function handleDelete(row) { await ElMessageBox.confirm('确认å é¤è¯¥ç¹ä½åï¼', 'æç¤º', { type: 'warning' }); const res = await delAlarmPoint(row.pointId); if (res.code === 200) { ElMessage.success('å 餿å'); getList(); } } async function handleBeforeStatusChange(row) { // è¿å true å è®¸åæ¢ï¼false 黿¢åæ¢ try { const newStatus = row.status === 1 ? 0 : 1; const res = await changePointStatus(row.pointId, newStatus); if (res.code === 200) { ElMessage.success('ç¶æä¿®æ¹æå'); return true; } return false; } catch (error) { return false; } } async function handleStatusChange(row, val) { // ç¶æå·²ç»éè¿ before-change æ´æ°ï¼è¿éåªåå·æ° getList(); } async function handleExport() { await exportPointLedger(queryParams); ElMessage.success('å¯¼åºæå'); } function handleAddInterface() { interfaceDialogTitle.value = 'æ°å¢æ¥å£'; Object.keys(interfaceForm).forEach(key => interfaceForm[key] = key === 'interfaceId' ? undefined : ''); interfaceDialogVisible.value = true; } function handleEditInterface(row) { interfaceDialogTitle.value = 'ç¼è¾æ¥å£'; Object.assign(interfaceForm, row); interfaceDialogVisible.value = true; } async function submitInterfaceForm() { interfaceFormRef.value.validate(async (valid) => { if (valid) { const res = await addDataInterface(interfaceForm); if (res.code === 200) { ElMessage.success(interfaceForm.interfaceId ? 'ä¿®æ¹æå' : 'æ°å¢æå'); interfaceDialogVisible.value = false; getInterfaceList(); } } }); } async function handleDeleteInterface(row) { await ElMessageBox.confirm('确认å é¤è¯¥æ¥å£åï¼', 'æç¤º', { type: 'warning' }); const res = await delDataInterface(row.interfaceId); if (res.code === 200) { ElMessage.success('å 餿å'); getInterfaceList(); } } async function handleInterfaceStatusChange(row) { const res = await changeInterfaceStatus(row.interfaceId, row.status); if (res.code === 200) { ElMessage.success('ç¶æä¿®æ¹æå'); } } async function handleStart(row) { const res = await startDataCollection(row.interfaceId); if (res.code === 200) { ElMessage.success('å¯å¨æå'); getInterfaceList(); } } async function handleStop(row) { const res = await stopDataCollection(row.interfaceId); if (res.code === 200) { ElMessage.success('忢æå'); getInterfaceList(); } } onMounted(() => { getStatistics(); getList(); getInterfaceList(); }); </script> <style scoped> .stat-row { margin-bottom: 20px; } .stat-row :deep(.el-statistic__content) { font-size: 28px; font-weight: 600; color: #303133; } .stat-row :deep(.el-statistic__title) { font-size: 14px; color: #606266; margin-bottom: 8px; } .card-header { display: flex; justify-content: space-between; align-items: center; } </style>