Jelajahi Sumber

修改工作台 修改工程安全

BAI 1 Minggu lalu
induk
melakukan
da139dc1c0

+ 2 - 2
src/components/TopNav.vue

@@ -69,7 +69,7 @@ export default {
     },
     title: {
       type: String,
-      default: '乌拉海沟水库安全监测平台'
+      default: '乌拉海沟水库综合应用管理系统'
     }
   },
   emits: ['navigate', 'toggle-mode'],
@@ -155,7 +155,7 @@ export default {
   top: 10px;
   left: 50%;
   transform: translateX(-50%);
-  font-size: 42px;
+  font-size: 37px;
   font-weight: 900;
   background: linear-gradient(to top, #00d5ff 0%, #ffffff 50%);
   -webkit-background-clip: text;

+ 2 - 75
src/views/HomeView.vue

@@ -40,31 +40,14 @@
     <LifecycleView v-if="activeTab === '全生命周期管理'" />
     <!-- 工程安全运维视图 -->
     <div v-if="activeTab === '工程安全运维'" class="tab-wrapper">
-      <!-- 底部子功能按钮 -->
-      <div class="secondary-title-container">
-        <div
-          v-for="tab in safetyTabs"
-          :key="tab"
-          class="secondary-title"
-          :class="{ active: activeSafetyTab === tab }"
-          @click="activeSafetyTab = tab"
-        >
-          <span>{{ tab }}</span>
-        </div>
-      </div>
-      <!-- 工程安全视图(完整迁移) -->
-      <EngineeringSafetyView v-if="activeSafetyTab === '工程安全'" />
-      <!-- 管线监测视图 -->
-      <InspectionView v-if="activeSafetyTab === '管线监测'" />
-      <!-- 安全巡护视图(巡查功能完整迁移) -->
-      <PatrolView v-if="activeSafetyTab === '安全巡护'" />
+      <EngineeringSafetyView />
     </div>
     <!-- 闸门控制视图(内嵌模式,不重新加载地图) -->
     <GateControlView v-if="activeTab === '闸门控制'" :embedded="true" />
     <!-- 视频监控视图 -->
     <VideoMonitorView v-if="activeTab === '视频监控'" />
     <!-- 工作台视图 -->
-    <WorkspaceView v-if="activeTab === '工作台'" />
+    <WorkspaceView v-if="activeTab === '工作台'" @backToDashboard="selectTab('流域总览')" />
     
     <!-- 水资源调度视图 -->
     <div v-if="activeTab === '水资源调度'" class="tab-wrapper">
@@ -82,8 +65,6 @@ import EngineeringSafetyView from './mainPages/EngineeringSafetyView.vue'
 import GateControlView from './mainPages/GateControlView.vue'
 import LifecycleView from './mainPages/LifecycleView.vue'
 import VideoMonitorView from './mainPages/VideoMonitorView.vue'
-import PatrolView from './mainPages/PatrolView.vue'
-import InspectionView from './mainPages/InspectionView.vue'
 import WorkspaceView from './mainPages/WorkspaceView.vue'
 import WaterResourceAllocationView from './admin/WaterResourceAllocationView.vue'
 import TopNav from '../components/TopNav.vue'
@@ -97,8 +78,6 @@ export default {
     GateControlView,
     LifecycleView,
     VideoMonitorView,
-    PatrolView,
-    InspectionView,
     WorkspaceView,
     WaterResourceAllocationView,
     CesiumMap,
@@ -109,10 +88,8 @@ export default {
     return {
       activeTab: '流域总览',
       activeSecondaryTab: '水文监控',
-      activeSafetyTab: '工程安全',
       showMap: true,
       loadEmbankmentWarning: false,
-      safetyTabs: ['工程安全', '管线监测', '安全运维', '安全巡护'],
       navButtonMap: {
         '流域总览': '综合首页',
         '水文四预': '水情测报',
@@ -172,9 +149,6 @@ export default {
       if (tab === '水文四预' || tab === '水资源调配') {
         this.activeSecondaryTab = '水文监控'
       }
-      if (tab === '工程安全运维') {
-        this.activeSafetyTab = '工程安全'
-      }
       if (tab !== '水文四预') {
         this.loadEmbankmentWarning = false
       }
@@ -345,46 +319,6 @@ export default {
   color: transparent;
 }
 
-/* 二级标题样式 - 位于顶部导航栏下方 */
-.secondary-title-container {
-  position: absolute;
-  top: 90px;
-  left: 50%;
-  transform: translateX(-50%);
-  display: flex;
-  gap: 10px;
-  z-index: 10;
-}
-
-.secondary-title {
-  width: 125px;
-  height: 26px;
-  background-image: url('/src/assets/images/未选中底部标题.png');
-  background-size: 100% 100%;
-  background-position: center;
-  background-repeat: no-repeat;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  font-size: 12px;
-  font-weight: bold;
-  cursor: pointer;
-  transition: all 0.3s ease;
-}
-
-.secondary-title span {
-  background: linear-gradient(to bottom, #e2e8ff, #7bbef6);
-  -webkit-background-clip: text;
-  background-clip: text;
-  color: transparent;
-  text-shadow: 0 0 5px rgba(0, 212, 255, 0.3);
-}
-
-.secondary-title:hover,
-.secondary-title.active {
-  background-image: url('/src/assets/images/选中底部标题.png');
-}
-
 /* tab 视图容器必须相对定位并填满,子视图用绝对定位 */
 .tab-wrapper {
   position: relative;
@@ -392,13 +326,6 @@ export default {
   height: 100%;
 }
 
-.secondary-title:hover span,
-.secondary-title.active span {
-  background: linear-gradient(to bottom, #e2e8ff, #62f6fb);
-  -webkit-background-clip: text;
-  background-clip: text;
-  color: transparent;
-}
 
 
 </style>

+ 10 - 101
src/views/admin/ArchiveOrdersView.vue

@@ -37,77 +37,10 @@
       </div>
     </div>
 
-    <!-- Tab 切换:待签收 / 执行中 / 历史调令 -->
+    <!-- 历史调令 -->
     <div class="glass-card">
-      <el-tabs v-model="activeTab" class="order-tabs" @tab-click="handleTabChange">
-        <el-tab-pane label="待签收" name="pending">
-          <div class="order-list">
-            <div v-for="(item, idx) in filteredPending" :key="idx" class="order-item">
-              <div class="order-header">
-                <div class="order-title-row">
-                  <el-tag :type="getUrgencyTag(item.urgency)" size="small" effect="dark" class="urgency-tag">
-                    {{ item.urgency }}
-                  </el-tag>
-                  <span class="order-title">{{ item.title }}</span>
-                </div>
-                <span class="order-docno">{{ item.docNo }}</span>
-              </div>
-              <div class="order-body">
-                <div class="order-meta">
-                  <span>签发人:{{ item.issuer }}</span>
-                  <span>签发时间:{{ item.issueTime }}</span>
-                  <span>接收单位:{{ item.receiver }}</span>
-                </div>
-                <div class="order-abstract">{{ item.abstract }}</div>
-              </div>
-              <div class="order-footer">
-                <span class="order-deadline">执行截止:{{ item.deadline }}</span>
-                <div class="order-actions">
-                  <el-button type="primary" size="small" @click="handleViewDetail(item)">详情</el-button>
-                </div>
-              </div>
-            </div>
-            <div v-if="filteredPending.length === 0" class="empty-state">
-              <el-icon class="empty-icon"><CircleCheck /></el-icon>
-              <p>暂无待签收调令</p>
-            </div>
-          </div>
-        </el-tab-pane>
-        <el-tab-pane label="执行中" name="executing">
-          <div class="order-list">
-            <div v-for="(item, idx) in filteredExecuting" :key="idx" class="order-item executing">
-              <div class="order-header">
-                <div class="order-title-row">
-                  <el-tag :type="getUrgencyTag(item.urgency)" size="small" effect="dark" class="urgency-tag">
-                    {{ item.urgency }}
-                  </el-tag>
-                  <span class="order-title">{{ item.title }}</span>
-                </div>
-                <span class="order-docno">{{ item.docNo }}</span>
-              </div>
-              <div class="order-body">
-                <div class="order-meta">
-                  <span>签发人:{{ item.issuer }}</span>
-                  <span>签收人:{{ item.signatory }}</span>
-                  <span>签收时间:{{ item.signTime }}</span>
-                </div>
-                <div class="order-progress">
-                  <span class="progress-label">执行进度</span>
-                  <el-progress :percentage="item.progress" :status="item.progress < 100 ? '' : 'success'" />
-                </div>
-              </div>
-              <div class="order-footer">
-                <span class="order-deadline">执行截止:{{ item.deadline }}</span>
-                <div class="order-actions">
-                  <el-button size="small" @click="handleViewDetail(item)">详情</el-button>
-                </div>
-              </div>
-            </div>
-          </div>
-        </el-tab-pane>
-        <el-tab-pane label="历史调令" name="history">
-          <div class="order-list">
-            <div v-for="(item, idx) in filteredHistory" :key="idx" class="order-item history">
+      <div class="order-list">
+        <div v-for="(item, idx) in filteredHistory" :key="idx" class="order-item history">
               <div class="order-header">
                 <div class="order-title-row">
                   <el-tag type="info" size="small" effect="dark" class="urgency-tag">已办结</el-tag>
@@ -133,9 +66,8 @@
               </div>
             </div>
           </div>
-        </el-tab-pane>
-      </el-tabs>
-    </div>
+        </div>
+      </div>
 
     <!-- 调令详情弹窗:红头文件样式 -->
     <el-dialog v-model="showDetail" :title="'调令详情 - ' + (detailItem?.docNo || '')" width="700px">
@@ -199,18 +131,16 @@
         <el-button type="primary" @click="handlePrint(detailItem)" v-if="detailItem">打印调令</el-button>
       </template>
     </el-dialog>
-  </div>
 </template>
 
 <script>
-import { Search, Download, CircleCheck } from '@element-plus/icons-vue'
+import { Search, Download } from '@element-plus/icons-vue'
 
 export default {
   name: 'ArchiveOrdersView',
-  components: { Search, Download, CircleCheck },
+  components: { Search, Download },
   data() {
     return {
-      activeTab: 'pending',
       searchText: '',
       filterUrgency: '',
       filterYear: '',
@@ -218,19 +148,9 @@ export default {
       detailItem: null,
       statsCards: [
         { title: '调令总数', value: '126', icon: '📜', iconBg: 'linear-gradient(135deg, #fee2e2, #fca5a5)' },
-        { title: '待签收', value: '3', icon: '📩', iconBg: 'linear-gradient(135deg, #fef3c7, #fcd34d)' },
-        { title: '执行中', value: '5', icon: '⚡', iconBg: 'linear-gradient(135deg, #dbeafe, #93c5fd)' },
-        { title: '本月调令', value: '12', icon: '📊', iconBg: 'linear-gradient(135deg, #dcfce7, #86efac)' }
-      ],
-      pendingOrders: [
-        { docNo: 'XJWL-2026-DD-018', title: '关于汛期加大泄洪流量的调度令', issuer: '王建国', urgency: '特急', receiver: '闸门管理所、水电站', issueTime: '2026-06-05 09:00', deadline: '2026-06-05 15:00', abstract: '受持续强降雨影响,乌拉海沟水库水位已逼近汛限水位22.00m。为确保大坝安全,决定自今日15:00起,将溢洪道闸门开度由30%调至60%,下泄流量由45m³/s增至90m³/s。' },
-        { docNo: 'XJWL-2026-DD-017', title: '关于调整农业灌溉供水的调度令', issuer: '李明', urgency: '紧急', receiver: '灌溉管理所', issueTime: '2026-06-04 14:30', deadline: '2026-06-06 08:00', abstract: '因下游灌区已进入夏灌高峰期,现要求将灌溉渠道A段供水流量由5m³/s调整为8m³/s,B段维持3m³/s不变。请灌溉管理所于明日上午8:00前完成闸门调整。' },
-        { docNo: 'XJWL-2026-DD-016', title: '关于生态补水调度指令', issuer: '张建平', urgency: '普通', receiver: '水电站', issueTime: '2026-06-03 16:00', deadline: '2026-06-07 18:00', abstract: '为保障下游河道生态流量,按照《水库生态调度方案》,要求水电站维持不小于2.5m³/s的生态下泄流量。' }
-      ],
-      executingOrders: [
-        { docNo: 'XJWL-2026-DD-015', title: '关于主坝安全监测加密的指令', issuer: '张建平', urgency: '紧急', receiver: '工程管理科', signatory: '刘强', signTime: '2026-06-03 08:30', deadline: '2026-06-10 18:00', progress: 65, abstract: '鉴于近期库水位持续高位运行,要求将主坝变形及渗流监测频次由每周一次加密为每日一次。' },
-        { docNo: 'XJWL-2026-DD-014', title: '关于防汛物资补充的调度令', issuer: '王建国', urgency: '紧急', receiver: '防汛办公室', signatory: '陈东', signTime: '2026-06-02 10:00', deadline: '2026-06-08 18:00', progress: 80, abstract: '根据汛前检查结果,要求补充编织袋5000条、救生衣100件、应急照明设备20套。' },
-        { docNo: 'XJWL-2026-DD-013', title: '关于溢洪道闸门检修的指令', issuer: '李明', urgency: '普通', receiver: '闸门管理所', signatory: '赵海', signTime: '2026-06-01 09:00', deadline: '2026-06-06 17:00', progress: 45, abstract: '汛期前对溢洪道3号闸门启闭机进行全面检修保养。' }
+        { title: '历史调令', value: '5', icon: '📋', iconBg: 'linear-gradient(135deg, #dcfce7, #86efac)' },
+        { title: '本月调令', value: '12', icon: '📊', iconBg: 'linear-gradient(135deg, #dbeafe, #93c5fd)' },
+        { title: '涉及单位', value: '6', icon: '🏢', iconBg: 'linear-gradient(135deg, #fef3c7, #fcd34d)' }
       ],
       historyOrders: [
         { docNo: 'XJWL-2026-DD-012', title: '关于水库汛前放水腾库的调度令', issuer: '王建国', urgency: '紧急', receiver: '闸门管理所、水电站', issueTime: '2026-05-20 08:00', closeTime: '2026-05-22 16:00', result: '已完成放水,库水位降至汛限水位以下2m', abstract: '为迎接主汛期,要求开启放水洞闸门,将库水位由21.50m降至20.00m,总泄水量约500万m³。' },
@@ -242,12 +162,6 @@ export default {
     }
   },
   computed: {
-    filteredPending() {
-      return this.filterOrders(this.pendingOrders)
-    },
-    filteredExecuting() {
-      return this.filterOrders(this.executingOrders)
-    },
     filteredHistory() {
       return this.filterOrders(this.historyOrders)
     }
@@ -271,11 +185,6 @@ export default {
       }
       return result
     },
-    handleTabChange() {
-      this.searchText = ''
-      this.filterUrgency = ''
-      this.filterYear = ''
-    },
     getUrgencyTag(v) {
       return { 普通: 'info', 紧急: 'warning', 特急: 'danger' }[v] || 'info'
     },

+ 237 - 1
src/views/admin/DeviceMaintainView.vue

@@ -78,6 +78,95 @@
         </div>
       </el-tab-pane>
 
+      <!-- 设备详情弹窗 -->
+      <el-dialog v-model="showDeviceDetail" :title="'设备详情 - ' + (selectedDevice?.name || '')" width="960px" top="5vh" @closed="handleCloseDetail">
+        <div class="device-detail-body" v-if="selectedDevice">
+          <div class="detail-top-row">
+            <div class="detail-info-section">
+              <div class="detail-info-header">设备信息</div>
+              <div class="detail-info-grid">
+                <div class="info-item">
+                  <span class="info-label">设备编号</span>
+                  <span class="info-value">{{ selectedDevice.code }}</span>
+                </div>
+                <div class="info-item">
+                  <span class="info-label">设备名称</span>
+                  <span class="info-value">{{ selectedDevice.name }}</span>
+                </div>
+                <div class="info-item">
+                  <span class="info-label">设备分类</span>
+                  <span class="info-value">{{ selectedDevice.category }}</span>
+                </div>
+                <div class="info-item">
+                  <span class="info-label">型号规格</span>
+                  <span class="info-value">{{ selectedDevice.model }}</span>
+                </div>
+                <div class="info-item">
+                  <span class="info-label">安装位置</span>
+                  <span class="info-value">{{ selectedDevice.location }}</span>
+                </div>
+                <div class="info-item">
+                  <span class="info-label">安装日期</span>
+                  <span class="info-value">{{ selectedDevice.installDate }}</span>
+                </div>
+                <div class="info-item">
+                  <span class="info-label">运行状态</span>
+                  <span class="info-value">
+                    <el-tag :type="getDeviceStatusType(selectedDevice.status)" size="small" effect="light" round>
+                      {{ selectedDevice.statusText }}
+                    </el-tag>
+                  </span>
+                </div>
+                <div class="info-item">
+                  <span class="info-label">上次维保</span>
+                  <span class="info-value">{{ selectedDevice.lastMaintain }}</span>
+                </div>
+                <div class="info-item">
+                  <span class="info-label">下次维保</span>
+                  <span class="info-value">{{ selectedDevice.nextMaintain }}</span>
+                </div>
+              </div>
+            </div>
+            <div class="detail-image-section">
+              <div class="detail-image-frame">
+                <img :src="getDeviceImage(selectedDevice)" :alt="selectedDevice.name" class="detail-device-img" />
+              </div>
+              <div class="detail-params-box">
+                <div class="params-label">设备参数</div>
+                <div class="params-text">{{ getDeviceParams(selectedDevice) }}</div>
+              </div>
+            </div>
+          </div>
+          <div class="detail-bottom-row">
+            <div class="detail-chart-header">参数趋势</div>
+            <div class="detail-chart-tabs">
+              <span v-for="tab in chartTabs" :key="tab.key" class="chart-tab" :class="{ active: activeChartTab === tab.key }" @click="switchChartTab(tab.key)">{{ tab.label }}</span>
+            </div>
+            <div class="detail-chart-body">
+              <div class="param-summary-row">
+                <div class="param-summary-item">
+                  <span class="ps-label">当前值</span>
+                  <span class="ps-value" :style="{ color: chartColors[activeChartTab] }">{{ currentChartValue }}</span>
+                </div>
+                <div class="param-summary-item">
+                  <span class="ps-label">最大值</span>
+                  <span class="ps-value" style="color:#ef4444">{{ maxChartValue }}</span>
+                </div>
+                <div class="param-summary-item">
+                  <span class="ps-label">最小值</span>
+                  <span class="ps-value" style="color:#3b82f6">{{ minChartValue }}</span>
+                </div>
+                <div class="param-summary-item">
+                  <span class="ps-label">平均值</span>
+                  <span class="ps-value" style="color:#10b981">{{ avgChartValue }}</span>
+                </div>
+              </div>
+              <div ref="deviceChartRef" style="width:100%;height:300px"></div>
+            </div>
+          </div>
+        </div>
+      </el-dialog>
+
       <!-- 维保记录 -->
       <el-tab-pane label="维保记录" name="maintain">
         <div class="tab-toolbar">
@@ -290,6 +379,7 @@
 
 <script>
 import { Search, Plus, Download, Minus } from '@element-plus/icons-vue'
+import * as echarts from 'echarts'
 
 export default {
   name: 'DeviceMaintainView',
@@ -297,6 +387,22 @@ export default {
   data() {
     return {
       activeTab: 'archive',
+      // 设备详情弹窗
+      showDeviceDetail: false,
+      selectedDevice: null,
+      chartTabs: [
+        { key: 'temperature', label: '温度' },
+        { key: 'stress', label: '应力' },
+        { key: 'displacement', label: '位移' },
+        { key: 'voltage', label: '电压' }
+      ],
+      activeChartTab: 'temperature',
+      chartColors: { temperature: '#62f6fb', stress: '#f97316', displacement: '#22c55e', voltage: '#a78bfa' },
+      chartInstance: null,
+      currentChartValue: '-',
+      maxChartValue: '-',
+      minChartValue: '-',
+      avgChartValue: '-',
       // 统计卡片
       statsCards: [
         { title: '设备总数', value: '156', icon: '📡', iconBg: 'linear-gradient(135deg, #dbeafe, #93c5fd)' },
@@ -388,7 +494,88 @@ export default {
       return { pending: 'info', processing: 'warning', completed: 'success' }[status] || 'info'
     },
     handleAddDevice() { console.log('新增设备') },
-    handleViewDevice(row) { console.log('查看设备:', row) },
+    handleViewDevice(row) {
+      this.selectedDevice = row
+      this.showDeviceDetail = true
+      this.activeChartTab = 'temperature'
+      this.$nextTick(() => this.initDeviceChart())
+    },
+    handleCloseDetail() {
+      if (this.chartInstance) {
+        this.chartInstance.dispose()
+        this.chartInstance = null
+      }
+      this.selectedDevice = null
+    },
+    switchChartTab(key) {
+      this.activeChartTab = key
+      this.$nextTick(() => this.initDeviceChart())
+    },
+    getDeviceParams(dev) {
+      const params = {
+        'WL-001': '量程: 0-30m, 精度: 0.1%FS, 输出: 4-20mA',
+        'WL-002': '量程: 0-30m, 精度: 0.1%FS, 输出: 4-20mA',
+        'SP-001': '量程: 0-2MPa, 精度: 0.5%FS, 防护: IP68',
+        'GT-001': '启闭力: 3000kN, 行程: 8m, 功率: 45kW',
+        'FL-001': '量程: 0-50m³/s, 精度: 1.0%, 输出: RS485',
+        'VD-001': '分辨率: 4K, 焦距: 6-22mm, 红外: 50m',
+        'DM-001': '量程: 0-100mm, 精度: 0.01mm, 输出: RS485',
+        'WT-001': '风速: 0-60m/s, 气温: -40~60°C, 雨量: 0-8mm/min'
+      }
+      return params[dev.code] || '—'
+    },
+    getDeviceImage(dev) {
+      return '/src/assets/images/Heilin/image.png'
+    },
+    initDeviceChart() {
+      if (!echarts) return
+      const el = this.$refs.deviceChartRef
+      if (!el) return
+      if (this.chartInstance) this.chartInstance.dispose()
+      this.chartInstance = echarts.init(el)
+      const seed = this.selectedDevice ? this.selectedDevice.name.charCodeAt(0) + this.selectedDevice.name.length : 42
+      const dataPoints = 168
+      const timeList = []
+      const data = []
+      for (let i = 0; i < dataPoints; i++) {
+        const d = new Date(Date.now() - (dataPoints - i) * 60 * 60 * 1000)
+        const pad = n => String(n).padStart(2, '0')
+        timeList.push((d.getMonth() + 1) + '/' + pad(d.getDate()) + ' ' + pad(d.getHours()) + ':00')
+        let val
+        switch (this.activeChartTab) {
+          case 'temperature':
+            val = +(22 + 5 * Math.sin(i * 0.15 + seed) + 3 * Math.cos(i * 0.05) + (Math.random() - 0.5) * 2).toFixed(1); break
+          case 'stress':
+            val = +(1.8 + 0.4 * Math.cos(i * 0.08 + seed) + 0.3 * Math.sin(i * 0.12) + (Math.random() - 0.5) * 0.3).toFixed(3); break
+          case 'displacement':
+            val = +(12.5 + 0.8 * Math.sin(i * 0.1 + seed) + 0.5 * Math.cos(i * 0.07) + (Math.random() - 0.5) * 0.4).toFixed(2); break
+          case 'voltage':
+            val = +(24.0 + 0.5 * Math.cos(i * 0.12 + seed) + 0.3 * Math.sin(i * 0.09) + (Math.random() - 0.5) * 0.5).toFixed(2); break
+          default: val = 0
+        }
+        data.push(val)
+      }
+      this.currentChartValue = data[data.length - 1]
+      this.maxChartValue = Math.max(...data).toFixed(2)
+      this.minChartValue = Math.min(...data).toFixed(2)
+      this.avgChartValue = (data.reduce((a, b) => a + b, 0) / data.length).toFixed(2)
+      const labelInterval = Math.max(1, Math.floor(dataPoints / 12))
+      const unitMap = { temperature: '℃', stress: 'MPa', displacement: 'mm', voltage: 'V' }
+      this.chartInstance.setOption({
+        animation: false, tooltip: { trigger: 'axis' },
+        grid: { left: 50, right: 20, top: 20, bottom: 30 },
+        xAxis: { type: 'category', boundaryGap: false, data: timeList, axisLine: { lineStyle: { color: '#e5e7eb' } }, axisLabel: { color: '#94a3b8', fontSize: 10, interval: labelInterval } },
+        yAxis: { type: 'value', name: unitMap[this.activeChartTab], nameTextStyle: { color: '#94a3b8', fontSize: 11 }, splitLine: { lineStyle: { color: 'rgba(0,0,0,0.04)' } }, axisLabel: { color: '#94a3b8', fontSize: 10 } },
+        dataZoom: [{ type: 'inside', start: 0, end: 100 }],
+        series: [{
+          type: 'line', smooth: true, symbol: 'none', data: data,
+          lineStyle: { width: 2, color: this.chartColors[this.activeChartTab] },
+          itemStyle: { color: this.chartColors[this.activeChartTab] },
+          areaStyle: { color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ offset: 0, color: this.chartColors[this.activeChartTab] + '33' }, { offset: 1, color: this.chartColors[this.activeChartTab] + '05' }]) }
+        }]
+      })
+      this.chartInstance.resize()
+    },
     handleEditDevice(row) { console.log('编辑设备:', row) },
     handleDeleteDevice(row) { console.log('删除设备:', row) },
     handleExport(type) { console.log('导出:', type) },
@@ -552,6 +739,55 @@ export default {
   font-weight: 600;
 }
 
+/* ==================== 设备详情弹窗 ==================== */
+.device-detail-body {
+  display: flex; flex-direction: column; gap: 20px;
+}
+.detail-top-row { display: flex; gap: 20px; }
+.detail-info-section { flex: 1; }
+.detail-info-header {
+  font-size: 15px; font-weight: 600; color: #1e293b;
+  margin-bottom: 12px; padding-bottom: 8px; border-bottom: 2px solid #3b82f6;
+}
+.detail-info-grid {
+  display: grid; grid-template-columns: 1fr 1fr; gap: 10px 20px;
+}
+.info-item { display: flex; flex-direction: column; gap: 2px; }
+.info-label { font-size: 11px; color: #94a3b8; }
+.info-value { font-size: 14px; font-weight: 500; color: #1e293b; }
+.detail-image-section {
+  width: 220px; flex-shrink: 0; display: flex; flex-direction: column; gap: 10px;
+}
+.detail-image-frame {
+  width: 220px; height: 150px; border-radius: 10px; overflow: hidden;
+  border: 1px solid #e2e8f0; background: #f8fafc;
+  display: flex; align-items: center; justify-content: center;
+}
+.detail-device-img { width: 100%; height: 100%; object-fit: contain; }
+.detail-params-box {
+  background: #f8fafc; border-radius: 8px; padding: 10px 12px;
+}
+.params-label { font-size: 11px; font-weight: 600; color: #64748b; margin-bottom: 4px; }
+.params-text { font-size: 12px; color: #1e293b; line-height: 1.5; }
+.detail-bottom-row { background: #fafbfc; border-radius: 10px; padding: 14px; }
+.detail-chart-header { font-size: 15px; font-weight: 600; color: #1e293b; margin-bottom: 10px; }
+.detail-chart-tabs { display: flex; gap: 4px; margin-bottom: 10px; }
+.chart-tab {
+  padding: 4px 14px; font-size: 12px; color: #64748b;
+  background: #f1f5f9; border-radius: 14px; cursor: pointer; transition: all 0.2s;
+}
+.chart-tab:hover { background: #e2e8f0; }
+.chart-tab.active { background: #3b82f6; color: #fff; }
+.param-summary-row { display: flex; gap: 12px; margin-bottom: 10px; }
+.param-summary-item {
+  flex: 1; background: #fff; border-radius: 8px; padding: 8px 10px;
+  display: flex; flex-direction: column; align-items: center; gap: 2px;
+  border: 1px solid #e2e8f0;
+}
+.ps-label { font-size: 11px; color: #94a3b8; }
+.ps-value { font-size: 18px; font-weight: 700; }
+.detail-chart-body { flex: 1; }
+
 /* ==================== 分页 ==================== */
 .pagination-wrap {
   display: flex;

+ 1 - 75
src/views/admin/GateControlAdminView.vue

@@ -88,43 +88,6 @@
               </div>
             </div>
           </div>
-          <!-- 右:控制区 -->
-          <div class="gate-controls">
-            <div class="control-section">
-              <div class="control-title">开度调节</div>
-              <div class="slider-area">
-                <el-slider v-model="gate1.sliderVal" :min="0" :max="100" :step="5"
-                  :disabled="gate1.isLocked" show-input size="small" />
-              </div>
-              <div class="preset-btns">
-                <el-button size="small" :type="gate1.sliderVal === 0 ? 'danger' : ''" @click="gate1.sliderVal = 0">全关</el-button>
-                <el-button size="small" @click="gate1.sliderVal = 25">25%</el-button>
-                <el-button size="small" @click="gate1.sliderVal = 50">50%</el-button>
-                <el-button size="small" @click="gate1.sliderVal = 75">75%</el-button>
-                <el-button size="small" :type="gate1.sliderVal === 100 ? 'success' : ''" @click="gate1.sliderVal = 100">全开</el-button>
-              </div>
-            </div>
-            <div class="control-actions">
-              <el-button type="primary" size="default" :disabled="gate1.isLocked || gate1.sliderVal === gate1.openDegree"
-                @click="confirmExecGate(gate1, gate1.sliderVal)" :loading="gate1.executing">
-                <el-icon><Switch /></el-icon> 执行开度
-              </el-button>
-              <el-button type="danger" size="default" plain :disabled="gate1.openDegree === 0 || gate1.isLocked"
-                @click="handleEmergencyClose(gate1)">
-                <el-icon><WarningFilled /></el-icon> 紧急关闭
-              </el-button>
-            </div>
-            <div class="control-meta">
-              <div class="meta-item">
-                <span class="meta-label">上次操作</span>
-                <span class="meta-val">{{ gate1.lastOpTime }}</span>
-              </div>
-              <div class="meta-item">
-                <span class="meta-label">操作人</span>
-                <span class="meta-val">{{ gate1.lastOperator }}</span>
-              </div>
-            </div>
-          </div>
         </div>
         <!-- 底部运行日志简表 -->
         <div class="gate-footer">
@@ -193,42 +156,6 @@
               </div>
             </div>
           </div>
-          <div class="gate-controls">
-            <div class="control-section">
-              <div class="control-title">开度调节</div>
-              <div class="slider-area">
-                <el-slider v-model="gate2.sliderVal" :min="0" :max="100" :step="5"
-                  :disabled="gate2.isLocked" show-input size="small" />
-              </div>
-              <div class="preset-btns">
-                <el-button size="small" :type="gate2.sliderVal === 0 ? 'danger' : ''" @click="gate2.sliderVal = 0">全关</el-button>
-                <el-button size="small" @click="gate2.sliderVal = 25">25%</el-button>
-                <el-button size="small" @click="gate2.sliderVal = 50">50%</el-button>
-                <el-button size="small" @click="gate2.sliderVal = 75">75%</el-button>
-                <el-button size="small" :type="gate2.sliderVal === 100 ? 'success' : ''" @click="gate2.sliderVal = 100">全开</el-button>
-              </div>
-            </div>
-            <div class="control-actions">
-              <el-button type="primary" size="default" :disabled="gate2.isLocked || gate2.sliderVal === gate2.openDegree"
-                @click="confirmExecGate(gate2, gate2.sliderVal)" :loading="gate2.executing">
-                <el-icon><Switch /></el-icon> 执行开度
-              </el-button>
-              <el-button type="warning" size="default" plain :disabled="gate2.isLocked"
-                @click="handlePause(gate2)">
-                <el-icon><VideoPause /></el-icon> 暂停保持
-              </el-button>
-            </div>
-            <div class="control-meta">
-              <div class="meta-item">
-                <span class="meta-label">上次操作</span>
-                <span class="meta-val">{{ gate2.lastOpTime }}</span>
-              </div>
-              <div class="meta-item">
-                <span class="meta-label">操作人</span>
-                <span class="meta-val">{{ gate2.lastOperator }}</span>
-              </div>
-            </div>
-          </div>
         </div>
         <div class="gate-footer">
           <span class="footer-title">近期操作记录</span>
@@ -614,7 +541,7 @@ export default {
 .gate-body {
   padding: 16px; display: flex; gap: 20px; flex: 1;
 }
-.gate-params { flex: 1; display: flex; flex-direction: column; gap: 8px; }
+.gate-params { width: 100%; display: flex; flex-direction: column; gap: 8px; }
 .param-row { display: flex; gap: 12px; }
 .param-item { flex: 1; display: flex; flex-direction: column; }
 .param-label { font-size: 11px; color: #94a3b8; }
@@ -633,7 +560,6 @@ export default {
 .ind-warn { font-size: 10px; color: #ef4444; font-weight: 600; margin-left: auto; }
 
 /* 控制区 */
-.gate-controls { width: 320px; flex-shrink: 0; display: flex; flex-direction: column; gap: 12px; }
 .control-section { }
 .control-title { font-size: 12px; font-weight: 600; color: #64748b; margin-bottom: 6px; }
 .slider-area { padding: 0 4px; }

+ 3 - 6
src/views/admin/SysRoleView.vue

@@ -199,7 +199,6 @@ export default {
           name: '水雨情监测', checked: true, indeterminate: false,
           actions: [
             { label: '实时监测', checked: true },
-            { label: '水情地图', checked: true },
             { label: '历史数据', checked: true },
             { label: '水情预报', checked: false }
           ]
@@ -207,9 +206,8 @@ export default {
         {
           name: '水资源调度', checked: false, indeterminate: false,
           actions: [
-            { label: '调度总览', checked: false },
-            { label: '灌溉供水', checked: false },
-            { label: '调度计划', checked: false }
+            { label: '供水水量', checked: false },
+            { label: '生态补水', checked: false }
           ]
         },
         {
@@ -224,8 +222,7 @@ export default {
           actions: [
             { label: '工程档案', checked: true },
             { label: '调令文件', checked: true },
-            { label: '全生命周期', checked: true },
-            { label: '智能报表', checked: false }
+            { label: '全生命周期', checked: true }
           ]
         },
         {

File diff ditekan karena terlalu besar
+ 252 - 621
src/views/admin/WaterResourceAllocationView.vue


+ 411 - 186
src/views/mainPages/EngineeringSafetyView.vue

@@ -1,10 +1,12 @@
-<!-- 工程安全运维页面:温度应力卡片 + 设备监控面板 -->
+<!-- 工程安全运维页面:报警数据 + 设备监控面板(右侧整合) -->
 <template>
   <div class="safety-container">
     <div class="safety-scroll-area">
       <div class="tab-content">
+        <!-- ========== 左侧面板 ========== -->
         <div class="left-sidebar">
-          <div class="data-card tall-card">
+          <!-- 安全状态评估 -->
+          <div class="data-card">
             <div class="card-header">
               <h3 class="card-title">安全状态评估</h3>
             </div>
@@ -55,6 +57,147 @@
                   <span class="safety-eval-time">最近巡检 2026-05-28</span>
                 </div>
               </div>
+            </div>
+          </div>
+
+          <!-- ===== 数据框2:坝体整体变形安全 ===== -->
+          <div class="data-card mt-10">
+            <div class="card-header">
+              <h3 class="card-title">坝体整体变形安全</h3>
+            </div>
+            <div class="card-body chart-body">
+              <div class="deform-section">
+                <div class="conclusion-row">
+                  <span class="conclusion-row-label">整体变形状态判定</span>
+                  <span class="conclusion-row-value text-green">稳定</span>
+                </div>
+                <div class="deform-metrics">
+                  <div class="metric-item">
+                    <span class="metric-item-label">坝顶最大水平位移</span>
+                    <span class="metric-item-value">12.6<span class="metric-item-unit">mm</span></span>
+                    <span class="metric-item-tag tag-ok">正常</span>
+                  </div>
+                  <div class="metric-item">
+                    <span class="metric-item-label">坝体累计垂直沉降</span>
+                    <span class="metric-item-value">8.3<span class="metric-item-unit">mm</span></span>
+                    <span class="metric-item-tag tag-ok">正常</span>
+                  </div>
+                </div>
+                <div class="deform-rate">
+                  <span class="rate-label">形变速率判定</span>
+                  <span class="rate-tag tag-ok">匀速稳定</span>
+                  <span class="rate-hint">速率 0.02mm/d</span>
+                </div>
+                <div class="deform-trend">
+                  <span class="trend-label">24h整体形变趋势</span>
+                  <div class="trend-chart-box">
+                    <canvas id="deformTrendChart" width="290" height="42"></canvas>
+                  </div>
+                </div>
+              </div>
+            </div>
+          </div>
+
+          <!-- ===== 数据框3:坝体渗流防渗安全 ===== -->
+          <div class="data-card mt-10">
+            <div class="card-header">
+              <h3 class="card-title">坝体渗流防渗安全</h3>
+            </div>
+            <div class="card-body chart-body">
+              <div class="seepage-section">
+                <div class="conclusion-row">
+                  <span class="conclusion-row-label">渗流整体安全状态</span>
+                  <span class="conclusion-row-value text-green">防渗正常</span>
+                </div>
+                <div class="deform-metrics">
+                  <div class="metric-item">
+                    <span class="metric-item-label">坝基典型扬压力均值</span>
+                    <span class="metric-item-value">36.8<span class="metric-item-unit">kPa</span></span>
+                    <span class="metric-item-tag tag-ok">正常</span>
+                  </div>
+                  <div class="metric-item">
+                    <span class="metric-item-label">坝基平均渗流量</span>
+                    <span class="metric-item-value">2.4<span class="metric-item-unit">L/s</span></span>
+                    <span class="metric-item-tag tag-ok">正常</span>
+                  </div>
+                </div>
+                <div class="deform-rate">
+                  <span class="rate-label">渗流稳定性判定</span>
+                  <span class="rate-tag tag-ok">平稳无波动</span>
+                </div>
+                <div class="balance-row">
+                  <span class="balance-row-label">绕坝渗流左右岸平衡</span>
+                  <div class="balance-bars">
+                    <div class="balance-bar-line">
+                      <span class="balance-bar-side">左岸</span>
+                      <div class="balance-track"><div class="balance-fill" style="width:48%"></div></div>
+                      <span class="balance-bar-val">48%</span>
+                    </div>
+                    <div class="balance-bar-line">
+                      <span class="balance-bar-side">右岸</span>
+                      <div class="balance-track"><div class="balance-fill fill-right" style="width:52%"></div></div>
+                      <span class="balance-bar-val">52%</span>
+                    </div>
+                  </div>
+                  <span class="balance-result tag-ok">均衡</span>
+                </div>
+              </div>
+            </div>
+          </div>
+
+          <!-- 巡检记录 -->
+          <div class="data-card mt-10">
+            <div class="card-header">
+              <h3 class="card-title">巡检记录</h3>
+            </div>
+            <div class="card-body card-body-tight">
+              <!-- 今日巡检统计 -->
+              <div class="patrol-stats-row">
+                <div class="patrol-stat-item">
+                  <span class="patrol-stat-num">24</span>
+                  <span class="patrol-stat-label">今日应巡检</span>
+                </div>
+                <div class="patrol-stat-item">
+                  <span class="patrol-stat-num" style="color:#22c55e">18</span>
+                  <span class="patrol-stat-label">已完成</span>
+                </div>
+                <div class="patrol-stat-item">
+                  <span class="patrol-stat-num" style="color:#f59e0b">6</span>
+                  <span class="patrol-stat-label">未完成</span>
+                </div>
+                <div class="patrol-stat-item">
+                  <span class="patrol-stat-num" style="color:#ef4444">2</span>
+                  <span class="patrol-stat-label">异常发现</span>
+                </div>
+              </div>
+              <!-- 最近巡检列表 -->
+              <div class="monitor-subtitle" style="margin:4px 0;">最近巡检</div>
+              <div class="patrol-list">
+                <div v-for="item in patrolRecords" :key="item.id" class="patrol-row">
+                  <div class="patrol-row-left">
+                    <span class="patrol-row-time">{{ item.time }}</span>
+                    <span class="patrol-row-point">{{ item.point }}</span>
+                  </div>
+                  <div class="patrol-row-right">
+                    <span class="patrol-row-person">{{ item.person }}</span>
+                    <span :class="['patrol-row-status', item.status === '正常' ? 'status-normal' : 'status-abnormal']">{{ item.status }}</span>
+                  </div>
+                </div>
+              </div>
+            </div>
+          </div>
+
+        </div>
+
+        <!-- ========== 右侧面板 ========== -->
+        <div class="right-sidebar">
+          <!-- 设备安全(顶部整合监控摘要 + 仪表盘 + 阈值报警 + 设备清单) -->
+          <div class="data-card">
+            <div class="card-header">
+              <h3 class="card-title">设备安全</h3>
+            </div>
+            <div class="card-body card-body-tight">
+              <!-- 设备完好率 + 仪表盘 -->
               <div class="device-stats-row">
                 <div class="device-stat-card">
                   <div class="device-stat-percent">89.55%</div>
@@ -70,9 +213,8 @@
                   <div class="device-stat-label">运行期 完好率</div>
                 </div>
               </div>
-            </div>
-            <div class="monitor-divider"></div>
-            <div class="card-body card-body-tight">
+
+              <!-- 监控摘要卡片 -->
               <div class="monitor-summary-row">
                 <div class="monitor-summary-card" :class="{ active: activeSummaryCard === item.name }" v-for="item in monitorSummaryList" :key="item.name" @click="toggleSummaryCard(item.name)">
                   <svg class="progress-ring" width="48" height="48" viewBox="0 0 48 48">
@@ -89,9 +231,53 @@
                 </div>
               </div>
               <div class="summary-pie-area" v-if="activeSummaryCard">
-                <canvas :id="'summaryPieChart'" width="290" height="200"></canvas>
+                <canvas id="summaryPieChart" width="290" height="160"></canvas>
+              </div>
+
+              <!-- 阈值报警信息 -->
+              <div class="monitor-divider"></div>
+              <div class="threshold-summary">
+                <div class="threshold-stat">
+                  <span class="threshold-stat-value">6</span>
+                  <span class="threshold-stat-label">超阈值设备</span>
+                </div>
+                <div class="threshold-stat">
+                  <span class="threshold-stat-value" style="color:#fbbf24;">3</span>
+                  <span class="threshold-stat-label">临界设备</span>
+                </div>
+                <div class="threshold-stat">
+                  <span class="threshold-stat-value" style="color:#22c55e;">128</span>
+                  <span class="threshold-stat-label">正常设备</span>
+                </div>
+              </div>
+              <div class="monitor-subtitle" style="margin:4px 0;">实时超阈值列表</div>
+              <div class="alarm-scroll-list">
+                <div v-for="item in thresholdAlarms" :key="item.id" class="threshold-item" :class="`threshold-${item.level}`">
+                  <div class="threshold-item-header">
+                    <span class="threshold-device">{{ item.device }}</span>
+                    <span :class="['threshold-tag', item.level === 'critical' ? 'tag-critical' : 'tag-warning']">{{ item.level === 'critical' ? '紧急' : '警告' }}</span>
+                  </div>
+                  <div class="threshold-item-body">
+                    <div class="threshold-metric">
+                      <span class="tm-label">阈值</span>
+                      <span class="tm-value">{{ item.threshold }}</span>
+                    </div>
+                    <div class="threshold-metric">
+                      <span class="tm-label">当前值</span>
+                      <span class="tm-value" :style="{ color: item.level === 'critical' ? '#ef4444' : '#fbbf24' }">{{ item.current }}</span>
+                    </div>
+                    <div class="threshold-metric">
+                      <span class="tm-label">超限</span>
+                      <span class="tm-value" :style="{ color: item.level === 'critical' ? '#ef4444' : '#fbbf24' }">{{ item.over }}%</span>
+                    </div>
+                  </div>
+                  <div class="threshold-item-time">{{ item.time }}</div>
+                </div>
               </div>
-              <div class="monitor-subtitle">设备清单</div>
+
+              <!-- 设备清单树 -->
+              <div class="monitor-divider"></div>
+              <div class="monitor-subtitle" style="margin:4px 0;">设备清单</div>
               <div class="tree-search-bar">
                 <svg class="tree-search-icon" viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="#7bbef6" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="10.5" cy="10.5" r="7.5"/><line x1="16" y1="16" x2="22" y2="22"/></svg>
                 <input class="tree-search-input" v-model="searchKey" placeholder="请输入关键词" />
@@ -165,7 +351,7 @@
                             </div>
                           </div>
                           <div class="tree-devices" v-if="pt.children && pt.expanded" v-for="dev in pt.children" :key="dev.name">
-                            <div class="tree-node-row tree-leaf" @click.stop="openDevicePanel(dev, grand, loc, pt, child)">
+                            <div class="tree-node-row tree-leaf">
                               <span class="tree-dot"></span>
                               <span class="tree-node-label tree-node-bold" style="color:#62f6fb;">{{ dev.name }}</span>
                               <div class="tree-node-actions">
@@ -183,20 +369,6 @@
             </div>
           </div>
         </div>
-        <div class="middle-area">
-          <TempStressCard
-            :device="selectedDevice"
-            :breadcrumb="deviceBreadcrumb"
-            :visible="!!selectedDevice"
-            @close="closeTempCard"
-          />
-        </div>
-        <div class="right-sidebar">
-          <DeviceRightPanel
-            :device="selectedDevice"
-            :breadcrumb="deviceBreadcrumb"
-          />
-        </div>
       </div>
     </div>
 
@@ -204,13 +376,40 @@
 </template>
 <script>
 import * as echarts from "echarts";
-import TempStressCard from "../../components/TempStressCard.vue";
-import DeviceRightPanel from "../../components/DeviceRightPanel.vue";
 export default {
   name: "EngineeringSafetyView",
-  components: { TempStressCard, DeviceRightPanel },
   data() {
     return {
+      // 监控摘要
+      activeSummaryCard: "变形检测",
+      summaryPieChart: null,
+      deviceGaugeChart: null,
+      monitorSummaryList: [
+        { name: "变形检测", count: 42, progress: 82, color: "#62f6fb" },
+        { name: "渗流渗压", count: 28, progress: 65, color: "#a78bfa" },
+        { name: "应力应变", count: 16, progress: 45, color: "#fbbf24" },
+      ],
+      summaryPieMap: {
+        "变形检测": [
+          { name: "精密水准", value: 12, color: "#62f6fb" },
+          { name: "基岩变形计", value: 10, color: "#34d399" },
+          { name: "电磁沉降环", value: 8, color: "#fbbf24" },
+          { name: "测缝计", value: 7, color: "#f97316" },
+          { name: "多点位移计", value: 5, color: "#ef4444" },
+        ],
+        "渗流渗压": [
+          { name: "渗压计", value: 10, color: "#a78bfa" },
+          { name: "量水堰", value: 7, color: "#818cf8" },
+          { name: "测压管", value: 6, color: "#c084fc" },
+          { name: "孔隙水压力计", value: 5, color: "#e879f9" },
+        ],
+        "应力应变": [
+          { name: "钢筋计", value: 6, color: "#fbbf24" },
+          { name: "应变计", value: 5, color: "#f59e0b" },
+          { name: "无应力计", value: 5, color: "#f97316" },
+        ],
+      },
+      // 设备清单树
       searchKey: "",
       treeData: [
         {
@@ -219,119 +418,31 @@ export default {
               name: "主坝", expanded: true, children: [
                 {
                   name: "变形监测", expanded: true, children: [
-                    {
-                      name: "坝顶", children: [
-                        { name: "坝顶水平位移-01", children: [{ name: "R201YL1" }, { name: "R201YL2" }, { name: "R201YL3" }] },
-                        { name: "坝顶水平位移-02", children: [{ name: "R201YL4" }, { name: "R201YL5" }, { name: "R201YL6" }] },
-                        { name: "坝顶水平位移-03", children: [{ name: "R201YL7" }, { name: "R201YL8" }, { name: "R201YL9" }] },
-                        { name: "坝顶水平位移-04", children: [{ name: "R201YL10" }, { name: "R201YL11" }, { name: "R201YL12" }] },
-                        { name: "坝顶水平位移-05", children: [{ name: "R201YL13" }, { name: "R201YL14" }, { name: "R201YL15" }] },
-                      ],
-                    },
-                    {
-                      name: "坝基", children: [
-                        { name: "坝基垂直位移-01", children: [{ name: "B301YL1" }, { name: "B301YL2" }, { name: "B301YL3" }] },
-                        { name: "坝基垂直位移-02", children: [{ name: "B301YL4" }, { name: "B301YL5" }, { name: "B301YL6" }] },
-                        { name: "坝基垂直位移-03", children: [{ name: "B301YL7" }, { name: "B301YL8" }, { name: "B301YL9" }] },
-                        { name: "坝基垂直位移-04", children: [{ name: "B301YL10" }, { name: "B301YL11" }, { name: "B301YL12" }] },
-                        { name: "坝基垂直位移-05", children: [{ name: "B301YL13" }, { name: "B301YL14" }, { name: "B301YL15" }] },
-                        { name: "坝基垂直位移-06", children: [{ name: "B301YL16" }, { name: "B301YL17" }, { name: "B301YL18" }] },
-                      ],
-                    },
-                    {
-                      name: "左岸", children: [
-                        { name: "库岸变形-B01", children: [{ name: "K401YL1" }, { name: "K401YL2" }, { name: "K401YL3" }] },
-                        { name: "库岸变形-B02", children: [{ name: "K401YL4" }, { name: "K401YL5" }, { name: "K401YL6" }] },
-                        { name: "库岸变形-B03", children: [{ name: "K401YL7" }, { name: "K401YL8" }, { name: "K401YL9" }] },
-                        { name: "裂缝开合度-C01", children: [{ name: "F501YL1" }, { name: "F501YL2" }, { name: "F501YL3" }] },
-                        { name: "裂缝开合度-C02", children: [{ name: "F501YL4" }, { name: "F501YL5" }, { name: "F501YL6" }] },
-                      ],
-                    },
-                    {
-                      name: "右岸", children: [
-                        { name: "库岸变形-B04", children: [{ name: "K401YL10" }, { name: "K401YL11" }, { name: "K401YL12" }] },
-                        { name: "库岸变形-B05", children: [{ name: "K401YL13" }, { name: "K401YL14" }, { name: "K401YL15" }] },
-                        { name: "裂缝开合度-C03", children: [{ name: "F501YL7" }, { name: "F501YL8" }, { name: "F501YL9" }] },
-                      ],
-                    },
-                    {
-                      name: "坝肩", children: [
-                        { name: "坝肩位移-J01", children: [{ name: "J601YL1" }, { name: "J601YL2" }, { name: "J601YL3" }] },
-                        { name: "坝肩位移-J02", children: [{ name: "J601YL4" }, { name: "J601YL5" }, { name: "J601YL6" }] },
-                        { name: "精密水准-S01", children: [{ name: "S701YL1" }, { name: "S701YL2" }, { name: "S701YL3" }] },
-                      ],
-                    },
+                    { name: "坝顶", children: [{ name: "坝顶水平位移-01", children: [{ name: "R201YL1" }, { name: "R201YL2" }, { name: "R201YL3" }] }, { name: "坝顶水平位移-02", children: [{ name: "R201YL4" }, { name: "R201YL5" }, { name: "R201YL6" }] }, { name: "坝顶水平位移-03", children: [{ name: "R201YL7" }, { name: "R201YL8" }, { name: "R201YL9" }] }, { name: "坝顶水平位移-04", children: [{ name: "R201YL10" }, { name: "R201YL11" }, { name: "R201YL12" }] }, { name: "坝顶水平位移-05", children: [{ name: "R201YL13" }, { name: "R201YL14" }, { name: "R201YL15" }] }] },
+                    { name: "坝基", children: [{ name: "坝基垂直位移-01", children: [{ name: "B301YL1" }, { name: "B301YL2" }, { name: "B301YL3" }] }, { name: "坝基垂直位移-02", children: [{ name: "B301YL4" }, { name: "B301YL5" }, { name: "B301YL6" }] }, { name: "坝基垂直位移-03", children: [{ name: "B301YL7" }, { name: "B301YL8" }, { name: "B301YL9" }] }, { name: "坝基垂直位移-04", children: [{ name: "B301YL10" }, { name: "B301YL11" }, { name: "B301YL12" }] }, { name: "坝基垂直位移-05", children: [{ name: "B301YL13" }, { name: "B301YL14" }, { name: "B301YL15" }] }, { name: "坝基垂直位移-06", children: [{ name: "B301YL16" }, { name: "B301YL17" }, { name: "B301YL18" }] }] },
+                    { name: "左岸", children: [{ name: "库岸变形-B01", children: [{ name: "K401YL1" }, { name: "K401YL2" }, { name: "K401YL3" }] }, { name: "库岸变形-B02", children: [{ name: "K401YL4" }, { name: "K401YL5" }, { name: "K401YL6" }] }, { name: "库岸变形-B03", children: [{ name: "K401YL7" }, { name: "K401YL8" }, { name: "K401YL9" }] }, { name: "裂缝开合度-C01", children: [{ name: "F501YL1" }, { name: "F501YL2" }, { name: "F501YL3" }] }, { name: "裂缝开合度-C02", children: [{ name: "F501YL4" }, { name: "F501YL5" }, { name: "F501YL6" }] }] },
+                    { name: "右岸", children: [{ name: "库岸变形-B04", children: [{ name: "K401YL10" }, { name: "K401YL11" }, { name: "K401YL12" }] }, { name: "库岸变形-B05", children: [{ name: "K401YL13" }, { name: "K401YL14" }, { name: "K401YL15" }] }, { name: "裂缝开合度-C03", children: [{ name: "F501YL7" }, { name: "F501YL8" }, { name: "F501YL9" }] }] },
+                    { name: "坝肩", children: [{ name: "坝肩位移-J01", children: [{ name: "J601YL1" }, { name: "J601YL2" }, { name: "J601YL3" }] }, { name: "坝肩位移-J02", children: [{ name: "J601YL4" }, { name: "J601YL5" }, { name: "J601YL6" }] }, { name: "精密水准-S01", children: [{ name: "S701YL1" }, { name: "S701YL2" }, { name: "S701YL3" }] }] },
                   ],
                 },
                 {
                   name: "渗流监测", expanded: true, children: [
-                    {
-                      name: "坝基", children: [
-                        { name: "渗流压力-P01", children: [{ name: "P801YL1" }, { name: "P801YL2" }, { name: "P801YL3" }] },
-                        { name: "渗流压力-P02", children: [{ name: "P801YL4" }, { name: "P801YL5" }, { name: "P801YL6" }] },
-                        { name: "渗流压力-P03", children: [{ name: "P801YL7" }, { name: "P801YL8" }, { name: "P801YL9" }] },
-                        { name: "渗流压力-P04", children: [{ name: "P801YL10" }, { name: "P801YL11" }, { name: "P801YL12" }] },
-                        { name: "绕坝渗流-S01", children: [{ name: "R901YL1" }, { name: "R901YL2" }, { name: "R901YL3" }] },
-                        { name: "绕坝渗流-S02", children: [{ name: "R901YL4" }, { name: "R901YL5" }, { name: "R901YL6" }] },
-                      ],
-                    },
-                    {
-                      name: "坝体", children: [
-                        { name: "渗流压力-P05", children: [{ name: "P801YL13" }, { name: "P801YL14" }, { name: "P801YL15" }] },
-                        { name: "渗流压力-P06", children: [{ name: "P801YL16" }, { name: "P801YL17" }, { name: "P801YL18" }] },
-                        { name: "渗流压力-P07", children: [{ name: "P801YL19" }, { name: "P801YL20" }, { name: "P801YL21" }] },
-                        { name: "渗流压力-P08", children: [{ name: "P801YL22" }, { name: "P801YL23" }, { name: "P801YL24" }] },
-                      ],
-                    },
-                    {
-                      name: "廊道", children: [
-                        { name: "廊道渗流-L01", children: [{ name: "L011YL1" }, { name: "L011YL2" }, { name: "L011YL3" }] },
-                        { name: "廊道渗流-L02", children: [{ name: "L011YL4" }, { name: "L011YL5" }, { name: "L011YL6" }] },
-                        { name: "廊道渗流-L03", children: [{ name: "L011YL7" }, { name: "L011YL8" }, { name: "L011YL9" }] },
-                      ],
-                    },
+                    { name: "坝基", children: [{ name: "渗流压力-P01", children: [{ name: "P801YL1" }, { name: "P801YL2" }, { name: "P801YL3" }] }, { name: "渗流压力-P02", children: [{ name: "P801YL4" }, { name: "P801YL5" }, { name: "P801YL6" }] }, { name: "渗流压力-P03", children: [{ name: "P801YL7" }, { name: "P801YL8" }, { name: "P801YL9" }] }, { name: "渗流压力-P04", children: [{ name: "P801YL10" }, { name: "P801YL11" }, { name: "P801YL12" }] }, { name: "绕坝渗流-S01", children: [{ name: "R901YL1" }, { name: "R901YL2" }, { name: "R901YL3" }] }, { name: "绕坝渗流-S02", children: [{ name: "R901YL4" }, { name: "R901YL5" }, { name: "R901YL6" }] }] },
+                    { name: "坝体", children: [{ name: "渗流压力-P05", children: [{ name: "P801YL13" }, { name: "P801YL14" }, { name: "P801YL15" }] }, { name: "渗流压力-P06", children: [{ name: "P801YL16" }, { name: "P801YL17" }, { name: "P801YL18" }] }, { name: "渗流压力-P07", children: [{ name: "P801YL19" }, { name: "P801YL20" }, { name: "P801YL21" }] }, { name: "渗流压力-P08", children: [{ name: "P801YL22" }, { name: "P801YL23" }, { name: "P801YL24" }] }] },
+                    { name: "廊道", children: [{ name: "廊道渗流-L01", children: [{ name: "L011YL1" }, { name: "L011YL2" }, { name: "L011YL3" }] }, { name: "廊道渗流-L02", children: [{ name: "L011YL4" }, { name: "L011YL5" }, { name: "L011YL6" }] }, { name: "廊道渗流-L03", children: [{ name: "L011YL7" }, { name: "L011YL8" }, { name: "L011YL9" }] }] },
                   ],
                 },
                 {
                   name: "应力应变", expanded: true, children: [
-                    {
-                      name: "坝体", children: [
-                        { name: "钢筋应力-R01", children: [{ name: "G111YL1" }, { name: "G111YL2" }, { name: "G111YL3" }] },
-                        { name: "钢筋应力-R02", children: [{ name: "G111YL4" }, { name: "G111YL5" }, { name: "G111YL6" }] },
-                        { name: "钢筋应力-R03", children: [{ name: "G111YL7" }, { name: "G111YL8" }, { name: "G111YL9" }] },
-                        { name: "钢筋应力-R04", children: [{ name: "G111YL10" }, { name: "G111YL11" }, { name: "G111YL12" }] },
-                      ],
-                    },
-                    {
-                      name: "坝基", children: [
-                        { name: "基岩应力-Y01", children: [{ name: "J121YL1" }, { name: "J121YL2" }, { name: "J121YL3" }] },
-                        { name: "基岩应力-Y02", children: [{ name: "J121YL4" }, { name: "J121YL5" }, { name: "J121YL6" }] },
-                        { name: "基岩应力-Y03", children: [{ name: "J121YL7" }, { name: "J121YL8" }, { name: "J121YL9" }] },
-                      ],
-                    },
+                    { name: "坝体", children: [{ name: "钢筋应力-R01", children: [{ name: "G111YL1" }, { name: "G111YL2" }, { name: "G111YL3" }] }, { name: "钢筋应力-R02", children: [{ name: "G111YL4" }, { name: "G111YL5" }, { name: "G111YL6" }] }, { name: "钢筋应力-R03", children: [{ name: "G111YL7" }, { name: "G111YL8" }, { name: "G111YL9" }] }, { name: "钢筋应力-R04", children: [{ name: "G111YL10" }, { name: "G111YL11" }, { name: "G111YL12" }] }] },
+                    { name: "坝基", children: [{ name: "基岩应力-Y01", children: [{ name: "J121YL1" }, { name: "J121YL2" }, { name: "J121YL3" }] }, { name: "基岩应力-Y02", children: [{ name: "J121YL4" }, { name: "J121YL5" }, { name: "J121YL6" }] }, { name: "基岩应力-Y03", children: [{ name: "J121YL7" }, { name: "J121YL8" }, { name: "J121YL9" }] }] },
                   ],
                 },
                 {
                   name: "环境量监测", expanded: true, children: [
-                    {
-                      name: "库水位", children: [
-                        { name: "库水位-W01", children: [{ name: "W131YL1" }, { name: "W131YL2" }, { name: "W131YL3" }] },
-                        { name: "库水位-W02", children: [{ name: "W131YL4" }, { name: "W131YL5" }, { name: "W131YL6" }] },
-                      ],
-                    },
-                    {
-                      name: "降雨量", children: [
-                        { name: "雨量计-R01", children: [{ name: "Y141YL1" }, { name: "Y141YL2" }, { name: "Y141YL3" }] },
-                        { name: "雨量计-R02", children: [{ name: "Y141YL4" }, { name: "Y141YL5" }, { name: "Y141YL6" }] },
-                      ],
-                    },
-                    {
-                      name: "温度", children: [
-                        { name: "温度计-T01", children: [{ name: "T151YL1" }, { name: "T151YL2" }, { name: "T151YL3" }] },
-                        { name: "温度计-T02", children: [{ name: "T151YL4" }, { name: "T151YL5" }, { name: "T151YL6" }] },
-                        { name: "温度计-T03", children: [{ name: "T151YL7" }, { name: "T151YL8" }, { name: "T151YL9" }] },
-                      ],
-                    },
+                    { name: "库水位", children: [{ name: "库水位-W01", children: [{ name: "W131YL1" }, { name: "W131YL2" }, { name: "W131YL3" }] }, { name: "库水位-W02", children: [{ name: "W131YL4" }, { name: "W131YL5" }, { name: "W131YL6" }] }] },
+                    { name: "降雨量", children: [{ name: "雨量计-R01", children: [{ name: "Y141YL1" }, { name: "Y141YL2" }, { name: "Y141YL3" }] }, { name: "雨量计-R02", children: [{ name: "Y141YL4" }, { name: "Y141YL5" }, { name: "Y141YL6" }] }] },
+                    { name: "温度", children: [{ name: "温度计-T01", children: [{ name: "T151YL1" }, { name: "T151YL2" }, { name: "T151YL3" }] }, { name: "温度计-T02", children: [{ name: "T151YL4" }, { name: "T151YL5" }, { name: "T151YL6" }] }, { name: "温度计-T03", children: [{ name: "T151YL7" }, { name: "T151YL8" }, { name: "T151YL9" }] }] },
                   ],
                 },
               ],
@@ -339,36 +450,23 @@ export default {
           ],
         },
       ],
-      monitorSummaryList: [
-        { name: "变形检测", count: 42, progress: 82, color: "#62f6fb" },
-        { name: "渗流渗压", count: 28, progress: 65, color: "#a78bfa" },
-        { name: "应力应变", count: 16, progress: 45, color: "#fbbf24" },
+      // 报警数据
+      // 巡检记录
+      patrolRecords: [
+        { id: "PR01", time: "08:30", point: "坝顶水平位移-01", person: "张建国", status: "正常" },
+        { id: "PR02", time: "08:45", point: "坝基垂直位移-03", person: "张建国", status: "正常" },
+        { id: "PR03", time: "09:10", point: "渗流压力-P05", person: "李卫东", status: "正常" },
+        { id: "PR04", time: "09:30", point: "绕坝渗流-S01", person: "李卫东", status: "正常" },
+        { id: "PR05", time: "09:55", point: "钢筋应力-R01", person: "王振华", status: "异常" },
+        { id: "PR06", time: "10:20", point: "基岩应力-Y02", person: "王振华", status: "正常" },
+        { id: "PR07", time: "10:40", point: "库水位-W01", person: "张建国", status: "正常" },
+        { id: "PR08", time: "11:00", point: "裂缝开合度-C01", person: "张建国", status: "正常" },
       ],
-      summaryPieMap: {
-        "变形检测": [
-          { name: "精密水准", value: 12, color: "#62f6fb" },
-          { name: "基岩变形计", value: 10, color: "#34d399" },
-          { name: "电磁沉降环", value: 8, color: "#fbbf24" },
-          { name: "测缝计", value: 7, color: "#f97316" },
-          { name: "多点位移计", value: 5, color: "#ef4444" },
-        ],
-        "渗流渗压": [
-          { name: "渗压计", value: 10, color: "#a78bfa" },
-          { name: "量水堰", value: 7, color: "#818cf8" },
-          { name: "测压管", value: 6, color: "#c084fc" },
-          { name: "孔隙水压力计", value: 5, color: "#e879f9" },
-        ],
-        "应力应变": [
-          { name: "钢筋计", value: 6, color: "#fbbf24" },
-          { name: "应变计", value: 5, color: "#f59e0b" },
-          { name: "无应力计", value: 5, color: "#f97316" },
-        ],
-      },
-      activeSummaryCard: "变形检测",
-      summaryPieChart: null,
-      selectedDevice: null,
-      deviceBreadcrumb: "",
-      deviceGaugeChart: null,
+      thresholdAlarms: [
+        { id: "T001", device: "钢筋应力-R01-03", threshold: "200 MPa", current: "246 MPa", over: "23%", level: "critical", time: "2026-06-08 11:00" },
+        { id: "T002", device: "基岩应力-Y02-05", threshold: "150 MPa", current: "172 MPa", over: "14.7%", level: "critical", time: "2026-06-08 10:10" },
+      ],
+      deformTrendChart: null,
     };
   },
   computed: {
@@ -385,15 +483,18 @@ export default {
   },
   mounted() {
     this.$nextTick(() => {
-      this.initCharts();
+      this.initGaugeChart();
       this.renderSummaryPieChart();
+      this.renderDeformTrendChart();
     });
   },
   beforeUnmount() {
     if (this.summaryPieChart) this.summaryPieChart.dispose();
     if (this.deviceGaugeChart) this.deviceGaugeChart.dispose();
+    if (this.deformTrendChart) this.deformTrendChart.dispose();
   },
   methods: {
+    // --- 设备清单树 ---
     filterNode(node, kw) {
       if (!node.children) {
         return node.name.toLowerCase().includes(kw) ? { ...node } : null;
@@ -409,6 +510,7 @@ export default {
         node.expanded = !node.expanded;
       }
     },
+    // --- 监控摘要 ---
     toggleSummaryCard(name) {
       if (this.activeSummaryCard === name) {
         this.activeSummaryCard = null;
@@ -456,14 +558,8 @@ export default {
         }],
       });
     },
-    openDevicePanel(dev, grand, loc, pt, child) {
-      this.selectedDevice = dev;
-      this.deviceBreadcrumb = `${child.name} > ${grand.name} > ${loc.name} > ${pt.name} > ${dev.name}`;
-    },
-    closeTempCard() {
-      this.selectedDevice = null;
-    },
-    initCharts() {
+    // --- 仪表盘 ---
+    initGaugeChart() {
       if (!echarts) return;
       const gc = document.getElementById("deviceGaugeChart");
       if (gc) {
@@ -501,6 +597,42 @@ export default {
         });
       }
     },
+    // --- 24h整体形变趋势(中心线偏移) ---
+    renderDeformTrendChart() {
+      if (!echarts) return;
+      const el = document.getElementById("deformTrendChart");
+      if (!el) return;
+      if (this.deformTrendChart) this.deformTrendChart.dispose();
+      this.deformTrendChart = echarts.init(el, null, { renderer: "canvas" });
+      const hours = ["00", "02", "04", "06", "08", "10", "12", "14", "16", "18", "20", "22"];
+      // 以中心线为基准的偏移值(mm),正=偏右/上,负=偏左/下
+      const values = [0.02, 0.05, 0.07, 0.04, 0.08, 0.06, 0.03, 0.01, 0.05, 0.07, 0.04, -0.02];
+      this.deformTrendChart.setOption({
+        animation: false,
+        grid: { left: 0, right: 0, top: 0, bottom: 0 },
+        xAxis: { type: "category", data: hours, show: false },
+        yAxis: { type: "value", show: false, min: -0.1, max: 0.1 },
+        tooltip: { trigger: "axis", formatter: p => `偏移: ${p[0].value} mm`, textStyle: { fontSize: 11, color: "#e0fcff" }, backgroundColor: "rgba(0,20,40,0.85)", borderColor: "rgba(0,212,255,0.3)", borderWidth: 1, padding: [4, 8] },
+        series: [{
+          type: "bar",
+          barWidth: "50%",
+          data: values.map(v => ({
+            value: v,
+            itemStyle: {
+              color: v >= 0 ? "rgba(98,246,251,0.8)" : "rgba(239,68,68,0.7)",
+              borderRadius: v >= 0 ? [2, 2, 0, 0] : [0, 0, 2, 2],
+            },
+          })),
+          markLine: {
+            silent: true,
+            symbol: "none",
+            lineStyle: { color: "rgba(98,246,251,0.4)", width: 1, type: "dashed" },
+            label: { show: false },
+            data: [{ yAxis: 0 }],
+          },
+        }],
+      });
+    },
   },
 };
 </script>
@@ -512,18 +644,19 @@ export default {
 .safety-scroll-area::-webkit-scrollbar-thumb { background: rgba(0,212,255,0.3); border-radius: 2px; }
 .tab-content { width: 100%; display: flex; justify-content: space-between; padding: 0 20px; box-sizing: border-box; }
 .left-sidebar { width: 350px; flex-shrink: 0; pointer-events: auto; }
-.middle-area { flex: 1; margin: 0 10px; min-width: 0; display: flex; flex-direction: column; }
-.middle-area-content { margin-top: auto; }
-.right-sidebar { width: 350px; flex-shrink: 0; pointer-events: auto; }
+.right-sidebar { width: 380px; flex-shrink: 0; pointer-events: auto; }
 .mt-10 { margin-top: 10px; }
+
+/* ========== Data Card ========== */
 .data-card { width: 100%; background: rgba(0,20,40,0.7); border-radius: 4px; overflow: hidden; box-shadow: 0 0 10px rgba(0,212,255,0.2); }
-.card-header { height: 42px; background-image: url("/src/assets/images/长数据框标题.png"); background-size: 100% 100%; background-position: center; background-repeat: no-repeat; display: flex; align-items: flex-start; justify-content: space-between; padding: 4px 16px 0; }
+.card-header { height: 42px; background-image: url("/src/assets/images/数据小标题.png"); background-size: 100% 100%; background-position: center; background-repeat: no-repeat; display: flex; align-items: flex-start; justify-content: space-between; padding: 4px 16px 0; }
 .card-title { font-size: var(--fs-card-title); font-weight: bold; color: #e0fcff; margin: 0; text-shadow: 0 0 5px rgba(0,212,255,0.5); padding-left: 20px; }
 .card-body { padding: 8px; min-height: auto; font-size: 13px; line-height: 1.5; margin-top: -6px; }
 .card-body.chart-body { padding: 2px 8px 4px; }
-.card-body.card-body-tight { padding: 2px 8px 4px; }
-.device-stats-row { display: flex; gap: 4px; align-items: center; }
-.safety-eval-section { background: rgba(0,20,40,0.5); border-radius: 4px; border: 1px solid rgba(0,212,255,0.12); padding: 8px 10px; margin-bottom: 6px; min-height: 120px; display: flex; flex-direction: column; justify-content: space-between; }
+.card-body.card-body-tight { padding: 2px 8px 4px; height: 100%; }
+
+/* ========== Safety Evaluation ========== */
+.safety-eval-section { background: rgba(0,20,40,0.5); border-radius: 4px; border: 1px solid rgba(0,212,255,0.12); padding: 8px 10px; min-height: 120px; display: flex; flex-direction: column; justify-content: space-between; }
 .safety-eval-top { display: flex; justify-content: space-between; align-items: center; height: 30px; padding: 0 10px; border-radius: 3px; margin-bottom: 6px; background: #22c55e; }
 .safety-eval-section-title { color: #ffffff; font-size: 15px; }
 .safety-eval-grade { color: #ffffff; font-size: 16px; font-weight: bold; }
@@ -538,17 +671,122 @@ export default {
 .eval-item-tag { font-size: 10px; font-weight: bold; padding: 1px 8px; border-radius: 2px; }
 .eval-item-tag.tag-ok { color: #22c55e; background: rgba(34,197,94,0.15); }
 .eval-item-tag.tag-warn { color: #ffd93d; background: rgba(255,217,61,0.15); }
-.safety-eval-bot { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
+.safety-eval-bot { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-top: 4px; }
 .safety-eval-stat { display: flex; align-items: center; gap: 4px; color: #e0fcff; font-size: 10px; }
 .eval-stat-dot { width: 6px; height: 6px; border-radius: 50%; }
 .dot-ok { background: #22c55e; } .dot-warn { background: #ffd93d; } .dot-err { background: #ef4444; }
 .safety-eval-time { margin-left: auto; color: #7bbef6; font-size: 10px; white-space: nowrap; }
+
+/* ========== Device Stats + Gauge ========== */
+.device-stats-row { display: flex; gap: 4px; align-items: center; }
 .device-stat-card { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 4px; border-radius: 4px; padding: 8px 4px; }
 .device-stat-percent { color: #e0fcff; font-size: 20px; font-weight: bold; }
 .device-stat-icon { display: flex; align-items: center; justify-content: center; height: 36px; }
 .stat-icon-img { height: auto; width: auto; max-height: none; }
 .device-stat-label { color: #ffffff; font-size: 13px; white-space: nowrap; }
 .device-gauge-section { flex-shrink: 0; display: flex; flex-direction: column; align-items: center; margin: 0 2px; }
+
+/* ========== Monitor Summary ========== */
+.monitor-divider { height: 1px; background: rgba(0,212,255,0.15); margin: 4px 0; }
+.monitor-summary-row { display: flex; gap: 6px; margin-bottom: 4px; }
+.monitor-summary-card { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 2px; background: rgba(0,20,40,0.5); border-radius: 4px; border: 1px solid rgba(0,212,255,0.12); padding: 8px 4px; cursor: pointer; transition: all 0.2s; }
+.monitor-summary-card:hover { border-color: rgba(0,212,255,0.35); background: rgba(0,30,60,0.6); }
+.monitor-summary-card.active { border-color: rgba(0,212,255,0.6); background: rgba(0,40,80,0.7); box-shadow: 0 0 8px rgba(0,212,255,0.2); }
+.summary-pie-area { background: rgba(0,20,40,0.4); border-radius: 4px; border: 1px solid rgba(0,212,255,0.1); padding: 2px; margin-bottom: 4px; text-align: center; }
+.progress-ring-bg { fill: none; stroke: rgba(255,255,255,0.08); stroke-width: 3; }
+.progress-ring-fill { fill: none; stroke-width: 3; stroke-linecap: round; transform: rotate(-90deg); transform-origin: 24px 24px; }
+.monitor-summary-name { color: #7bbef6; font-size: 10px; }
+.monitor-summary-count { font-size: 18px; font-weight: bold; }
+
+/* ========== Patrol Record Card ========== */
+.patrol-stats-row { display: grid; grid-template-columns: 1fr 1fr 1fr 1fr; gap: 4px; margin-bottom: 6px; }
+.patrol-stat-item { display: flex; flex-direction: column; align-items: center; padding: 6px 2px; background: rgba(0,20,40,0.4); border-radius: 3px; border: 1px solid rgba(0,212,255,0.08); }
+.patrol-stat-num { font-size: 20px; font-weight: bold; color: #e0fcff; line-height: 1.2; }
+.patrol-stat-label { color: #7bbef6; font-size: 9px; margin-top: 2px; white-space: nowrap; }
+.patrol-list { max-height: 120px; overflow-y: auto; display: flex; flex-direction: column; gap: 2px; }
+.patrol-list::-webkit-scrollbar { width: 3px; }
+.patrol-list::-webkit-scrollbar-track { background: rgba(0,20,40,0.5); }
+.patrol-list::-webkit-scrollbar-thumb { background: rgba(0,212,255,0.3); border-radius: 2px; }
+.patrol-row { display: flex; align-items: center; justify-content: space-between; padding: 5px 8px; background: rgba(0,20,40,0.3); border-radius: 3px; border: 1px solid rgba(0,212,255,0.06); }
+.patrol-row-left { display: flex; align-items: center; gap: 8px; }
+.patrol-row-right { display: flex; align-items: center; gap: 6px; }
+.patrol-row-time { color: #7bbef6; font-size: 11px; flex-shrink: 0; }
+.patrol-row-point { color: #e0fcff; font-size: 11px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 120px; }
+.patrol-row-person { color: #7bbef6; font-size: 11px; }
+.patrol-row-status { font-size: 10px; font-weight: bold; padding: 0 6px; border-radius: 2px; line-height: 18px; }
+.patrol-row-status.status-normal { color: #22c55e; background: rgba(34,197,94,0.15); }
+.patrol-row-status.status-abnormal { color: #ef4444; background: rgba(239,68,68,0.15); }
+
+/* ========== Threshold Alarm ========== */
+.threshold-summary { display: flex; gap: 6px; margin-bottom: 4px; }
+.threshold-stat { flex: 1; display: flex; flex-direction: column; align-items: center; padding: 6px 4px; background: rgba(0,20,40,0.4); border-radius: 4px; border: 1px solid rgba(0,212,255,0.1); }
+.threshold-stat-value { font-size: 22px; font-weight: bold; color: #ef4444; line-height: 1.2; }
+.threshold-stat-label { font-size: 10px; color: #7bbef6; margin-top: 2px; }
+.threshold-item { padding: 5px 6px; border-radius: 3px; border: 1px solid transparent; margin-bottom: 3px; }
+.threshold-item.threshold-critical { background: rgba(239,68,68,0.08); border-color: rgba(239,68,68,0.2); }
+.threshold-item.threshold-warning { background: rgba(251,191,36,0.06); border-color: rgba(251,191,36,0.15); }
+.threshold-item-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 3px; }
+.threshold-device { color: #e0fcff; font-size: 11px; font-weight: bold; }
+.threshold-tag { font-size: 9px; padding: 0 5px; border-radius: 2px; line-height: 16px; }
+.tag-critical { background: rgba(239,68,68,0.2); color: #ef4444; }
+.tag-warning { background: rgba(251,191,36,0.2); color: #fbbf24; }
+.threshold-item-body { display: flex; gap: 4px; margin-bottom: 2px; }
+.threshold-metric { flex: 1; display: flex; flex-direction: column; align-items: center; padding: 2px 4px; background: rgba(0,20,40,0.3); border-radius: 2px; }
+.tm-label { color: #7bbef6; font-size: 9px; }
+.tm-value { color: #e0fcff; font-size: 11px; font-weight: bold; }
+.threshold-item-time { color: #7bbef6; font-size: 9px; text-align: right; }
+
+/* ========== Deformation & Seepage Section ========== */
+.deform-section,
+.seepage-section { background: rgba(0,20,40,0.5); border-radius: 4px; border: 1px solid rgba(0,212,255,0.12); padding: 8px 10px; min-height: 120px; display: flex; flex-direction: column; justify-content: space-between; gap: 6px; }
+
+/* Conclusion row (no background bar, text-only green) */
+.conclusion-row { display: flex; justify-content: space-between; align-items: center; padding: 4px 8px; background: rgba(0,20,40,0.3); border-radius: 3px; }
+.conclusion-row-label { color: #7bbef6; font-size: 13px; }
+.conclusion-row-value { font-size: 14px; font-weight: bold; }
+.conclusion-row-value.text-green { color: #22c55e; }
+
+/* Metrics (2-column grid) */
+.deform-metrics { display: grid; grid-template-columns: 1fr 1fr; gap: 4px; }
+.metric-item { display: flex; flex-direction: column; align-items: center; gap: 2px; padding: 6px 4px; background: rgba(0,20,40,0.4); border-radius: 3px; }
+.metric-item-label { color: #7bbef6; font-size: 11px; text-align: center; }
+.metric-item-value { color: #e0fcff; font-size: 20px; font-weight: bold; line-height: 1.2; }
+.metric-item-unit { color: #7bbef6; font-size: 12px; font-weight: normal; margin-left: 2px; }
+.metric-item-tag { font-size: 9px; padding: 0 6px; border-radius: 2px; line-height: 16px; }
+.metric-item-tag.tag-ok { color: #22c55e; background: rgba(34,197,94,0.15); }
+
+/* Rate row */
+.deform-rate { display: flex; align-items: center; gap: 8px; padding: 4px 8px; background: rgba(0,20,40,0.4); border-radius: 3px; }
+.rate-label { color: #7bbef6; font-size: 12px; }
+.rate-tag { font-size: 11px; font-weight: bold; padding: 1px 8px; border-radius: 2px; }
+.rate-tag.tag-ok { color: #22c55e; background: rgba(34,197,94,0.15); }
+.rate-hint { margin-left: auto; color: #7bbef6; font-size: 11px; }
+
+/* Trend chart */
+.deform-trend { display: flex; flex-direction: column; gap: 2px; }
+.trend-label { color: #7bbef6; font-size: 12px; padding-left: 2px; }
+.trend-chart-box { background: rgba(0,20,40,0.4); border-radius: 3px; border: 1px solid rgba(0,212,255,0.08); padding: 2px; }
+
+/* Balance row (seepage) */
+.balance-row { display: flex; flex-direction: column; gap: 4px; padding: 4px 8px; background: rgba(0,20,40,0.4); border-radius: 3px; }
+.balance-row-label { color: #7bbef6; font-size: 12px; }
+.balance-bars { display: flex; flex-direction: column; gap: 3px; }
+.balance-bar-line { display: flex; align-items: center; gap: 6px; }
+.balance-bar-side { color: #e0fcff; font-size: 11px; width: 28px; text-align: right; flex-shrink: 0; }
+.balance-track { flex: 1; height: 8px; background: rgba(255,255,255,0.08); border-radius: 4px; overflow: hidden; }
+.balance-fill { height: 100%; background: #62f6fb; border-radius: 4px; }
+.balance-fill.fill-right { background: #62f6fb; }
+.balance-bar-val { color: #e0fcff; font-size: 11px; width: 30px; text-align: left; flex-shrink: 0; }
+.balance-result { font-size: 11px; font-weight: bold; padding: 1px 8px; border-radius: 2px; align-self: flex-end; }
+.balance-result.tag-ok { color: #22c55e; background: rgba(34,197,94,0.15); }
+
+/* ========== Small Title ========== */
+.monitor-subtitle { color: #e0fcff; font-size: var(--fs-label); font-weight: bold; padding: 3px 16px 2px 22px; background-image: url("/src/assets/images/小标题.png"); background-size: 100% 100%; background-position: center; background-repeat: no-repeat; height: 24px; display: inline-flex; align-items: center; }
+
+canvas { display: block; margin: 0 auto; }
+canvas#summaryPieChart { display: flex !important; padding-left: 35px !important; padding-right: 35px !important; }
+
+/* ========== Tree ========== */
 .tree-search-bar { display: flex; align-items: center; gap: 6px; padding: 4px 8px; background: rgba(0,20,40,0.5); border: 1px solid rgba(0,212,255,0.15); border-radius: 4px; margin-bottom: 4px; }
 .tree-search-icon { flex-shrink: 0; }
 .tree-search-input { flex: 1; background: none; border: none; outline: none; color: #e0fcff; font-size: 12px; line-height: 26px; }
@@ -574,17 +812,4 @@ export default {
 .tree-locations { padding-left: 36px; }
 .tree-points { padding-left: 48px; }
 .tree-devices { padding-left: 60px; }
-.tall-card { height: calc(100% + 10px); min-height: 440px; }
-.monitor-divider { height: 1px; background: rgba(0,212,255,0.15); margin: 0 8px; }
-.monitor-subtitle { color: #e0fcff; font-size: var(--fs-label); font-weight: bold; padding: 3px 16px 2px 22px; background-image: url("/src/assets/images/小标题.png"); background-size: 100% 100%; background-position: center; background-repeat: no-repeat; height: 24px; display: inline-flex; align-items: center; margin-bottom: 2px; }
-.monitor-summary-row { display: flex; gap: 6px; margin-bottom: 4px; }
-.monitor-summary-card { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 2px; background: rgba(0,20,40,0.5); border-radius: 4px; border: 1px solid rgba(0,212,255,0.12); padding: 8px 4px; cursor: pointer; transition: all 0.2s; }
-.monitor-summary-card:hover { border-color: rgba(0,212,255,0.35); background: rgba(0,30,60,0.6); }
-.monitor-summary-card.active { border-color: rgba(0,212,255,0.6); background: rgba(0,40,80,0.7); box-shadow: 0 0 8px rgba(0,212,255,0.2); }
-.summary-pie-area { background: rgba(0,20,40,0.4); border-radius: 4px; border: 1px solid rgba(0,212,255,0.1); padding: 2px; margin-bottom: 2px; }
-.progress-ring-bg { fill: none; stroke: rgba(255,255,255,0.08); stroke-width: 3; }
-.progress-ring-fill { fill: none; stroke-width: 3; stroke-linecap: round; transform: rotate(-90deg); transform-origin: 24px 24px; }
-.monitor-summary-name { color: #7bbef6; font-size: 10px; }
-.monitor-summary-count { font-size: 18px; font-weight: bold; }
-canvas { display: block; margin: 0 auto; }
-</style>
+</style>

+ 38 - 32
src/views/mainPages/WorkspaceView.vue

@@ -4,10 +4,18 @@
     <!-- 顶部标题栏 -->
     <header class="oa-header">
       <div class="header-left">
-        <h1 class="system-title">乌拉海沟水库安全监测平台</h1>
+        <h1 class="system-title">乌拉海沟水库综合应用管理系统</h1>
         <el-tag type="primary" effect="dark" round size="small">工作台</el-tag>
       </div>
       <div class="header-right">
+        <el-tooltip content="返回大屏" placement="bottom">
+          <div class="back-bigscreen-btn" @click="$emit('backToDashboard')">
+            <svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+              <path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"></path>
+              <polyline points="9 22 9 12 15 12 15 22"></polyline>
+            </svg>
+          </div>
+        </el-tooltip>
         <el-input v-model="searchText" placeholder="搜索功能、工单、设备..." clearable class="header-search">
           <template #prefix>
             <el-icon><Search /></el-icon>
@@ -58,10 +66,7 @@
 
         <!-- 水雨情监测页面 -->
         <WaterRainView v-if="activeMenu === 'hydro-realtime'" />
-        <HydroMapView v-if="activeMenu === 'hydro-map'" />
         <HydroHistoryView v-if="activeMenu === 'hydro-history'" />
-        <HydroForecastView v-if="activeMenu === 'hydro-forecast'" />
-
         <!-- 水资源调度模块 -->
         <WaterResourceAllocationView v-if="isWaterActive" ref="waterView" :default-tab="waterTabMap[activeMenu]" :key="activeMenu" />
 
@@ -72,18 +77,12 @@
         <ArchiveFilesView v-if="activeMenu === 'archive-files'" />
         <ArchiveOrdersView v-if="activeMenu === 'archive-orders'" />
         <ArchiveLifecycleView v-if="activeMenu === 'archive-lifecycle'" />
-        <ArchiveReportView v-if="activeMenu === 'archive-report'" />
 
         <!-- 系统权限模块 -->
         <SysRoleView v-if="activeMenu === 'sys-role'" />
         <SysUserView v-if="activeMenu === 'sys-user'" />
         <SysLogView v-if="activeMenu === 'sys-log'" />
 
-        <!-- 视频监控模块 -->
-        <VideoLiveView v-if="activeMenu === 'video-live'" />
-        <VideoCaptureView v-if="activeMenu === 'video-capture'" />
-        <VideoDeviceView v-if="activeMenu === 'video-device'" />
-
         <!-- 首页内容 -->
         <template v-if="isHomePage">
         <!-- 核心水情数据卡片 -->
@@ -339,26 +338,20 @@ import PatrolPlanView from '../admin/PatrolPlanView.vue'
 import PatrolRecordView from '../admin/PatrolRecordView.vue'
 import PatrolHiddenView from '../admin/PatrolHiddenView.vue'
 import WaterRainView from '../admin/WaterRainView.vue'
-import HydroMapView from '../admin/HydroMapView.vue'
 import HydroHistoryView from '../admin/HydroHistoryView.vue'
-import HydroForecastView from '../admin/HydroForecastView.vue'
 import WaterResourceAllocationView from '../admin/WaterResourceAllocationView.vue'
 import GateControlAdminView from '../admin/GateControlAdminView.vue'
 import BenefitSummaryView from '../admin/BenefitSummaryView.vue'
 import ArchiveFilesView from '../admin/ArchiveFilesView.vue'
 import ArchiveOrdersView from '../admin/ArchiveOrdersView.vue'
 import ArchiveLifecycleView from '../admin/ArchiveLifecycleView.vue'
-import ArchiveReportView from '../admin/ArchiveReportView.vue'
 import SysRoleView from '../admin/SysRoleView.vue'
 import SysUserView from '../admin/SysUserView.vue'
 import SysLogView from '../admin/SysLogView.vue'
-import VideoLiveView from '../admin/VideoLiveView.vue'
-import VideoCaptureView from '../admin/VideoCaptureView.vue'
-import VideoDeviceView from '../admin/VideoDeviceView.vue'
 
 export default {
   name: 'WorkspaceView',
-  components: { Search, Warning, DeviceMaintainView, PatrolPlanView, PatrolRecordView, PatrolHiddenView, WaterRainView, HydroMapView, HydroHistoryView, HydroForecastView, WaterResourceAllocationView, GateControlAdminView, BenefitSummaryView, ArchiveFilesView, ArchiveOrdersView, ArchiveLifecycleView, ArchiveReportView, SysRoleView, SysUserView, SysLogView, VideoLiveView, VideoCaptureView, VideoDeviceView },
+  components: { Search, Warning, DeviceMaintainView, PatrolPlanView, PatrolRecordView, PatrolHiddenView, WaterRainView, HydroHistoryView, WaterResourceAllocationView, GateControlAdminView, BenefitSummaryView, ArchiveFilesView, ArchiveOrdersView, ArchiveLifecycleView, SysRoleView, SysUserView, SysLogView },
   data() {
     return {
       currentDate: '',
@@ -367,24 +360,18 @@ export default {
       timer: null,
       activeMenu: 'dashboard',
       waterTabMap: {
-        'water-overview': 'overview',
-        'water-irrigate': 'irrigation',
-        'water-drink': 'drinking',
-        'water-industry': 'industrial',
-        'water-eco': 'eco',
-        'water-dispatch': 'dispatch',
-        'water-network': 'network'
+        'water-supply': 'supply',
+        'water-eco': 'eco'
       },
       menuTree: [
         { name: '首页', children: [] },
-        { name: '视频监控', children: [{ id: 'video-live', name: '实时监控' }, { id: 'video-capture', name: '异常抓拍' }, { id: 'video-device', name: '点位台账' }] },
         { name: '日常巡检', children: [{ id: 'patrol-plan', name: '巡检计划' }, { id: 'patrol-record', name: '巡检记录' }, { id: 'patrol-hidden', name: '隐患台账' }] },
         { name: '设备运维', children: [] },
         { name: '闸门控制', children: [] },
-        { name: '水雨情监测', children: [{ id: 'hydro-realtime', name: '实时监测' }, { id: 'hydro-map', name: '水情地图' }, { id: 'hydro-history', name: '历史数据' }, { id: 'hydro-forecast', name: '水情预报' }] },
-        { name: '水资源调度', children: [{ id: 'water-overview', name: '调度总览' }, { id: 'water-irrigate', name: '灌溉供水' }, { id: 'water-drink', name: '人畜饮水' }, { id: 'water-industry', name: '工业供水' }, { id: 'water-eco', name: '生态补水' }, { id: 'water-dispatch', name: '调度计划' }, { id: 'water-network', name: '供水网络' }] },
+        { name: '水雨情监测', children: [{ id: 'hydro-realtime', name: '实时监测' }, { id: 'hydro-history', name: '历史数据' }] },
+        { name: '水资源调度', children: [{ id: 'water-supply', name: '供水水量' }, { id: 'water-eco', name: '生态补水' }] },
         { name: '工程效益', children: [] },
-        { name: '资料档案', children: [{ id: 'archive-files', name: '工程档案' }, { id: 'archive-orders', name: '调令文件' }, { id: 'archive-lifecycle', name: '全生命周期' }, { id: 'archive-report', name: '智能报表' }] },
+        { name: '资料档案', children: [{ id: 'archive-files', name: '工程档案' }, { id: 'archive-orders', name: '调令文件' }, { id: 'archive-lifecycle', name: '全生命周期' }] },
         { name: '系统权限', children: [{ id: 'sys-role', name: '角色管理' }, { id: 'sys-user', name: '用户账号' }, { id: 'sys-log', name: '操作日志' }] }
       ],
       // 水位状态
@@ -473,12 +460,12 @@ export default {
   },
   computed: {
     isHomePage() {
-      const subPages = ['设备运维', '闸门控制', '工程效益', 'patrol-plan', 'patrol-record', 'patrol-hidden', 'hydro-realtime', 'hydro-map', 'hydro-history', 'hydro-forecast', 'archive-files', 'archive-orders', 'archive-lifecycle', 'archive-report', 'sys-role', 'sys-user', 'sys-log', 'video-live', 'video-capture', 'video-device']
-      const waterPages = ['water-overview', 'water-irrigate', 'water-drink', 'water-industry', 'water-eco', 'water-dispatch', 'water-network']
+      const subPages = ['设备运维', '闸门控制', '工程效益', 'patrol-plan', 'patrol-record', 'patrol-hidden', 'hydro-realtime', 'hydro-history', 'archive-files', 'archive-orders', 'archive-lifecycle', 'sys-role', 'sys-user', 'sys-log']
+      const waterPages = ['water-supply', 'water-eco']
       return ![...subPages, ...waterPages].includes(this.activeMenu)
     },
     isWaterActive() {
-      return ['water-overview', 'water-irrigate', 'water-drink', 'water-industry', 'water-eco', 'water-dispatch', 'water-network'].includes(this.activeMenu)
+      return ['water-supply', 'water-eco'].includes(this.activeMenu)
     },
     isBenefitActive() {
       return this.activeMenu === '工程效益'
@@ -599,10 +586,29 @@ export default {
 .header-right {
   display: flex;
   align-items: center;
-  gap: 20px;
+  gap: 12px;
   font-size: 14px;
   opacity: 0.95;
 }
+.back-bigscreen-btn {
+  width: 36px;
+  height: 36px;
+  border-radius: 50%;
+  background: rgba(255,255,255,0.15);
+  border: 1px solid rgba(255,255,255,0.3);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  cursor: pointer;
+  transition: all 0.25s;
+  color: rgba(255,255,255,0.85);
+  flex-shrink: 0;
+}
+.back-bigscreen-btn:hover {
+  background: rgba(255,255,255,0.3);
+  color: #fff;
+  transform: scale(1.05);
+}
 .header-time {
   font-size: 20px;
   font-weight: 600;

Beberapa file tidak ditampilkan karena terlalu banyak file yang berubah dalam diff ini