From a440032dc3c2217730c55b5176d45d146876c52b Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期二, 02 六月 2026 16:50:29 +0800
Subject: [PATCH] 浪潮 1.添加数据采集与解析、报警分析评估、报警优化管理三个页面,前端页面开发并联调

---
 src/api/alarmManagement/alarmAnalysis.js              |   77 ++
 src/api/alarmManagement/alarmOptimization.js          |  141 +++++
 src/views/alarmManagement/alarmOptimization/index.vue |  458 ++++++++++++++++
 src/views/alarmManagement/dataCollection/index.vue    |  457 ++++++++++++++++
 src/views/alarmManagement/alarmAnalysis/index.vue     |  374 +++++++++++++
 src/api/alarmManagement/dataCollection.js             |  163 +++++
 6 files changed, 1,670 insertions(+), 0 deletions(-)

diff --git a/src/api/alarmManagement/alarmAnalysis.js b/src/api/alarmManagement/alarmAnalysis.js
new file mode 100644
index 0000000..fd69824
--- /dev/null
+++ b/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
+  });
+}
diff --git a/src/api/alarmManagement/alarmOptimization.js b/src/api/alarmManagement/alarmOptimization.js
new file mode 100644
index 0000000..1d2496a
--- /dev/null
+++ b/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'
+  });
+}
diff --git a/src/api/alarmManagement/dataCollection.js b/src/api/alarmManagement/dataCollection.js
new file mode 100644
index 0000000..fb2c467
--- /dev/null
+++ b/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'
+  });
+}
diff --git a/src/views/alarmManagement/alarmAnalysis/index.vue b/src/views/alarmManagement/alarmAnalysis/index.vue
new file mode 100644
index 0000000..e0ec0e7
--- /dev/null
+++ b/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>
diff --git a/src/views/alarmManagement/alarmOptimization/index.vue b/src/views/alarmManagement/alarmOptimization/index.vue
new file mode 100644
index 0000000..1abbd98
--- /dev/null
+++ b/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="璇疯緭鍏ヨ鍒欓厤缃甁SON" />
+        </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>
diff --git a/src/views/alarmManagement/dataCollection/index.vue b/src/views/alarmManagement/dataCollection/index.vue
new file mode 100644
index 0000000..014d3a0
--- /dev/null
+++ b/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="瑙f瀽鎴愬姛鐜�(%)" :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="璇疯緭鍏ユ帴鍙e悕绉�" />
+        </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="璇疯緭鍏ユ帴鍙f弿杩帮紙鍙�夛級" />
+        </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 鍏佽鍒囨崲锛宖alse 闃绘鍒囨崲
+  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('纭鍒犻櫎璇ユ帴鍙e悧锛�', '鎻愮ず', { 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>

--
Gitblit v1.9.3