From 28110912ca4803e5793f181517d7bf2d7a5ea2ad Mon Sep 17 00:00:00 2001
From: HuBingJie <3146306518@qq.com>
Date: 星期五, 05 十二月 2025 00:32:49 +0800
Subject: [PATCH] 1

---
 代码管理/WCS/WCS/WIDESEAWCS_Client/src/views/Home.vue | 1068 +++++++++++++++++++++++++++++++++++++++++++---------------
 1 files changed, 783 insertions(+), 285 deletions(-)

diff --git "a/\344\273\243\347\240\201\347\256\241\347\220\206/WCS/WCS/WIDESEAWCS_Client/src/views/Home.vue" "b/\344\273\243\347\240\201\347\256\241\347\220\206/WCS/WCS/WIDESEAWCS_Client/src/views/Home.vue"
index 3e7822e..b893e82 100644
--- "a/\344\273\243\347\240\201\347\256\241\347\220\206/WCS/WCS/WIDESEAWCS_Client/src/views/Home.vue"
+++ "b/\344\273\243\347\240\201\347\256\241\347\220\206/WCS/WCS/WIDESEAWCS_Client/src/views/Home.vue"
@@ -6,65 +6,51 @@
         <!-- 鐩戞帶绫诲瀷鍒囨崲 -->
         <div class="monitor-type-switch">
           <el-button-group>
-            <el-button 
-              :type="currentMonitorType === 'inbound' ? 'primary' : ''"
-              @click="switchMonitorType('inbound')"
-            >
+            <el-button :type="currentMonitorType === 'inbound' ? 'primary' : ''" @click="switchMonitorType('inbound')">
               鍏ュ簱鐩戞帶
             </el-button>
-            <el-button 
-              :type="currentMonitorType === 'outbound' ? 'primary' : ''"
-              @click="switchMonitorType('outbound')"
-            >
+            <el-button :type="currentMonitorType === 'outbound' ? 'primary' : ''"
+              @click="switchMonitorType('outbound')">
               鍑哄簱鐩戞帶
             </el-button>
-            <el-button 
-              :type="currentMonitorType === 'safetydoor' ? 'primary' : ''"
-              @click="switchMonitorType('safetydoor')"
-            >
+            <el-button :type="currentMonitorType === 'safetydoor' ? 'primary' : ''"
+              @click="switchMonitorType('safetydoor')">
               瀹夊叏闂ㄧ洃鎺�
+            </el-button>
+            <el-button :type="currentMonitorType === 'platform' ? 'primary' : ''"
+              @click="switchMonitorType('platform')">
+              绔欏彴鐩戞帶
             </el-button>
           </el-button-group>
         </div>
-        
-        <!-- 涓�閿搷浣滄寜閽紙瀹夊叏闂ㄧ洃鎺ф椂涓嶆樉绀猴級 -->
-        <div class="one-click-operations" v-if="currentMonitorType !== 'safetydoor'">
+
+        <!-- 涓�閿搷浣滄寜閽紙瀹夊叏闂ㄥ拰绔欏彴鐩戞帶鏃朵笉鏄剧ず锛� -->
+        <div class="one-click-operations"
+          v-if="currentMonitorType !== 'safetydoor' && currentMonitorType !== 'platform'">
           <el-button-group>
-            <el-button 
-              type="primary" 
-              @click="handleOneClickOperation('init')"
-              :loading="oneClickLoading.init"
-            >
+            <el-button type="primary"
+              @mousedown="startOneClickInitHold"
+              @mouseup="cancelOneClickInitHold"
+              @mouseleave="cancelOneClickInitHold"
+              @touchstart.prevent="startOneClickInitHold"
+              @touchend="cancelOneClickInitHold"
+              @touchcancel="cancelOneClickInitHold"
+              :loading="oneClickLoading.init">
               涓�閿垵濮嬪寲
             </el-button>
-            <el-button 
-              type="warning" 
-              @click="handleOneClickOperation('reset')"
-              :loading="oneClickLoading.reset"
-            >
+            <el-button type="warning" @click="handleOneClickOperation('reset')" :loading="oneClickLoading.reset">
               涓�閿浣�
             </el-button>
-            <el-button 
-              type="success" 
-              @click="handleOneClickOperation('start')"
-              :loading="oneClickLoading.start"
-            >
+            <el-button type="success" @click="handleOneClickOperation('start')" :loading="oneClickLoading.start">
               涓�閿惎鍔�
             </el-button>
-            <el-button 
-              type="danger" 
-              @click="handleOneClickOperation('stop')"
-              :loading="oneClickLoading.stop"
-            >
+            <el-button type="danger" @click="handleOneClickOperation('stop')" :loading="oneClickLoading.stop">
               涓�閿殏鍋�
             </el-button>
           </el-button-group>
         </div>
-        
-        <el-button 
-          :type="isMonitoring ? 'danger' : 'primary'" 
-          @click="toggleMonitoring"
-        >
+
+        <el-button :type="isMonitoring ? 'danger' : 'primary'" @click="toggleMonitoring">
           {{ isMonitoring ? '鍋滄鐩戞帶' : '鍚姩鐩戞帶' }}
         </el-button>
         <el-button type="warning" @click="refreshData">鍒锋柊鏁版嵁</el-button>
@@ -73,21 +59,13 @@
 
     <!-- 鐩戞帶鐘舵�佹樉绀� -->
     <div class="monitor-status">
-      <el-alert
-        :title="getMonitorStatusTitle()"
-        :type="isMonitoring ? 'success' : 'info'"
-        :closable="false"
-        show-icon
-      />
+      <el-alert :title="getMonitorStatusTitle()" :type="isMonitoring ? 'success' : 'info'" :closable="false"
+        show-icon />
     </div>
 
     <div class="devices-container">
       <!-- 鍔ㄦ�佹覆鏌撹澶� -->
-      <div 
-        class="device-card" 
-        v-for="(deviceData, deviceKey) in currentDeviceData" 
-        :key="deviceKey"
-      >
+      <div class="device-card" v-for="(deviceData, deviceKey) in currentDeviceData" :key="deviceKey">
         <div class="device-header">
           <h3>{{ getDeviceDisplayName(deviceKey) }}</h3>
           <div class="status-indicator" :class="getStatusClass(deviceData)"></div>
@@ -95,24 +73,16 @@
         <div class="device-content">
           <template v-if="deviceData && Object.keys(deviceData).length > 0">
             <!-- RGV璁惧鏄剧ず -->
-            <template v-if="currentMonitorType !== 'safetydoor'">
+            <template v-if="currentMonitorType !== 'safetydoor' && currentMonitorType !== 'platform'">
               <!-- 鍒濆鍖栫姸鎬佹樉绀� -->
-              <div 
-                class="data-row" 
-                v-if="deviceData['鍒濆鍖栨湭瀹屾垚鏍囧織浣�'] !== undefined"
-              >
+              <div class="data-row" v-if="deviceData['鍒濆鍖栨湭瀹屾垚鏍囧織浣�'] !== undefined">
                 <span class="label">鍒濆鍖栫姸鎬�:</span>
                 <span class="value" :class="deviceData['鍒濆鍖栨湭瀹屾垚鏍囧織浣�'] === 1 ? 'fault-text' : ''">
                   {{ deviceData['鍒濆鍖栨湭瀹屾垚鏍囧織浣�'] === 0 ? '宸插畬鎴�' : '鏈畬鎴�' }}
                 </span>
               </div>
-              
-              <div 
-                class="data-row" 
-                v-for="(value, key) in deviceData" 
-                :key="key"
-                v-if="key !== '鍒濆鍖栨湭瀹屾垚鏍囧織浣�'"
-              >
+
+              <div class="data-row" v-for="(value, key) in deviceData" :key="key" v-if="key !== '鍒濆鍖栨湭瀹屾垚鏍囧織浣�'">
                 <span class="label">{{ getFieldDisplayName(key) }}:</span>
                 <span class="value" :class="getValueClass(key, value, deviceKey)">
                   {{ getFormattedValue(key, value, deviceKey) }}
@@ -124,12 +94,8 @@
             </template>
 
             <!-- 瀹夊叏闂ㄨ澶囨樉绀� -->
-            <template v-else>
-              <div 
-                class="data-row" 
-                v-for="(value, key) in deviceData" 
-                :key="key"
-              >
+            <template v-else-if="currentMonitorType === 'safetydoor'">
+              <div class="data-row" v-for="(value, key) in deviceData" :key="key">
                 <span class="label">{{ getFieldDisplayName(key) }}:</span>
                 <span class="value" :class="getSafetyDoorValueClass(key, value)">
                   {{ getSafetyDoorFormattedValue(key, value) }}
@@ -139,158 +105,175 @@
                 </span>
               </div>
             </template>
+
+            <!-- 绔欏彴璁惧鏄剧ず -->
+            <template v-else-if="currentMonitorType === 'platform'">
+              <div class="data-row" v-for="(value, key) in deviceData" :key="key">
+                <span class="label">{{ getFieldDisplayName(key) }}:</span>
+                <span class="value" :class="getPlatformValueClass(key, value)">
+                  {{ getPlatformFormattedValue(key, value) }}
+                  <!-- 绔欏彴鍏夌數淇″彿鎸囩ず鐏� -->
+                  <span v-if="key === '鍏夌數淇″彿'" class="signal-indicator" :class="getSignalClass(value)"></span>
+                </span>
+              </div>
+            </template>
           </template>
           <div v-else class="no-data">
             璁惧鏈繛鎺ユ垨鏆傛棤鏁版嵁
           </div>
 
-          <!-- 鎿嶄綔鎸夐挳鍖哄煙锛堝畨鍏ㄩ棬鐩戞帶鏃朵笉鏄剧ず锛� -->
-          <div class="operation-buttons" v-if="currentMonitorType !== 'safetydoor'">
+          <!-- 鎿嶄綔鎸夐挳鍖哄煙锛堝畨鍏ㄩ棬鍜岀珯鍙扮洃鎺ф椂涓嶆樉绀猴級 -->
+          <div class="operation-buttons"
+            v-if="currentMonitorType !== 'safetydoor' && currentMonitorType !== 'platform'">
             <!-- 瀛愯溅鎿嶄綔鎸夐挳 -->
             <template v-if="getDeviceType(deviceKey) === 'child'">
-              <el-button 
-                type="primary" 
-                size="small" 
-                @click="handleOperation(deviceKey, 'cs')"
-                :loading="loadingStates[deviceKey]?.cs"
-                :disabled="deviceData && deviceData['鍒濆鍖栨湭瀹屾垚鏍囧織浣�'] === 0"
-              >
+              <el-button type="primary" size="small"
+                @mousedown="startInitHold(deviceKey)"
+                @mouseup="cancelInitHold(deviceKey)"
+                @mouseleave="cancelInitHold(deviceKey)"
+                @touchstart.prevent="startInitHold(deviceKey)"
+                @touchend="cancelInitHold(deviceKey)"
+                @touchcancel="cancelInitHold(deviceKey)"
+                :loading="loadingStates[deviceKey]?.cs">
                 {{ getInitializationButtonText(deviceData) }}
               </el-button>
-              <el-button 
-                :type="getModeButtonType(deviceData)" 
-                size="small" 
-                @click="handleModeToggle(deviceKey)"
-                :loading="loadingStates[deviceKey]?.modeToggle"
-              >
+              <el-button :type="getModeButtonType(deviceData)" size="small" @click="handleModeToggle(deviceKey)"
+                :loading="loadingStates[deviceKey]?.modeToggle">
                 {{ getCurrentModeText(deviceData) }}
               </el-button>
-              <el-button 
-                type="warning" 
-                size="small" 
-                @click="handleOperation(deviceKey, 'fw')"
-                :loading="loadingStates[deviceKey]?.fw"
-              >
+              <el-button type="warning" size="small" @click="handleOperation(deviceKey, 'fw')"
+                :loading="loadingStates[deviceKey]?.fw">
                 澶嶄綅
+              </el-button>
+              <!-- 闀挎寜锛氫笂鍗�/涓嬮檷锛堟寜涓�=1锛屾澗寮�=0锛� -->
+              <el-button type="success" size="small"
+                @pointerdown.prevent="handleLiftPress(deviceKey, 'ss')"
+                @pointerup="handleLiftRelease(deviceKey, 'ss')"
+                @pointercancel="handleLiftRelease(deviceKey, 'ss')"
+                :disabled="!isManualMode(deviceData) || deviceData['涓婂崌淇″彿鍒颁綅'] === 1"
+                :loading="activeLift && activeLift.deviceKey === deviceKey && activeLift.operationType === 'ss'">
+                涓婂崌
+              </el-button>
+              <el-button type="info" size="small"
+                @pointerdown.prevent="handleLiftPress(deviceKey, 'xj')"
+                @pointerup="handleLiftRelease(deviceKey, 'xj')"
+                @pointercancel="handleLiftRelease(deviceKey, 'xj')"
+                :disabled="!isManualMode(deviceData) || deviceData['涓嬮檷淇″彿鍒颁綅'] === 1"
+                :loading="activeLift && activeLift.deviceKey === deviceKey && activeLift.operationType === 'xj'">
+                涓嬮檷
+              </el-button>
+              <!-- 淇濋殰锛氭墜鍔ㄥ仠姝㈡寜閽紙鐐瑰嚮鍗冲彂0锛� -->
+              <el-button type="warning" size="small"
+                @click="stopLift(deviceKey, 'ss')"
+                :disabled="!isManualMode(deviceData)">
+                鍋滄涓婂崌
+              </el-button>
+              <el-button type="warning" size="small"
+                @click="stopLift(deviceKey, 'xj')"
+                :disabled="!isManualMode(deviceData)">
+                鍋滄涓嬮檷
               </el-button>
             </template>
 
             <!-- 姣嶈溅鎿嶄綔鎸夐挳 -->
             <template v-else-if="getDeviceType(deviceKey) === 'mother'">
-              <el-button 
-                type="primary" 
-                size="small" 
-                @click="handleOperation(deviceKey, 'cs')"
-                :loading="loadingStates[deviceKey]?.cs"
-                :disabled="deviceData && deviceData['鍒濆鍖栨湭瀹屾垚鏍囧織浣�'] === 0"
-              >
+              <el-button type="primary" size="small"
+                @mousedown="startInitHold(deviceKey)"
+                @mouseup="cancelInitHold(deviceKey)"
+                @mouseleave="cancelInitHold(deviceKey)"
+                @touchstart.prevent="startInitHold(deviceKey)"
+                @touchend="cancelInitHold(deviceKey)"
+                @touchcancel="cancelInitHold(deviceKey)"
+                :loading="loadingStates[deviceKey]?.cs">
                 {{ getInitializationButtonText(deviceData) }}
               </el-button>
-              <el-button 
-                :type="getModeButtonType(deviceData)" 
-                size="small" 
-                @click="handleModeToggle(deviceKey)"
-                :loading="loadingStates[deviceKey]?.modeToggle"
-              >
+              <el-button :type="getModeButtonType(deviceData)" size="small" @click="handleModeToggle(deviceKey)"
+                :loading="loadingStates[deviceKey]?.modeToggle">
                 {{ getCurrentModeText(deviceData) }}
               </el-button>
-              <el-button 
-                type="warning" 
-                size="small" 
-                @click="handleOperation(deviceKey, 'fw')"
-                :loading="loadingStates[deviceKey]?.fw"
-              >
+              <el-button type="warning" size="small" @click="handleOperation(deviceKey, 'fw')"
+                :loading="loadingStates[deviceKey]?.fw">
                 澶嶄綅
+              </el-button>
+              <!-- 闆疯揪寮�鍏虫寜閽� -->
+              <el-button :type="getRadarButtonType(deviceData)" size="small" @click="handleRadarToggle(deviceKey)"
+                :loading="loadingStates[deviceKey]?.radarToggle" :disabled="!isManualMode(deviceData)">
+                {{ getRadarButtonText(deviceData) }}
               </el-button>
             </template>
 
             <!-- 鍘熸枡杞︽搷浣滄寜閽� -->
             <template v-else-if="getDeviceType(deviceKey) === 'material'">
-              <el-button 
-                type="primary" 
-                size="small" 
-                @click="handleOperation(deviceKey, 'cs')"
-                :loading="loadingStates[deviceKey]?.cs"
-                :disabled="deviceData && deviceData['鍒濆鍖栨湭瀹屾垚鏍囧織浣�'] === 0"  
-              >
-              <!---->
+              <el-button type="primary" size="small"
+                @mousedown="startInitHold(deviceKey)"
+                @mouseup="cancelInitHold(deviceKey)"
+                @mouseleave="cancelInitHold(deviceKey)"
+                @touchstart.prevent="startInitHold(deviceKey)"
+                @touchend="cancelInitHold(deviceKey)"
+                @touchcancel="cancelInitHold(deviceKey)"
+                :loading="loadingStates[deviceKey]?.cs">
                 {{ getInitializationButtonText(deviceData) }}
               </el-button>
-              <el-button 
-                :type="getModeButtonType(deviceData)" 
-                size="small" 
-                @click="handleModeToggle(deviceKey)"
-                :loading="loadingStates[deviceKey]?.modeToggle"
-              >
+              <el-button :type="getModeButtonType(deviceData)" size="small" @click="handleModeToggle(deviceKey)"
+                :loading="loadingStates[deviceKey]?.modeToggle">
                 {{ getCurrentModeText(deviceData) }}
               </el-button>
-              <el-button 
-                type="warning" 
-                size="small" 
-                @click="handleOperation(deviceKey, 'fw')"
-                :loading="loadingStates[deviceKey]?.fw"
-              >
+              <el-button type="warning" size="small" @click="handleOperation(deviceKey, 'fw')"
+                :loading="loadingStates[deviceKey]?.fw">
                 澶嶄綅
               </el-button>
               <!-- 闆疯揪寮�鍏虫寜閽� -->
-              <el-button 
-                :type="getRadarButtonType(deviceData)" 
-                size="small" 
-                @click="handleRadarToggle(deviceKey)"
-                :loading="loadingStates[deviceKey]?.radarToggle"
-                :disabled="!isManualMode(deviceData)"
-              >
+              <el-button :type="getRadarButtonType(deviceData)" size="small" @click="handleRadarToggle(deviceKey)"
+                :loading="loadingStates[deviceKey]?.radarToggle" :disabled="!isManualMode(deviceData)">
                 {{ getRadarButtonText(deviceData) }}
               </el-button>
-              
-              <!-- 鍏ュ簱缁х画浠诲姟鎸夐挳锛堜粎瀵筊GV101鏄剧ず锛� -->
-              <el-button 
-                v-if="deviceKey === 'rgV101'"
-                type="success" 
-                size="small" 
-                @click="handleInNormal(deviceKey)"
-                :loading="loadingStates[deviceKey]?.inNormal"
-              >
-                鍏ュ簱缁х画浠诲姟
+              <!-- 闀挎寜锛氫笂鍗�/涓嬮檷锛堟寜涓�=1锛屾澗寮�=0锛� -->
+              <el-button type="success" size="small"
+                @pointerdown.prevent="handleLiftPress(deviceKey, 'ss')"
+                @pointerup="handleLiftRelease(deviceKey, 'ss')"
+                @mousedown.prevent="handleLiftPress(deviceKey, 'ss')"
+                @mouseup="handleLiftRelease(deviceKey, 'ss')"
+                @touchstart.prevent="handleLiftPress(deviceKey, 'ss')"
+                @touchend="handleLiftRelease(deviceKey, 'ss')"
+                @touchcancel="handleLiftRelease(deviceKey, 'ss')"
+                :disabled="!isManualMode(deviceData) || deviceData['涓婂崌淇″彿鍒颁綅'] === 1"
+                :loading="activeLift && activeLift.deviceKey === deviceKey && activeLift.operationType === 'ss'">
+                涓婂崌
               </el-button>
-              
-              <!-- 鍏ュ簱寮傚父鎺掗櫎鎸夐挳锛堜粎瀵筊GV101鏄剧ず锛� -->
-              <el-button 
-                v-if="deviceKey === 'rgV101'"
-                type="danger" 
-                size="small" 
-                @click="handleInAbnormal(deviceKey)"
-                :loading="loadingStates[deviceKey]?.inAbnormal"
-              >
-                鍏ュ簱寮傚父鎺掗櫎
+              <el-button type="info" size="small"
+                @pointerdown.prevent="handleLiftPress(deviceKey, 'xj')"
+                @pointerup="handleLiftRelease(deviceKey, 'xj')"
+                @pointercancel="handleLiftRelease(deviceKey, 'xj')"
+                :disabled="!isManualMode(deviceData) || deviceData['涓嬮檷淇″彿鍒颁綅'] === 1"
+                :loading="activeLift && activeLift.deviceKey === deviceKey && activeLift.operationType === 'xj'">
+                涓嬮檷
+              </el-button>
+              <!-- 淇濋殰锛氭墜鍔ㄥ仠姝㈡寜閽紙鐐瑰嚮鍗冲彂0锛� -->
+              <el-button type="warning" size="small"
+                @click="stopLift(deviceKey, 'ss')"
+                :disabled="!isManualMode(deviceData)">
+                鍋滄涓婂崌
+              </el-button>
+              <el-button type="warning" size="small"
+                @click="stopLift(deviceKey, 'xj')"
+                :disabled="!isManualMode(deviceData)">
+                鍋滄涓嬮檷
               </el-button>
             </template>
           </div>
 
-          <!-- 鍦板潃鎿嶄綔鍖哄煙锛堝畨鍏ㄩ棬鐩戞帶鏃朵笉鏄剧ず锛� -->
-          <div class="address-operation" v-if="currentMonitorType !== 'safetydoor'">
+          <!-- 鍦板潃鎿嶄綔鍖哄煙锛堝畨鍏ㄩ棬鍜岀珯鍙扮洃鎺ф椂涓嶆樉绀猴級 -->
+          <div class="address-operation"
+            v-if="currentMonitorType !== 'safetydoor' && currentMonitorType !== 'platform'">
             <div class="address-title">鍦板潃鎿嶄綔</div>
             <div class="address-input-group">
-              <el-select 
-                v-model="addressValues[deviceKey]" 
-                placeholder="閫夋嫨鐩爣鍦板潃"
-                size="small"
-                style="width: 200px; margin-right: 10px;"
-              >
-                <el-option
-                  v-for="address in getDeviceAddresses(deviceKey)"
-                  :key="address.value"
-                  :label="address.label"
-                  :value="address.value"
-                />
+              <el-select v-model="addressValues[deviceKey]" placeholder="閫夋嫨鐩爣鍦板潃" size="small"
+                style="width: 200px; margin-right: 10px;">
+                <el-option v-for="address in getDeviceAddresses(deviceKey)" :key="address.value" :label="address.label"
+                  :value="address.value" />
               </el-select>
-              <el-button 
-                type="info" 
-                size="small" 
-                @click="handleAddressOperation(deviceKey)"
-                :loading="loadingStates[deviceKey]?.dz"
-                :disabled="!addressValues[deviceKey]"
-              >
+              <el-button type="info" size="small" @click="handleAddressOperation(deviceKey)"
+                :loading="loadingStates[deviceKey]?.dz" :disabled="!addressValues[deviceKey]">
                 鍓嶅線鍦板潃
               </el-button>
             </div>
@@ -299,8 +282,8 @@
       </div>
     </div>
 
-    <!-- 鍏ㄥ眬鎿嶄綔闈㈡澘锛堝畨鍏ㄩ棬鐩戞帶鏃朵笉鏄剧ず锛� -->
-    <div class="operation-panel" v-if="currentMonitorType !== 'safetydoor'">
+    <!-- 鍏ㄥ眬鎿嶄綔闈㈡澘锛堝畨鍏ㄩ棬鍜岀珯鍙扮洃鎺ф椂涓嶆樉绀猴級 -->
+    <div class="operation-panel" v-if="currentMonitorType !== 'safetydoor' && currentMonitorType !== 'platform'">
       <!-- <el-button type="primary" @click="showOperationDialog = true">楂樼骇鎿嶄綔</el-button> -->
     </div>
 
@@ -316,13 +299,30 @@
   name: 'RgvMonitor',
   data() {
     return {
-      currentMonitorType: 'inbound', // 'inbound' 鎴� 'outbound' 鎴� 'safetydoor'
+      currentMonitorType: 'inbound', // 'inbound' 鎴� 'outbound' 鎴� 'safetydoor' 鎴� 'platform'
       isMonitoring: false,
+      monitoringLoading: false,
       showOperationDialog: false,
       pollingTimer: null,
       loadingStates: {},
       addressValues: {},
-      
+      // 闀挎寜鍒濆鍖栫浉鍏�
+      holdTimers: {}, // 璁惧绾у垵濮嬪寲闀挎寜瀹氭椂鍣�
+      oneClickInitTimer: null, // 涓�閿垵濮嬪寲闀挎寜瀹氭椂鍣�
+      holdDuration: 3000, // 鎸変綇3绉掕Е鍙�
+      activeLift: null, // { deviceKey, operationType } 褰撳墠鎸変笅涓殑鍗囬檷鎿嶄綔
+      monitoringPaused: false, // 闀挎寜鏈熼棿鏆傚仠鐩戞帶鍒锋柊
+      liftPressPromises: {}, // key: `${deviceKey}-${operationType}` -> Promise for press(1)
+      signalPollingTimer: null, // 鍗囬檷闀挎寜鏈熼棿鐨勮交閲忎俊鍙疯疆璇�
+      signalPollInterval: 1200, // 杞婚噺淇″彿杞闂撮殧(ms)
+      lastLiftPressAt: {}, // 璁板綍姣忎釜(deviceKey-op)鏈�鍚庢寜涓嬬殑鏃堕棿鎴�
+      liftReleaseInProgress: {}, // 姝e湪鍙戦�侀噴鏀�(0)鐨勬爣璁帮紝闃查噸澶�
+
+      // 鐐瑰嚮寮忓崌闄嶆帶鍒剁姸鎬�
+      activeLiftStates: {}, // { [deviceKey]: { ss: boolean, xj: boolean } }
+      liftAutoStopTimeouts: {}, // { [deviceKey-op]: timeoutId }
+      liftCommandTimeoutMs: 10000, // 鍗囬檷鎸囦护鏈�澶ф寔缁椂闂达紝瓒呮椂鑷姩鍋滄
+
       // 涓�閿搷浣滃姞杞界姸鎬�
       oneClickLoading: {
         init: false,
@@ -330,7 +330,7 @@
         start: false,
         stop: false
       },
-      
+
       // 璁惧鏁版嵁
       inboundDeviceData: {
         rgV101: null,
@@ -340,7 +340,6 @@
         rgV107: null,
         rgV108: null,
         rgV109: null,
-        // rgV202: null
       },
       outboundDeviceData: {
         rgV116: null,
@@ -356,7 +355,19 @@
         aqm002: null,
         aqm003: null
       },
-      
+      platformDeviceData: {
+        '1001': null,
+        '1002': null,
+        '2016': null,
+        '2017': null,
+        '2018': null,
+        '2019': null,
+        '1021': null,
+        '1061': null,
+        '1131': null,
+        '1171': null
+      },
+
       // 瀛楁鏄剧ず鍚嶇О鏄犲皠
       fieldDisplayNames: {
         '宸ヤ綔妯″紡': '宸ヤ綔妯″紡',
@@ -379,9 +390,12 @@
         '瀹夊叏闂ㄩ攣鐘舵��': '闂ㄩ攣鐘舵��',
         '瀹夊叏闂ㄥ浣嶇姸鎬�': '澶嶄綅鐘舵��',
         '鎶ヨ淇℃伅': '鎶ヨ淇℃伅',
-        '寮�闂ㄤ俊鎭�': '寮�闂ㄤ俊鎭�'
+        '寮�闂ㄤ俊鎭�': '寮�闂ㄤ俊鎭�',
+        // 绔欏彴瀛楁
+        '鍏夌數淇″彿': '鍏夌數淇″彿',
+        '浠诲姟id': '浠诲姟ID'
       },
-      
+
       // 璁惧鏄剧ず鍚嶇О鏄犲皠
       deviceDisplayNames: {
         // 鍏ュ簱璁惧
@@ -403,9 +417,20 @@
         // 瀹夊叏闂ㄨ澶�
         'aqm001': 'AQM001 - 1#瀹夊叏闂�',
         'aqm002': 'AQM002 - 2#瀹夊叏闂�',
-        'aqm003': 'AQM003 - 3#瀹夊叏闂�'
+        'aqm003': 'AQM003 - 3#瀹夊叏闂�',
+        // 绔欏彴璁惧
+        '1001': '1001 - 1#绔欏彴',
+        '1002': '1002 - 2#绔欏彴',
+        '2016': '2016 - 3#绔欏彴',
+        '2017': '2017 - 4#绔欏彴',
+        '2018': '2018 - 5#绔欏彴',
+        '2019': '2019 - 6#绔欏彴',
+        '1021': '1021 - 7#绔欏彴',
+        '1061': '1061 - 8#绔欏彴',
+        '1131': '1131 - 9#绔欏彴',
+        '1171': '1171 - 10#绔欏彴'
       },
-      
+
       // 鎿嶄綔绫诲瀷鏄犲皠
       operationTypes: {
         'cs': '鍒濆鍖�',
@@ -415,8 +440,10 @@
         'kld': '寮�闆疯揪',
         'gld': '鍏抽浄杈�',
         'fw': '澶嶄綅',
+        'ss': '涓婂崌',
+        'xj': '涓嬮檷',
       },
-      
+
       // 鎶ヨ浠g爜鏄犲皠
       motherCarAlarmCodes: {
         0: '鏃犳姤璀�',
@@ -433,7 +460,7 @@
         11: '鏀捐揣鏃惰嚜韬棤璐х墿鎶ヨ',
         12: '鍋滄鏃朵綅缃繃鍐叉姤璀�'
       },
-      
+
       childCarAlarmCodes: {
         0: '鏃犳姤璀�',
         1: 'RGV灏忚溅鎬ュ仠琚寜涓�',
@@ -453,7 +480,8 @@
         15: '鏀捐揣鏃惰嚜韬棤璐х墿鎶ヨ',
         16: '鍙栬揣妫�娴嬩笉鍒拌揣鐗╂姤璀�'
       },
-      
+
+      // 鍦� data() 涓慨鏀� materialCarAlarmCodes
       materialCarAlarmCodes: {
         0: '鏃犳姤璀�',
         1: 'RGV灏忚溅鎬ュ仠琚寜涓�',
@@ -461,7 +489,7 @@
         3: '鍙嶈浆闆疯揪鎶ヨ',
         4: '鍓嶈繘闄愪綅鎶ヨ',
         5: '鍚庨��闄愪綅鎶ヨ',
-        6: '棰勭暀',
+        6: '',
         7: 'PLC妯″潡鏁呴殰',
         8: 'PLC鎵╁睍妯″潡鏁呴殰',
         9: '绉伴噸妯″潡鏁呴殰',
@@ -486,9 +514,17 @@
         28: '鏀捐揣鏃惰嚜韬棤璐х墿鎶ヨ',
         29: '璐у弶鏈洖鍒板垵濮嬩綅鎶ヨ',
         30: '瑙﹀彂浠呯Щ鍔ㄥ懡浠ゆ椂璐у弶涓嶅湪鍒濆浣嶆姤璀�',
-        31: '璐у弶鍒拌揪鍒濆浣嶄絾涓綅浼犳劅鍣ㄦ湭妫�娴嬪埌鎶ヨ'
+        31: '璐у弶鍒拌揪鍒濆浣嶄絾涓綅浼犳劅鍣ㄦ湭妫�娴嬪埌鎶ヨ',
+        32: '琛岃蛋杞存病鍒颁綅绂佹璐у弶浼稿嚭',
+        33: '鍙栬揣寮傚父鎶ヨ',
+        34: '鏀捐揣寮傚父鎶ヨ',
+        35: '澶栧瀷妫�娴�-鍓嶈秴鍑烘姤璀�',
+        36: '澶栧瀷妫�娴�-鍚庤秴鍑烘姤璀�',
+        37: '澶栧瀷妫�娴�-宸﹁秴鍑烘姤璀�',
+        38: '澶栧瀷妫�娴�-鍙宠秴鍑烘姤璀�',
+        39: '澶栧瀷妫�娴�-涓婅秴鍑烘姤璀�'
       },
-      
+
       // 瀹夊叏闂ㄦ寚绀虹伅鐘舵�佹槧灏�
       safetyDoorLightCodes: {
         0: '鏃犺緭鍑�',
@@ -497,7 +533,7 @@
         3: '榛勭伅闂儊(2HZ)',
         4: '榛勭伅甯镐寒'
       },
-      
+
       // 璁惧绫诲瀷鍒嗙被
       deviceTypes: {
         // 鍏ュ簱璁惧
@@ -509,9 +545,11 @@
         outboundChildCars: ['rgV111', 'rgV116'],
         outboundMaterialCars: ['rgV118'],
         // 瀹夊叏闂ㄨ澶�
-        safetyDoors: ['aqm001', 'aqm002', 'aqm003']
+        safetyDoors: ['aqm001', 'aqm002', 'aqm003'],
+        // 绔欏彴璁惧
+        platforms: ['1001', '1002', '2016', '2017', '2018', '2019', '1021', '1061', '1131', '1171']
       },
-      
+
       // 璁惧鍦板潃鏄犲皠
       deviceAddresses: {
         // 鍏ュ簱璁惧鍦板潃
@@ -527,6 +565,9 @@
         'rgV104': [
           { value: '3', label: '鍋滈潬鐐�1' },
           { value: '5', label: '鍋滈潬鐐�2' },
+          { value: '1031', label: '1031 - 瀛愯溅鍙栬揣浣�' },
+          { value: '1051', label: '1051 - 瀛愯溅鍙栬揣浣�' }
+
         ],
         'rgV105': [
           { value: '1051', label: '1051 - 姣嶈溅鍋滆溅浣�1' },
@@ -535,6 +576,8 @@
         'rgV107': [
           { value: '3', label: '鍋滈潬鐐�1' },
           { value: '5', label: '鍋滈潬鐐�2' },
+          { value: '1081', label: '1081 - 瀛愯溅鍙栬揣浣�' },
+          { value: '1091', label: '1091 - 瀛愯溅鍙栬揣浣�' }
         ],
         'rgV108': [
           { value: '1081', label: '1081 - 姣嶈溅鍋滆溅浣�1' },
@@ -544,17 +587,6 @@
           { value: '1091', label: '1091 - 姣嶈溅鍋滆溅浣�1' },
           { value: '1092', label: '1092 - 姣嶈溅鍋滆溅浣�2' }
         ],
-        // 'rgV202': [
-        //   { value: '2001', label: '2001 - 宸ヤ綅1' },
-        //   { value: '2002', label: '2002 - 宸ヤ綅2' },
-        //   { value: '2003', label: '2003 - 宸ヤ綅3' },
-        //   { value: '2004', label: '2004 - 宸ヤ綅4' },
-        //   { value: '2005', label: '2005 - 宸ヤ綅5' },
-        //   { value: '2006', label: '2006 - 宸ヤ綅6' },
-        //   { value: '2007', label: '2007 - 宸ヤ綅7' },
-        //   { value: '2008', label: '2008 - 宸ヤ綅8' },
-        //   { value: '2009', label: '2009 - 宸ヤ綅9' }
-        // ],
         // 鍑哄簱璁惧鍦板潃
         'rgV110': [
           { value: '1101', label: '1101 - 姣嶈溅鍋滆溅浣�1' },
@@ -563,6 +595,8 @@
         'rgV111': [
           { value: '3', label: '鍋滈潬鐐�1' },
           { value: '5', label: '鍋滈潬鐐�2' },
+          { value: '1101', label: '1101 - 瀛愯溅鍙栬揣浣�' },
+          { value: '1121', label: '1121 - 瀛愯溅鍙栬揣浣�' }
         ],
         'rgV112': [
           { value: '1121', label: '1121 - 姣嶈溅鍋滆溅浣�1' },
@@ -570,7 +604,7 @@
         ],
         'rgV114': [
           { value: '1141', label: '1141 - 姣嶈溅鍋滆溅浣�1' },
-          { value: '1142', label: '1142 - 姣嶈溅鍋滆溅浣�2' }
+          { value: '1142', label: '1142 - 姣嶈溅鍋滆溅浣�2' },
         ],
         'rgV115': [
           { value: '1151', label: '1151 - 姣嶈溅鍋滆溅浣�1' },
@@ -579,6 +613,8 @@
         'rgV116': [
           { value: '3', label: '鍋滈潬鐐�1' },
           { value: '5', label: '鍋滈潬鐐�2' },
+          { value: '1151', label: '1151 - 瀛愯溅鍙栬揣浣�' },
+          { value: '1141', label: '1141 - 瀛愯溅鍙栬揣浣�' }
         ],
         'rgV118': [
           { value: '2016', label: '2016 - 鍘熸枡澶勭悊浣�1' },
@@ -587,7 +623,7 @@
           { value: '2019', label: '2019 - 鍘熸枡澶勭悊浣�4' }
         ]
       },
-      
+
       // 鐗规畩瀛楁鐨勫�兼牸寮忓寲
       valueFormatters: {
         '宸ヤ綔妯″紡': (value) => {
@@ -608,7 +644,7 @@
         '闆疯揪鐘舵��': (value) => value === 0 ? '鍏抽棴' : '寮�鍚�',
         '璐у弶鐘舵��': (value) => value === 0 ? '缂╁洖' : '浼稿嚭'
       },
-      
+
       // 瀹夊叏闂ㄥ瓧娈靛�兼牸寮忓寲
       safetyDoorValueFormatters: {
         '瀹夊叏闂ㄦ寚绀虹伅鐘舵��': (value) => {
@@ -621,6 +657,12 @@
         '瀹夊叏闂ㄥ浣嶇姸鎬�': (value) => value === 0 ? '姝e父' : '澶嶄綅涓�',
         '鎶ヨ淇℃伅': (value) => value === 0 ? '姝e父' : '鎶ヨ',
         '寮�闂ㄤ俊鎭�': (value) => value === 0 ? '鍏抽棬' : '寮�闂�'
+      },
+
+      // 绔欏彴瀛楁鍊兼牸寮忓寲
+      platformValueFormatters: {
+        '鍏夌數淇″彿': (value) => value === 0 ? '鏃犱俊鍙�' : '鏈変俊鍙�',
+        '浠诲姟id': (value) => value === 0 ? '鏃犱换鍔�' : `浠诲姟${value}`
       }
     }
   },
@@ -634,22 +676,254 @@
           return this.outboundDeviceData
         case 'safetydoor':
           return this.safetyDoorDeviceData
+        case 'platform':
+          return this.platformDeviceData
         default:
           return this.inboundDeviceData
       }
     }
   },
   methods: {
+    // 鏆傚仠/鎭㈠鐩戞帶杞
+    pauseMonitoring() {
+      this.monitoringPaused = true
+      if (this.pollingTimer) {
+        clearTimeout(this.pollingTimer)
+        this.pollingTimer = null
+      }
+    },
+    resumeMonitoring() {
+      // 浠呭綋娌℃湁浠讳綍闀挎寜/鍗囬檷鍦ㄨ繘琛屾椂鎵嶆仮澶�
+      if (!this.activeLift && !this.isHoldActive()) {
+        this.monitoringPaused = false
+        if (this.isMonitoring && !this.pollingTimer) {
+          this.startPolling()
+        }
+      }
+    },
+    // 鍗囬檷闀挎寜鏈熼棿浠呰疆璇㈠綋鍓嶈澶囩殑"涓�/涓嬪埌浣�"淇″彿锛岄伩鍏嶅叏閲忓埛鏂帮紙瀹炰緥鏂规硶锛�
+    startLiftSignalPolling(deviceKey) {
+      this.stopLiftSignalPolling()
+      this.signalPollingTimer = setInterval(async () => {
+        // 浠呭湪褰撳墠浠嶅浜庤璁惧鐨勫崌闄嶉暱鎸変笖鐩戞帶寮�鍚椂鏈夋晥锛屽惁鍒欒嚜鍔ㄥ仠姝�
+        if (!this.isMonitoring || !this.activeLift || this.activeLift.deviceKey !== deviceKey) {
+          this.stopLiftSignalPolling()
+          return
+        }
+        try {
+          const response = await this.http.post('api/Rgvoperainform/GetDeviceStatusDto', {
+            off: 1,
+            monitorType: this.currentMonitorType
+          })
+          if (response && response.status && response.data) {
+            const keys = Object.keys(response.data)
+            const respKey = keys.find(k => k.toLowerCase() === String(deviceKey).toLowerCase())
+            const dev = respKey ? response.data[respKey] : null
+            if (!dev) return
+            const updateMap = (mapObj) => {
+              if (!mapObj) return null
+              const devOld = mapObj[deviceKey] || {}
+              const patch = { ...devOld }
+              const riseVal = Object.prototype.hasOwnProperty.call(dev, '涓婂崌淇″彿鍒颁綅') ? dev['涓婂崌淇″彿鍒颁綅']
+                : (Object.prototype.hasOwnProperty.call(dev, 'RGV_Risingsignalplace') ? dev['RGV_Risingsignalplace']
+                : (Object.prototype.hasOwnProperty.call(dev, 'RiseArrived') ? dev['RiseArrived'] : undefined))
+              const downVal = Object.prototype.hasOwnProperty.call(dev, '涓嬮檷淇″彿鍒颁綅') ? dev['涓嬮檷淇″彿鍒颁綅']
+                : (Object.prototype.hasOwnProperty.call(dev, 'RGV_Descentsignal') ? dev['RGV_Descentsignal']
+                : (Object.prototype.hasOwnProperty.call(dev, 'DescendArrived') ? dev['DescendArrived'] : undefined))
+              if (riseVal !== undefined) patch['涓婂崌淇″彿鍒颁綅'] = riseVal
+              if (downVal !== undefined) patch['涓嬮檷淇″彿鍒颁綅'] = downVal
+              return { ...mapObj, [deviceKey]: patch }
+            }
+
+            let patched = false
+            const tryPatch = (getter, setter) => {
+              const next = updateMap(getter)
+              if (next) {
+                setter(next)
+                patched = true
+              }
+            }
+
+            if (this.currentMonitorType === 'inbound') tryPatch(this.inboundDeviceData, v => this.inboundDeviceData = v)
+            if (this.currentMonitorType === 'outbound') tryPatch(this.outboundDeviceData, v => this.outboundDeviceData = v)
+            if (this.currentMonitorType === 'safetydoor') tryPatch(this.safetyDoorDeviceData, v => this.safetyDoorDeviceData = v)
+            if (this.currentMonitorType === 'platform') tryPatch(this.platformDeviceData, v => this.platformDeviceData = v)
+
+            if (!patched) {
+              tryPatch(this.inboundDeviceData, v => this.inboundDeviceData = v)
+              tryPatch(this.outboundDeviceData, v => this.outboundDeviceData = v)
+              tryPatch(this.safetyDoorDeviceData, v => this.safetyDoorDeviceData = v)
+              tryPatch(this.platformDeviceData, v => this.platformDeviceData = v)
+            }
+
+            if (typeof this.$forceUpdate === 'function') this.$forceUpdate()
+          }
+        } catch (e) {
+          // 蹇界暐杞婚噺杞閿欒
+        }
+      }, this.signalPollInterval)
+    },
+    stopLiftSignalPolling() {
+      if (this.signalPollingTimer) {
+        clearInterval(this.signalPollingTimer)
+        this.signalPollingTimer = null
+      }
+    },
+    // 鏄惁瀛樺湪闀挎寜涓殑鍒濆鍖栵紙璁惧绾ф垨涓�閿級
+    isHoldActive() {
+      if (this.oneClickInitTimer) return true
+      // holdTimers 涓湁浠讳綍涓�涓湁鏁堝畾鏃跺櫒鍗宠涓洪暱鎸変腑
+      return Object.values(this.holdTimers || {}).some(t => !!t)
+    },
+    // 寮�濮嬭澶囩骇鍒濆鍖栭暱鎸�
+    startInitHold(deviceKey) {
+      this.pauseMonitoring()
+      if (this.holdTimers[deviceKey]) {
+        clearTimeout(this.holdTimers[deviceKey])
+      }
+      this.holdTimers[deviceKey] = setTimeout(() => {
+        this.handleOperation(deviceKey, 'cs')
+        this.holdTimers[deviceKey] = null
+        // 鍒濆鍖栬Е鍙戝畬鎴愬悗锛屾仮澶嶇洃鎺у苟纭繚鏃犳畫鐣欒交閲忚疆璇�
+        this.stopLiftSignalPolling()
+        this.resumeMonitoring()
+      }, this.holdDuration)
+    },
+
+    // 鍙栨秷璁惧绾у垵濮嬪寲闀挎寜
+    cancelInitHold(deviceKey) {
+      const t = this.holdTimers[deviceKey]
+      if (t) {
+        clearTimeout(t)
+        this.holdTimers[deviceKey] = null
+        // 鍙栨秷鍒濆鍖栭暱鎸夛紝鎭㈠鐩戞帶骞跺仠姝㈣交閲忚疆璇�
+        this.stopLiftSignalPolling()
+        this.resumeMonitoring()
+      }
+    },
+
+    // 寮�濮嬩竴閿垵濮嬪寲闀挎寜
+    startOneClickInitHold() {
+      this.pauseMonitoring()
+      if (this.oneClickInitTimer) {
+        clearTimeout(this.oneClickInitTimer)
+      }
+      this.oneClickInitTimer = setTimeout(() => {
+        this.handleOneClickOperation('init')
+        this.oneClickInitTimer = null
+        this.resumeMonitoring()
+      }, this.holdDuration)
+    },
+
+    // 鍙栨秷涓�閿垵濮嬪寲闀挎寜
+    cancelOneClickInitHold() {
+      if (this.oneClickInitTimer) {
+        clearTimeout(this.oneClickInitTimer)
+        this.oneClickInitTimer = null
+        this.resumeMonitoring()
+      }
+    },
+
+    // 鎸変笅鍗囬檷锛氬彂閫佸弬鏁�1
+    async handleLiftPress(deviceKey, operationType) {
+      // operationType: 'ss' or 'xj'
+      console.log('[LIFT][PRESS] event received', { deviceKey, operationType, ts: Date.now() })
+      if (this.activeLift && this.activeLift.deviceKey === deviceKey && this.activeLift.operationType === operationType) {
+        console.log('[LIFT][PRESS] skipped because same activeLift exists')
+        return
+      }
+      this.activeLift = { deviceKey, operationType }
+      // 浠呭綋宸插紑鍚洃鎺ф椂锛屾墠鏆傚仠鍏ㄥ眬杞骞跺紑鍚交閲忎俊鍙疯疆璇�
+      if (this.isMonitoring) {
+        this.pauseMonitoring()
+        this.startLiftSignalPolling(deviceKey)
+      }
+      // 璁板綍鎸変笅鏃堕棿鎴�
+      this.lastLiftPressAt[`${deviceKey}-${operationType}`] = Date.now()
+      // 涓嶇瓑寰咃紝搴忓垪鍖栧瓨鍌≒romise锛屼繚璇乺elease鏃舵寜椤哄簭鍙戦��
+      const key = `${deviceKey}-${operationType}`
+      console.log('[LIFT][PRESS] sending 1', { key, DelKeys: [deviceKey, operationType, 1] })
+      this.liftPressPromises[key] = this.http.post('api/Rgvoperainform/DeviceOperation', {
+        DelKeys: [deviceKey, operationType, 1],
+        Extra: true
+      }).then((response) => {
+        console.log('[LIFT][PRESS] response', { key, status: response && response.status, message: response && response.message })
+        if (!response.status) {
+          this.$message.error(response.message || `${this.operationTypes[operationType]}澶辫触`)
+        }
+      }).catch((error) => {
+        console.error('[LIFT][PRESS] error', { key, error })
+        this.$message.error(`${this.operationTypes[operationType]}璇锋眰澶辫触: ` + error.message)
+      })
+    },
+
+    // 鏉惧紑鍗囬檷锛氬彂閫佸弬鏁�0
+    async handleLiftRelease(deviceKey, operationType) {
+      console.log('[LIFT][RELEASE] event received', { deviceKey, operationType, ts: Date.now() })
+      if (!this.activeLift || this.activeLift.deviceKey !== deviceKey || this.activeLift.operationType !== operationType) {
+        console.log('[LIFT][RELEASE] skipped because activeLift not match', { activeLift: this.activeLift })
+        return
+      }
+      const key = `${deviceKey}-${operationType}`
+      if (this.liftReleaseInProgress[key]) {
+        // 宸叉湁閲婃斁璇锋眰鍦ㄨ繘琛岋紝閬垮厤閲嶅鍙戦��0锛堝彲鑳芥潵鑷厓绱犱簨浠�+鍏ㄥ眬浜嬩欢鐨勫弻瑙﹀彂锛�
+        console.log('[LIFT][RELEASE] skipped because release in progress', { key })
+        return
+      }
+      this.liftReleaseInProgress[key] = true
+      // 閲婃斁涓�寮�濮嬪氨鍋滄杞婚噺杞锛岄伩鍏嶇户缁崰鐢ㄧ綉缁滃鑷�0鍙戦�佸欢杩�
+      this.stopLiftSignalPolling()
+      // 闃叉鎸変笅鍚庢瀬鐭椂闂村唴灏辫Е鍙戦噴鏀惧鑷�0鍏堜簬1鎴�"鐪嬭捣鏉ュ彧鍙戜簡0"
+      const pressedAt = this.lastLiftPressAt[key] || 0
+      const elapsed = Date.now() - pressedAt
+      console.log('[LIFT][RELEASE] timing', { key, pressedAt, elapsed })
+      if (elapsed < 120) {
+        console.log('[LIFT][RELEASE] delaying to ensure press first', { delayMs: 120 - elapsed })
+        await new Promise(r => setTimeout(r, 120 - elapsed))
+      }
+      try {
+        const pressPromise = this.liftPressPromises[key]
+        if (pressPromise) {
+          console.log('[LIFT][RELEASE] awaiting press promise', { key })
+          // 鍔犺秴鏃朵繚鎶わ紝鑻ress闀挎椂闂存湭杩斿洖锛屼篃涓嶈鏃犻檺绛夛紝鏈�澶氱瓑300ms
+          const timeout = new Promise((_, rej) => setTimeout(() => rej(new Error('press wait timeout')), 300))
+          await Promise.race([pressPromise, timeout]).catch(err => {
+            console.warn('[LIFT][RELEASE] press await timeout or error, continue to send 0', err && err.message)
+          })
+        }
+        console.log('[LIFT][RELEASE] sending 0', { key, DelKeys: [deviceKey, operationType, 0] })
+        const response = await this.http.post('api/Rgvoperainform/DeviceOperation', {
+          DelKeys: [deviceKey, operationType, 0],
+          Extra: true
+        })
+        console.log('[LIFT][RELEASE] response', { key, status: response && response.status, message: response && response.message })
+        if (!response.status) {
+          this.$message.error(response.message || `${this.operationTypes[operationType]}鍋滄澶辫触`)
+        }
+      } catch (error) {
+        console.error('[LIFT][RELEASE] error', { key, error })
+        this.$message.error(`${this.operationTypes[operationType]}鍋滄璇锋眰澶辫触: ` + error.message)
+      } finally {
+        console.log('[LIFT][RELEASE] finalize cleanup', { key })
+        this.activeLift = null
+        delete this.liftPressPromises[key]
+        delete this.lastLiftPressAt[key]
+        delete this.liftReleaseInProgress[key]
+        this.stopLiftSignalPolling()
+        // 鎭㈠鍏ㄥ眬2s杞
+        this.resumeMonitoring()
+      }
+    },
     // 鍏ュ簱缁х画浠诲姟
     async handleInNormal(deviceKey) {
       this.setLoadingState(deviceKey, 'inNormal', true);
-      
+
       try {
         const response = await this.http.post("api/RgvOperation/WriteInNormal", {}, "鏁版嵁澶勭悊涓�...");
-        
+
         if (response.status) {
           this.$message.success('鍏ュ簱缁х画浠诲姟鎴愬姛');
-          this.refreshData();
+          if (this.isMonitoring) this.refreshData();
         } else {
           this.$message.error(response.message || '鍏ュ簱缁х画浠诲姟澶辫触');
         }
@@ -663,13 +937,13 @@
     // 鍏ュ簱寮傚父鎺掗櫎
     async handleInAbnormal(deviceKey) {
       this.setLoadingState(deviceKey, 'inAbnormal', true);
-      
+
       try {
         const response = await this.http.post("api/RgvOperation/WriteInAbnormal", {}, "鏁版嵁澶勭悊涓�...");
-        
+
         if (response.status) {
           this.$message.success('鍏ュ簱寮傚父鎺掗櫎鎴愬姛');
-          this.refreshData();
+          if (this.isMonitoring) this.refreshData();
         } else {
           this.$message.error(response.message || '鍏ュ簱寮傚父鎺掗櫎澶辫触');
         }
@@ -685,7 +959,8 @@
       const typeNames = {
         'inbound': '鍏ュ簱',
         'outbound': '鍑哄簱',
-        'safetydoor': '瀹夊叏闂�'
+        'safetydoor': '瀹夊叏闂�',
+        'platform': '绔欏彴'
       }
       const status = this.isMonitoring ? '杩愯涓�' : '宸插仠姝�'
       return `${typeNames[this.currentMonitorType]}鐩戞帶鐘舵��: ${status}`
@@ -711,6 +986,20 @@
       return ''
     },
 
+    // 绔欏彴瀛楁鍊兼牸寮忓寲
+    getPlatformFormattedValue(fieldKey, value) {
+      const formatter = this.platformValueFormatters[fieldKey]
+      return formatter ? formatter(value) : value
+    },
+
+    // 绔欏彴瀛楁鍊兼牱寮�
+    getPlatformValueClass(fieldKey, value) {
+      if (fieldKey === '鍏夌數淇″彿' && value === 1) {
+        return 'normal-text'
+      }
+      return ''
+    },
+
     // 瀹夊叏闂ㄦ寚绀虹伅鏍峰紡
     getSafetyLightClass(value) {
       const classMap = {
@@ -732,9 +1021,9 @@
     async handleOneClickOperation(operationType) {
       // 鏍规嵁褰撳墠鐩戞帶绫诲瀷璁剧疆鍙傛暟
       const monitorType = this.currentMonitorType === 'inbound' ? 'Inbound' : 'Outbound'
-      
+
       this.oneClickLoading[operationType] = true
-      
+
       try {
         const operationNames = {
           init: '涓�閿垵濮嬪寲',
@@ -742,12 +1031,12 @@
           start: '涓�閿惎鍔�',
           stop: '涓�閿殏鍋�'
         }
-        
+
         const response = await this.http.post('api/Rgvoperainform/OneClickOperation', {
           operationType: operationType,
           monitorType: monitorType
         }, `${operationNames[operationType]}涓�...`)
-        
+
         if (response.status) {
           this.$message.success(`${operationNames[operationType]} ${monitorType}绔澶囨垚鍔焋)
           this.refreshData()
@@ -765,6 +1054,90 @@
     getInitializationButtonText(deviceData) {
       if (!deviceData) return '鍒濆鍖�'
       return deviceData['鍒濆鍖栨湭瀹屾垚鏍囧織浣�'] === 0 ? '宸插垵濮嬪寲' : '鍒濆鍖�'
+    },
+
+    // 鐐瑰嚮寮忓崌闄嶏細鐘舵�佹煡璇�
+    isLifting(deviceKey) {
+      const st = this.activeLiftStates[deviceKey]
+      return !!(st && st.ss === true)
+    },
+    isLowering(deviceKey) {
+      const st = this.activeLiftStates[deviceKey]
+      return !!(st && st.xj === true)
+    },
+
+    // 鍚姩鍗囬檷锛堢偣鍑讳竴娆″彂1锛�
+    async startLift(deviceKey, operationType) {
+      // operationType: 'ss' | 'xj'
+      const isManual = this.isManualMode && this.isManualMode(this.currentMonitorDataMap()?.[deviceKey])
+      if (!isManual) {
+        this.$message.warning('璇峰垏鎹负鎵嬪姩妯″紡鍚庡啀鎿嶄綔')
+        return
+      }
+      // 浜掓枼涓庨槻閲�
+      const st = this.activeLiftStates[deviceKey] || { ss: false, xj: false }
+      if ((operationType === 'ss' && (st.ss || st.xj)) || (operationType === 'xj' && (st.xj || st.ss))) {
+        return
+      }
+      // 璁剧疆鍚姩鎬�
+      this.activeLiftStates = { ...this.activeLiftStates, [deviceKey]: { ...st, [operationType]: true } }
+      try {
+        const resp = await this.http.post('api/Rgvoperainform/DeviceOperation', {
+          DelKeys: [deviceKey, operationType, 1],
+          Extra: true
+        })
+        if (!resp.status) {
+          this.$message.error((this.operationTypes && this.operationTypes[operationType]) ? `${this.operationTypes[operationType]}澶辫触` : '鎸囦护鍙戦�佸け璐�')
+          // 鍥炴粴鐘舵��
+          const cur = this.activeLiftStates[deviceKey] || {}
+          this.activeLiftStates = { ...this.activeLiftStates, [deviceKey]: { ...cur, [operationType]: false } }
+          return
+        }
+        // 鎴愬姛鍚庡惎鍔ㄨ秴鏃惰嚜鍔ㄥ仠姝�
+        const key = `${deviceKey}-${operationType}`
+        this.clearLiftTimeout(key)
+        this.liftAutoStopTimeouts[key] = setTimeout(() => {
+          // 瓒呮椂鑷姩鍙戦��0
+          this.stopLift(deviceKey, operationType, true)
+          this.$message.warning('鍗囬檷鍔ㄤ綔瓒呮椂锛屽凡鑷姩鍋滄')
+        }, this.liftCommandTimeoutMs)
+      } catch (e) {
+        this.$message.error('璇锋眰澶辫触: ' + e.message)
+        // 鍥炴粴鐘舵��
+        const cur = this.activeLiftStates[deviceKey] || {}
+        this.activeLiftStates = { ...this.activeLiftStates, [deviceKey]: { ...cur, [operationType]: false } }
+      }
+    },
+
+    // 鍋滄鍗囬檷锛堢偣鍑讳竴娆″彂0锛�
+    async stopLift(deviceKey, operationType, fromTimeout = false) {
+      // 鍗充娇鏈褰曚负鍚姩鎬侊紝涔熷厑璁稿彂閫�0锛屼繚璇佸仠姝㈡寜閽湪鎵嬪姩妯″紡涓嬪缁堝彲鐢�
+      const st = this.activeLiftStates[deviceKey] || { ss: false, xj: false }
+      try {
+        const resp = await this.http.post('api/Rgvoperainform/DeviceOperation', {
+          DelKeys: [deviceKey, operationType, 0],
+          Extra: true
+        })
+        if (!resp.status && !fromTimeout) {
+          this.$message.error((this.operationTypes && this.operationTypes[operationType]) ? `${this.operationTypes[operationType]}鍋滄澶辫触` : '鍋滄鎸囦护澶辫触')
+          return
+        }
+      } catch (e) {
+        if (!fromTimeout) this.$message.error('鍋滄璇锋眰澶辫触: ' + e.message)
+      } finally {
+        // 缃负鍋滄鎬佸苟娓呯悊瓒呮椂瀹氭椂鍣�
+        const cur = this.activeLiftStates[deviceKey] || {}
+        this.activeLiftStates = { ...this.activeLiftStates, [deviceKey]: { ...cur, [operationType]: false } }
+        const key = `${deviceKey}-${operationType}`
+        this.clearLiftTimeout(key)
+      }
+    },
+
+    clearLiftTimeout(key) {
+      if (this.liftAutoStopTimeouts[key]) {
+        clearTimeout(this.liftAutoStopTimeouts[key])
+        delete this.liftAutoStopTimeouts[key]
+      }
     },
 
     // 鍒囨崲鐩戞帶绫诲瀷
@@ -789,6 +1162,7 @@
 
     // 鐩戞帶鎺у埗鏂规硶
     async toggleMonitoring() {
+      if (this.monitoringLoading) return
       if (this.isMonitoring) {
         this.stopMonitoring()
       } else {
@@ -798,13 +1172,14 @@
 
     async startMonitoring() {
       try {
+        this.monitoringLoading = true
         const param = {
           off: 1,
           monitorType: this.currentMonitorType
         }
-        
+
         const response = await this.http.post('api/Rgvoperainform/GetDeviceStatusDto', param)
-        
+
         if (response.status) {
           this.isMonitoring = true
           // 鏍规嵁鐩戞帶绫诲瀷鏇存柊瀵瑰簲鐨勮澶囨暟鎹�
@@ -818,6 +1193,9 @@
             case 'safetydoor':
               this.safetyDoorDeviceData = response.data
               break
+            case 'platform':
+              this.platformDeviceData = response.data
+              break
           }
           this.startPolling()
           this.$message.success(`${this.getMonitorStatusTitle()}宸插惎鍔╜)
@@ -826,6 +1204,8 @@
         }
       } catch (error) {
         this.$message.error('璇锋眰澶辫触: ' + error.message)
+      } finally {
+        this.monitoringLoading = false
       }
     },
 
@@ -835,18 +1215,18 @@
         clearTimeout(this.pollingTimer)
         this.pollingTimer = null
       }
-      
+
       this.http.post('api/Rgvoperainform/GetDeviceStatusDto', {
         off: 0,
         monitorType: this.currentMonitorType
       })
-      
+
       this.$message.info(`${this.getMonitorStatusTitle()}宸插仠姝)
     },
 
     startPolling() {
       this.pollingTimer = setTimeout(() => {
-        if (this.isMonitoring) {
+        if (this.isMonitoring && !this.monitoringPaused) {
           this.refreshData()
           this.startPolling()
         }
@@ -855,24 +1235,68 @@
 
     async refreshData() {
       if (!this.isMonitoring) return
+      if (this.monitoringPaused) return
 
       try {
-        const response = await this.http.post('api/Rgvoperainform/GetDeviceStatusDto', { 
+        const response = await this.http.post('api/Rgvoperainform/GetDeviceStatusDto', {
           off: 1,
           monitorType: this.currentMonitorType
         })
         if (response.status) {
-          // 鏍规嵁鐩戞帶绫诲瀷鏇存柊瀵瑰簲鐨勮澶囨暟鎹�
-          switch (this.currentMonitorType) {
-            case 'inbound':
-              this.inboundDeviceData = response.data
-              break
-            case 'outbound':
-              this.outboundDeviceData = response.data
-              break
-            case 'safetydoor':
-              this.safetyDoorDeviceData = response.data
-              break
+          // 鍦ㄥ崌闄嶉暱鎸夋椂锛屼粎鍚堝苟褰撳墠璁惧鐨勫埌浣嶄俊鍙凤紝閬垮厤澶ч潰绉噸缁橀�犳垚鎵撴柇
+          if (this.activeLift) {
+            const { deviceKey } = this.activeLift
+            const respKeys = Object.keys(response.data || {})
+            const respKey = respKeys.find(k => k.toLowerCase() === String(deviceKey).toLowerCase())
+            const dev = respKey ? response.data[respKey] : null
+            const mergeSignals = (mapObj, setter) => {
+              if (!mapObj) return false
+              const old = mapObj[deviceKey]
+              if (!old) return false
+              const patch = { ...old }
+              const riseVal = Object.prototype.hasOwnProperty.call(dev || {}, '涓婂崌淇″彿鍒颁綅') ? dev['涓婂崌淇″彿鍒颁綅']
+                : (Object.prototype.hasOwnProperty.call(dev || {}, 'RGV_Risingsignalplace') ? dev['RGV_Risingsignalplace']
+                : (Object.prototype.hasOwnProperty.call(dev || {}, 'RiseArrived') ? dev['RiseArrived'] : undefined))
+              const downVal = Object.prototype.hasOwnProperty.call(dev || {}, '涓嬮檷淇″彿鍒颁綅') ? dev['涓嬮檷淇″彿鍒颁綅']
+                : (Object.prototype.hasOwnProperty.call(dev || {}, 'RGV_Descentsignal') ? dev['RGV_Descentsignal']
+                : (Object.prototype.hasOwnProperty.call(dev || {}, 'DescendArrived') ? dev['DescendArrived'] : undefined))
+              if (riseVal !== undefined) patch['涓婂崌淇″彿鍒颁綅'] = riseVal
+              if (downVal !== undefined) patch['涓嬮檷淇″彿鍒颁綅'] = downVal
+              setter({ ...mapObj, [deviceKey]: patch })
+              if (typeof this.$forceUpdate === 'function') this.$forceUpdate()
+              return true
+            }
+
+            let merged = false
+            if (this.currentMonitorType === 'inbound') merged = mergeSignals(this.inboundDeviceData, v => this.inboundDeviceData = v)
+            if (this.currentMonitorType === 'outbound') merged = mergeSignals(this.outboundDeviceData, v => this.outboundDeviceData = v)
+            if (this.currentMonitorType === 'safetydoor') merged = mergeSignals(this.safetyDoorDeviceData, v => this.safetyDoorDeviceData = v)
+            if (this.currentMonitorType === 'platform') merged = mergeSignals(this.platformDeviceData, v => this.platformDeviceData = v)
+
+            if (!merged) {
+              merged = mergeSignals(this.inboundDeviceData, v => this.inboundDeviceData = v) ||
+                mergeSignals(this.outboundDeviceData, v => this.outboundDeviceData = v) ||
+                mergeSignals(this.safetyDoorDeviceData, v => this.safetyDoorDeviceData = v) ||
+                mergeSignals(this.platformDeviceData, v => this.platformDeviceData = v)
+            }
+          } else {
+            // 闈為暱鎸夛紝姝e父鏇挎崲鏁版嵁闆�
+            switch (this.currentMonitorType) {
+              case 'inbound':
+                this.inboundDeviceData = response.data
+                break
+              case 'outbound':
+                this.outboundDeviceData = response.data
+                break
+              case 'safetydoor':
+                this.safetyDoorDeviceData = response.data
+                break
+              case 'platform':
+                this.platformDeviceData = response.data
+                break
+            }
+            // 鐐瑰嚮寮忥細妫�娴嬪埌浣嶅悗鑷姩鍋滄瀵瑰簲鍔ㄤ綔
+            this.autoStopLiftIfArrived()
           }
         }
       } catch (error) {
@@ -880,10 +1304,38 @@
       }
     },
 
+    // 鑻ヨ澶囧湪鐐瑰嚮寮忓崌闄嶄腑锛屾娴嬪埌涓�/涓嬪埌浣嶅垯鑷姩鍙戦�佸仠姝�
+    autoStopLiftIfArrived() {
+      const dataMap = this.currentMonitorDataMap()
+      if (!dataMap) return
+      Object.keys(this.activeLiftStates).forEach(deviceKey => {
+        const state = this.activeLiftStates[deviceKey] || {}
+        const dev = dataMap[deviceKey]
+        if (!dev) return
+        if (state.ss && (dev['涓婂崌淇″彿鍒颁綅'] === 1 || dev['RGV_Risingsignalplace'] === 1 || dev['RiseArrived'] === 1)) {
+          this.stopLift(deviceKey, 'ss')
+        }
+        if (state.xj && (dev['涓嬮檷淇″彿鍒颁綅'] === 1 || dev['RGV_Descentsignal'] === 1 || dev['DescendArrived'] === 1)) {
+          this.stopLift(deviceKey, 'xj')
+        }
+      })
+    },
+
+    // 杩斿洖褰撳墠鐩戞帶绫诲瀷鐨勬暟鎹槧灏�
+    currentMonitorDataMap() {
+      switch (this.currentMonitorType) {
+        case 'inbound': return this.inboundDeviceData
+        case 'outbound': return this.outboundDeviceData
+        case 'safetydoor': return this.safetyDoorDeviceData
+        case 'platform': return this.platformDeviceData
+        default: return null
+      }
+    },
+
     // 鍏朵粬鍘熸湁鏂规硶淇濇寔涓嶅彉
     getStatusClass(device) {
       if (!device || Object.keys(device).length === 0) return 'offline'
-      
+
       // 瀹夊叏闂ㄧ姸鎬佸垽鏂�
       if (this.currentMonitorType === 'safetydoor') {
         if (device['瀹夊叏闂ㄦ�ュ仠鐘舵��'] === 0) return 'fault'
@@ -891,7 +1343,13 @@
         if (device['鎶ヨ淇℃伅'] === 1) return 'fault'
         return 'normal'
       }
-      
+
+      // 绔欏彴鐘舵�佸垽鏂�
+      if (this.currentMonitorType === 'platform') {
+        if (device['鍏夌數淇″彿'] === 1) return 'running'
+        return 'normal'
+      }
+
       // RGV璁惧鐘舵�佸垽鏂�
       if (device['鏁呴殰浠g爜'] !== 0) return 'fault'
       if (device['浠诲姟鐘舵��'] === 1) return 'running'
@@ -921,17 +1379,19 @@
 
     // 鑾峰彇璁惧绫诲瀷
     getDeviceType(deviceKey) {
-      if (this.deviceTypes.motherCars.includes(deviceKey) || 
-          this.deviceTypes.outboundMotherCars.includes(deviceKey)) {
+      if (this.deviceTypes.motherCars.includes(deviceKey) ||
+        this.deviceTypes.outboundMotherCars.includes(deviceKey)) {
         return 'mother'
-      } else if (this.deviceTypes.childCars.includes(deviceKey) || 
-                this.deviceTypes.outboundChildCars.includes(deviceKey)) {
+      } else if (this.deviceTypes.childCars.includes(deviceKey) ||
+        this.deviceTypes.outboundChildCars.includes(deviceKey)) {
         return 'child'
-      } else if (this.deviceTypes.materialCars.includes(deviceKey) || 
-                this.deviceTypes.outboundMaterialCars.includes(deviceKey)) {
+      } else if (this.deviceTypes.materialCars.includes(deviceKey) ||
+        this.deviceTypes.outboundMaterialCars.includes(deviceKey)) {
         return 'material'
       } else if (this.deviceTypes.safetyDoors.includes(deviceKey)) {
         return 'safetydoor'
+      } else if (this.deviceTypes.platforms.includes(deviceKey)) {
+        return 'platform'
       }
       return 'unknown'
     },
@@ -944,10 +1404,10 @@
     // 鑾峰彇鎶ヨ鏂囨湰
     getAlarmText(alarmCode, deviceKey) {
       if (alarmCode === 0) return '鏃犳姤璀�'
-      
+
       const deviceType = this.getDeviceType(deviceKey)
       let alarmMap = {}
-      
+
       switch (deviceType) {
         case 'mother':
           alarmMap = this.motherCarAlarmCodes
@@ -961,7 +1421,7 @@
         default:
           alarmMap = this.motherCarAlarmCodes
       }
-      
+
       return alarmMap[alarmCode] || `鏈繛鎺�(${alarmCode})`
     },
 
@@ -977,9 +1437,10 @@
       return deviceData['宸ヤ綔妯″紡'] === 1 ? 'warning' : 'success'
     },
 
-    // 鍒ゆ柇鏄惁涓烘墜鍔ㄦā寮�
+    // 鍒ゆ柇鏄惁涓烘墜鍔ㄦā寮忥紙浠呭綋鏄庣‘涓�1=鑷姩鏃惰涓洪潪鎵嬪姩锛泆ndefined/0閮芥寜鎵嬪姩澶勭悊锛�
     isManualMode(deviceData) {
-      return deviceData && deviceData['宸ヤ綔妯″紡'] === 0
+      if (!deviceData) return false
+      return deviceData['宸ヤ綔妯″紡'] !== 1
     },
 
     // 鑾峰彇闆疯揪鎸夐挳鏂囨湰
@@ -1006,21 +1467,21 @@
     // 鎵嬪姩/鑷姩妯″紡鍒囨崲
     async handleModeToggle(deviceKey) {
       this.setLoadingState(deviceKey, 'modeToggle', true)
-      
+
       try {
         const deviceData = this.currentDeviceData[deviceKey]
         const currentMode = deviceData?.['宸ヤ綔妯″紡'] || 0
-        
+
         const operationType = currentMode === 0 ? 'zd' : 'sd'
-        
+
         const response = await this.http.post('api/Rgvoperainform/DeviceOperation', {
           DelKeys: [deviceKey, operationType],
           Extra: true
         }, `${this.operationTypes[operationType]}涓�...`)
-        
+
         if (response.status) {
           this.$message.success(`${this.getDeviceDisplayName(deviceKey)} ${this.operationTypes[operationType]}鎴愬姛`)
-          this.refreshData()
+          if (this.isMonitoring) this.refreshData()
         } else {
           this.$message.error(response.message || `${this.operationTypes[operationType]}澶辫触`)
         }
@@ -1034,18 +1495,18 @@
     // 闆疯揪寮�鍏冲垏鎹�
     async handleRadarToggle(deviceKey) {
       this.setLoadingState(deviceKey, 'radarToggle', true)
-      
+
       try {
         const deviceData = this.currentDeviceData[deviceKey]
         const currentRadarState = deviceData?.['闆疯揪鐘舵��'] || 0
-        
+
         const operationType = currentRadarState === 0 ? 'kld' : 'gld'
-        
+
         const response = await this.http.post('api/Rgvoperainform/DeviceOperation', {
           DelKeys: [deviceKey, operationType],
           Extra: true
         }, `${this.operationTypes[operationType]}涓�...`)
-        
+
         if (response.status) {
           this.$message.success(`${this.getDeviceDisplayName(deviceKey)} ${this.operationTypes[operationType]}鎴愬姛`)
           this.refreshData()
@@ -1068,16 +1529,16 @@
       }
 
       this.setLoadingState(deviceKey, 'dz', true)
-      
+
       try {
         const response = await this.http.post('api/Rgvoperainform/DeviceOperation', {
           DelKeys: [deviceKey, 'dz', address],
           Extra: true
         }, '鍓嶅線鍦板潃涓�...')
-        
+
         if (response.status) {
           this.$message.success(`${this.getDeviceDisplayName(deviceKey)} 鍓嶅線鍦板潃 ${address} 鎴愬姛`)
-          this.refreshData()
+          if (this.isMonitoring) this.refreshData()
         } else {
           this.$message.error(response.message || '鍓嶅線鍦板潃澶辫触')
         }
@@ -1091,28 +1552,22 @@
     // 缁熶竴鎿嶄綔澶勭悊鍑芥暟
     async handleOperation(deviceKey, operationType) {
       this.setLoadingState(deviceKey, operationType, true)
-      
+
       try {
+        // 涓婂崌/涓嬮檷闇�瑕佺涓変釜鍙傛暟缃綅
+        const delKeys = (operationType === 'ss' || operationType === 'xj')
+          ? [deviceKey, operationType, 1]
+          : [deviceKey, operationType]
+
         const response = await this.http.post('api/Rgvoperainform/DeviceOperation', {
-          DelKeys: [deviceKey, operationType],
+          DelKeys: delKeys,
           Extra: true
         }, `${this.operationTypes[operationType]}涓�...`)
-        
+
         if (response.status) {
           const operationName = this.operationTypes[operationType]
           this.$message.success(`${this.getDeviceDisplayName(deviceKey)} ${operationName}鎿嶄綔鎴愬姛`)
-          
-          // 濡傛灉鏄垵濮嬪寲鎿嶄綔锛屾坊鍔犻澶栨彁绀�
-          if (operationType === 'cs') {
-            this.$notify({
-              title: '鍒濆鍖栨垚鍔�',
-              message: `${this.getDeviceDisplayName(deviceKey)} 璁惧鍒濆鍖栧畬鎴恅,
-              type: 'success',
-              duration: 3000
-            })
-          }
-          
-          this.refreshData()
+          if (this.isMonitoring) this.refreshData()
         } else {
           this.$message.error(response.message || `${this.operationTypes[operationType]}鎿嶄綔澶辫触`)
         }
@@ -1124,13 +1579,40 @@
     }
   },
 
+  mounted() {
+    // 鍏ㄥ眬閲婃斁鍏滃簳锛岄槻姝㈡寚閽堢Щ鍑烘寜閽尯鍩熸垨绐楀彛瀵艰嚧鏃犳硶鍙戦�� 0
+    this._liftGlobalRelease = () => {
+      if (this.activeLift) {
+        const { deviceKey, operationType } = this.activeLift
+        this.handleLiftRelease(deviceKey, operationType)
+      }
+    }
+    window.addEventListener('mouseup', this._liftGlobalRelease)
+    window.addEventListener('touchend', this._liftGlobalRelease, { passive: true })
+    window.addEventListener('blur', this._liftGlobalRelease)
+    document.addEventListener('visibilitychange', () => {
+      if (document.hidden) this._liftGlobalRelease()
+    })
+  },
+
   beforeUnmount() {
     this.stopMonitoring()
+    if (this._liftGlobalRelease) {
+      window.removeEventListener('mouseup', this._liftGlobalRelease)
+      window.removeEventListener('touchend', this._liftGlobalRelease)
+      window.removeEventListener('blur', this._liftGlobalRelease)
+    }
   }
 }
 </script>
 
 <style scoped>
+/* 娣诲姞绔欏彴姝e父鏂囨湰鏍峰紡 */
+.normal-text {
+  color: #67C23A;
+  font-weight: bold;
+}
+
 /* 鍘熸湁鐨勬牱寮忎繚鎸佷笉鍙橈紝娣诲姞瀹夊叏闂ㄧ浉鍏虫牱寮� */
 
 /* 瀹夊叏闂ㄦ寚绀虹伅鏍峰紡 */
@@ -1393,14 +1875,30 @@
 }
 
 @keyframes pulse {
-  0% { opacity: 1; }
-  50% { opacity: 0.5; }
-  100% { opacity: 1; }
+  0% {
+    opacity: 1;
+  }
+
+  50% {
+    opacity: 0.5;
+  }
+
+  100% {
+    opacity: 1;
+  }
 }
 
 @keyframes blink {
-  0%, 50% { opacity: 1; }
-  51%, 100% { opacity: 0.3; }
+
+  0%,
+  50% {
+    opacity: 1;
+  }
+
+  51%,
+  100% {
+    opacity: 0.3;
+  }
 }
 
 /* 鍝嶅簲寮忚璁� */
@@ -1408,7 +1906,7 @@
   .devices-container {
     grid-template-columns: 1fr;
   }
-  
+
   .monitor-header {
     flex-direction: column;
     gap: 15px;

--
Gitblit v1.9.3