From d79ce11fcd47db138764557d214f4ea2169fb90a Mon Sep 17 00:00:00 2001
From: WXL <1785969728@qq.com>
Date: 星期五, 20 六月 2025 18:05:38 +0800
Subject: [PATCH] 维护

---
 src/views/ecg/callingscreen/roomscreen.vue |  980 ++++++++++++++++++++++++++++++++++++++++++++-------------
 1 files changed, 752 insertions(+), 228 deletions(-)

diff --git a/src/views/ecg/callingscreen/roomscreen.vue b/src/views/ecg/callingscreen/roomscreen.vue
index 2498b97..be74bd6 100644
--- a/src/views/ecg/callingscreen/roomscreen.vue
+++ b/src/views/ecg/callingscreen/roomscreen.vue
@@ -1,247 +1,771 @@
-<script setup lang="ts">
-
-import {RoomProfileVO} from "@/api/ecg/doctor";
-import {RoomApi} from "@/api/ecg/room";
-import {ScreenQueueVO, ScreenApi} from "@/api/ecg/screen";
-import {CallApi, CallVO} from "@/api/ecg/call";
-import {queueStatusConvert} from "../../../utils/statusFormatter";
-import {getCheckTypeName, getCheckTypeSeqPrefix} from "../../../utils/checkTypeFormatter";
-
-defineOptions({ name: 'roomscreen' })
-let roomId = ref<number>(0)
-
-const checkRelatedPatientList = ref<ScreenQueueVO[]>([])
-const installRelatedPatientList = ref<ScreenQueueVO[]>([])
-
-let curSpeakPat : CallVO | null = null;
-
-const roomProfile = ref<RoomProfileVO>()
-
-const getList = async () => {
-  const data = await ScreenApi.getRoomScreenData(roomId.value)
-  checkRelatedPatientList.value = data[1]
-  installRelatedPatientList.value = data[2]
-}
-
-const getRoomByIp = async () => {
-  const data = await RoomApi.getRoomByIP(roomId.value)
-  roomProfile.value = data
-}
-
-const startScrolling = () => {
-  setInterval(() => {
-    getList()
-    if ( curSpeakPat === null ) {
-      initiateSpeak()
-    }
-  }, 3000); // 姣忎袱绉掓粴鍔ㄤ竴娆�
-}
-
-const nameDesensitize = (patName) => {
-  if (patName.length == 2) {
-    //鎴彇name 瀛楃涓叉埅鍙栫涓�涓瓧绗︼紝
-    return patName.substring(0, 1) + '*';
-  } else if (patName.length == 3) {
-    //鎴彇绗竴涓拰绗笁涓瓧绗�
-    return patName.substring(0, 1) + '*' + patName.substring(2, 3);
-  } else if (patName.length > 3) {
-    //鎴彇绗竴涓拰澶т簬绗�4涓瓧绗�
-    return (
-        patName.substring(0, 1) + '*' + '*' + patName.substring(3, patName.length)
-    );
-  }
-}
-
-const tableRowClassName = ({row, rowIndex}: {
-  row: ScreenQueueVO
-  rowIndex: number
-}) => {
-  if (row.status === 5) {
-    return 'warning-row'
-  } else if (row.status === 7) {
-    return 'warning-row'  //return 'success-row'
-  }
-  return ''
-}
-
-const onSpeachEndEvent = async (event) => {
-  console.log("Speech ended... " + event.currentTarget.text);
-  curSpeakPat!.called = 1
-  await CallApi.updateCall(curSpeakPat!)
-  initiateSpeak()
-}
-
-const initiateSpeak = async () => {
-  //TODO: 娴嬭瘯鐢紝鏆傛椂涓嶆挱闊�
-  return;
-
-  curSpeakPat = await CallApi.getNextInstallCall()
-  if (curSpeakPat == null)
-    return;
-
-  speak("璇枫��" + curSpeakPat.patName + "鍒�" + curSpeakPat.roomName + "瑁呮満");
-}
-
-const speak = (msg) => {
-  console.info("speak " + msg);
-  var speech = new SpeechSynthesisUtterance()
-  speech.text = msg + "銆傘�傘��" + msg + "銆傘�傘��" + msg  + "銆傘�傘��"
-  speech.pitch = 1 // 鑾峰彇骞惰缃瘽璇殑闊宠皟(0-2 榛樿1锛屽�艰秺澶ц秺灏栭攼,瓒婁綆瓒婁綆娌�)
-  speech.rate = 0.9 // 鑾峰彇骞惰缃璇濈殑閫熷害(0.1-10 榛樿1锛屽�艰秺澶ц閫熻秺蹇�,瓒婂皬璇�熻秺鎱�)
-  speech.volume = 100 // 鑾峰彇骞惰缃璇濈殑闊抽噺
-  speech.lang = 'zh-CN' // 璁剧疆鎾斁璇█
-
-  speech.onend = onSpeachEndEvent
-  speechSynthesis.speak(speech)
-}
-
-onMounted( () => {
-  getRoomByIp()
-  startScrolling()
-})
-
-</script>
-
 <template>
-  <el-container style="height: 100%;">
-    <el-header style="font-size: 25px">
-      {{ roomProfile?.roomName||'-' }} {{roomProfile?.callingScreenType}}
-      <el-input-number v-model="roomId"  @change="getRoomByIp" />
-    </el-header>
-    <el-main>
-      <div class="layout-content">
-        <div class="left" v-if="roomProfile?.callingScreenType === 10 || roomProfile?.callingScreenType === 20 || roomProfile?.callingScreenType === 40 || roomProfile?.callingScreenType === 50">
-          <el-table
-              :data="checkRelatedPatientList"
-              :show-header="false"
-              style="width: 100%; height: 100%; border: solid var(--el-color-primary-light-7); font-size: 18px;"
-              :row-class-name="tableRowClassName"
-          >
-            <el-table-column
-                prop="patName"
-                label="棰勭害搴忓彿"
-                width="60px">
-              <template #default="scope">
-                <span style="display:inline-block; width:60px;">{{getCheckTypeSeqPrefix(scope.row.bookCheckType)}}{{scope.row.bookSeqNum}} </span>
-              </template>
-            </el-table-column>
-            <el-table-column
-                prop="patName"
-                label="鎮h�呭鍚�"
-                width="80px">
-              <template #default="scope">
-                <span style="display:inline-block; width:80px;">{{ nameDesensitize(scope.row.patName) }} </span>
-              </template>
-            </el-table-column>
-            <el-table-column
-                prop="patName"
-                label="妫�鏌ラ」鐩�"
-                width="80px">
-              <template #default="scope">
-                <span style="display:inline-block; width:80px;">{{scope.row.bookCheckType && getCheckTypeName(scope.row.bookCheckType)}} </span>
-              </template>
-            </el-table-column>
-            <el-table-column label="鐘舵��" align="center" width="200px">
-              <template #default="scope">
-                <!--            <dict-tag :type="DICT_TYPE.ECG_QUEUE_STATUS" :value="scope.row.status" />-->
-                {{queueStatusConvert(scope.row.status)}} {{scope.row.bedNo}}
-              </template>
-            </el-table-column>
-          </el-table>
+  <div class="room-screen-container">
+    <div class="search-bar">
+      <input
+        class="search-input"
+        type="text"
+        placeholder="璇疯緭鍏ユ埧闂村彿鏌ヨ"
+        v-model="searchRoomInput"
+        @keyup.enter="searchRoom"
+      />
+      <button class="search-btn" @click="searchRoom"> 鏌ヨ </button>
+    </div>
+
+    <div class="header">
+      <div class="clinic-title">蹇冪數鍥捐瘖闂村彨鍙风郴缁�</div>
+      <div class="clinic-info">
+        <div class="room-name">
+          {{ roomProfile.roomName || '璇婇棿鍔犺浇涓�...' }}
         </div>
-        <div class="right" v-if="roomProfile?.callingScreenType === 30 || roomProfile?.callingScreenType === 40 || roomProfile?.callingScreenType === 50">
-          <el-table
-              :data="installRelatedPatientList"
-              :show-header="false"
-              style="width: 100%; height: 100%; border: solid var(--el-color-primary-light-7); font-size: 18px;"
-              :row-class-name="tableRowClassName"
+        <div class="screen-type"> 妯″紡锛歿{ screenTypeText }} </div>
+      </div>
+    </div>
+
+    <div class="main-content">
+      <div class="panel" v-if="showCheckPanel">
+        <div class="panel-header">妫�鏌ラ槦鍒�</div>
+        <div class="patient-list">
+          <div v-if="checkRelatedPatientList.length === 0" class="empty-state">
+            鏆傛棤绛夊緟妫�鏌ョ殑鎮h��
+          </div>
+          <div
+            v-for="(patient, index) in checkRelatedPatientList"
+            :key="'check-' + index"
+            class="patient-item"
+            :class="getStatusClass(patient.status)"
           >
-            <el-table-column
-                prop="patName"
-                label="棰勭害搴忓彿"
-                width="60px">
-              <template #default="scope">
-                <span style="display:inline-block; width:60px;">{{getCheckTypeSeqPrefix(scope.row.bookCheckType)}}{{scope.row.bookSeqNum}} </span>
-              </template>
-            </el-table-column>
-            <el-table-column
-                prop="patName"
-                label="鎮h�呭鍚�"
-                width="80px">
-              <template #default="scope">
-                <span style="display:inline-block; width:80px;">{{ nameDesensitize(scope.row.patName) }} </span>
-              </template>
-            </el-table-column>
-            <el-table-column
-                prop="patName"
-                label="妫�鏌ラ」鐩�"
-                width="80px">
-              <template #default="scope">
-                <span style="display:inline-block; width:80px;">{{scope.row.bookCheckType && getCheckTypeName(scope.row.bookCheckType)}} </span>
-              </template>
-            </el-table-column>
-            <el-table-column label="鐘舵��" align="center" width="200px">
-              <template #default="scope">
-                <!--            <dict-tag :type="DICT_TYPE.ECG_QUEUE_STATUS" :value="scope.row.status" />-->
-                {{queueStatusConvert(scope.row.status)}} {{scope.row.bedNo}}
-              </template>
-            </el-table-column>
-          </el-table>
+            <div class="patient-info">
+              <div class="patient-number"> {{ getSeqPrefix(patient) }}{{ patient.bedNo }} </div>
+              <div class="patient-name">
+                {{ nameDesensitize(patient.patName) }}
+              </div>
+              <div class="patient-check-type">
+                {{ getCheckTypeName(patient.bookCheckType) }}
+              </div>
+              <div class="patient-status" :class="'status-' + getStatusClass(patient.status)">
+                {{ queueStatusConvert(patient.status) }}
+              </div>
+            </div>
+          </div>
         </div>
       </div>
-    </el-main>
-    <el-button @click="speak('娆㈣繋浣跨敤')" >娆㈣繋浣跨敤</el-button>
-<!--
-    <el-footer height="100px" style="padding: 0 0">
-          <el-header height="30px" style="background-color: #98b8e5; line-height: 30px;">杩囧彿鍖�</el-header>
-          <span v-for="(passedItem, index) in installRelatedPatientList" :key="index">
-                {{nameDesensitize(passedItem.patName) + "&nbsp;&nbsp;&nbsp;&nbsp;"}}
-          </span>
-    </el-footer>
--->
-  </el-container>
+
+      <div class="panel" v-if="showInstallPanel">
+        <div class="panel-header">瑁呮満闃熷垪</div>
+        <div class="patient-list">
+          <div v-if="installRelatedPatientList.length === 0" class="empty-state">
+            鏆傛棤绛夊緟瑁呮満鐨勬偅鑰�
+          </div>
+          <div
+            v-for="(patient, index) in installRelatedPatientList"
+            :key="'install-' + index"
+            class="patient-item"
+            :class="getStatusClass(patient.status)"
+          >
+            <div class="patient-info">
+              <div class="patient-number">
+                {{ patient.bookSeqNum }}
+              </div>
+              <div class="patient-name">
+                {{ nameDesensitize(patient.patName) }}
+              </div>
+              <div class="patient-check-type">
+                {{ getCheckTypeName(patient.bookCheckType) }}
+              </div>
+              <div class="patient-status" :class="'status-' + getStatusClass(patient.status)">
+                {{ queueStatusConvert(patient.status) }}
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+
+    <div class="footer">
+      <div class="announcement">
+        {{ announcementText }}
+      </div>
+      <div class="controls">
+        <button class="control-btn pulse" @click="initiateSpeak">
+          <i>馃摙</i>
+          <span>鍙彿</span>
+        </button>
+        <button class="flex-1 control-btn" @click="speak('娆㈣繋浣跨敤璇婇棿鍙彿绯荤粺')">
+          <i>馃攰</i>
+          <span>娴嬭瘯鎾煶</span>
+        </button>
+        <button class="flex-1 control-btn" @click="changeRoom">
+          <i>馃攧</i>
+          <span>鍒囨崲璇婇棿</span>
+        </button>
+      </div>
+    </div>
+  </div>
 </template>
 
-<style scoped lang="scss">
-.el-header, .el-footer {
-  background-color: var(--el-color-primary-light-7);
-  color: #333;
-  text-align: center;
-  line-height: 60px;
-}
+<script>
+import { ref, computed, onBeforeUnmount } from 'vue'
+import { ScreenApi } from '@/api/ecg/screen'
+import { RoomApi } from '@/api/ecg/room'
 
-.el-aside {
-  background-color: var(--el-color-primary-light-7);
-  color: #333;
-  text-align: center;
-  line-height: 200px;
-}
+import axios from 'axios'
 
-.el-main {
-  background-color: var(--el-color-primary-light-7);
-  color: #333;
-  padding: 0 0;
-  text-align: center;
-  line-height: 160px;
-}
+export default {
+  name: 'RoomScreen',
+  setup() {
+    // 鍝嶅簲寮忔暟鎹�
+    const roomProfile = ref({
+      roomName: '蹇冪數鍥捐瘖瀹� 01',
+      callingScreenType: 40
+    })
 
-.el-table ::v-deep .warning-row {
-  --el-table-tr-bg-color: var(--el-color-warning-light-9);
-}
-.el-table ::v-deep .success-row {
-  --el-table-tr-bg-color: var(--el-color-success-light-9);
-}
+    const checkRelatedPatientList = ref([])
+    const installRelatedPatientList = ref([])
+    const curSpeakPat = ref(null)
+    const announcementText = ref('绯荤粺杩愯涓�...')
+    const roomId = ref(1)
+    const timer = ref(null)
+    const speechSynthesis = ref(window.speechSynthesis || null)
+    const searchRoomInput = ref('')
 
-.layout-content {
+    // 璁$畻灞炴��
+    const screenTypeText = computed(() => {
+      const types = {
+        10: '浠呮鏌ラ槦鍒�',
+        20: '浠呮鏌ラ槦鍒�',
+        30: '浠呰鏈洪槦鍒�',
+        40: '鍙岄槦鍒楁ā寮�',
+        50: '鍙岄槦鍒楁ā寮�'
+      }
+      return types[roomProfile.value.callingScreenType] || '鏈煡妯″紡'
+    })
+
+    const showCheckPanel = computed(() => {
+      return [10, 20, 40, 50].includes(roomProfile.value.callingScreenType)
+    })
+
+    const showInstallPanel = computed(() => {
+      return [30, 40, 50].includes(roomProfile.value.callingScreenType)
+    })
+
+    // 鏂规硶
+    const searchRoom = () => {
+      if (!searchRoomInput.value.trim()) {
+        announcementText.value = '璇疯緭鍏ユ湁鏁堢殑鎴块棿鍙�'
+        return
+      }
+      RoomApi.getRoomByIP(roomId.value).then((response) => {
+        roomProfile.value = response
+        console.log(roomProfile.value.callingScreenType,'绫诲瀷');
+        
+      })
+
+      announcementText.value = `姝e湪鏌ヨ ${searchRoomInput.value} 鎴块棿淇℃伅...`
+
+      setTimeout(() => {
+        const roomNum = parseInt(searchRoomInput.value) || 0
+        // roomId.value = roomNum % 3
+        getRoomByIp()
+        announcementText.value = `宸插姞杞� ${roomProfile.value.roomName} 淇℃伅`
+      }, 500)
+    }
+
+    const getRoomByIp = () => {
+      setTimeout(() => {
+        ScreenApi.getRoomScreenData(searchRoomInput.value)
+          .then((response) => {
+            console.log(response, '991')
+            checkRelatedPatientList.value = response[1]
+          })
+          .catch((error) => {
+            console.error('鑾峰彇鎮h�呭け璐�:', error)
+          })
+        // axios
+        //   .get(`http://localhost:48080/admin-api/ecg/screen/room-screen-data`, {
+        //     params: {
+        //       roomId: searchRoomInput.value
+        //     }
+        //   })
+        //   .then((response) => {
+        //     const patient = response.data
+        //     console.log(response.data, '55')
+
+        //     if (patient && patient.called === 0) {
+        //       curSpeakPat.value = patient
+        //       speak(`璇�${patient.patName}鍒�${roomProfile.value.roomName}瑁呮満`)
+        //     }
+        //   })
+        //   .catch((error) => {
+        //     console.error('鑾峰彇涓嬩竴浣嶆偅鑰呭け璐�:', error)
+        //   })
+
+        const rooms = [
+          { roomName: '蹇冪數鍥捐瘖瀹� 01', callingScreenType: 40 },
+          { roomName: '鍔ㄦ�佸績鐢靛浘瀹�', callingScreenType: 10 },
+          { roomName: '杩愬姩璇曢獙瀹�', callingScreenType: 30 }
+        ]
+        roomProfile.value = rooms[roomId.value % 3]
+        announcementText.value = `宸插姞杞� ${roomProfile.value.roomName} 淇℃伅`
+      }, 300)
+    }
+
+    const getList = () => {
+      setTimeout(() => {
+        ScreenApi.getRoomScreenData(searchRoomInput.value)
+          .then((response) => {
+            console.log(response, '199')
+            checkRelatedPatientList.value = response[1]
+          })
+          .catch((error) => {
+            console.error('鑾峰彇鎮h�呭け璐�:', error)
+          })
+        // axios
+        //   .get(`http://localhost:48080/admin-api/ecg/screen/room-screen-data`, {
+        //     params: {
+        //       roomId: searchRoomInput.value
+        //     }
+        //   })
+        //   .then((response) => {
+        //     checkRelatedPatientList.value = response.data.data[1]
+        //     console.log(response.data.data[1], '66')
+        //   })
+        //   .catch((error) => {
+        //     console.error('鑾峰彇涓嬩竴浣嶆偅鑰呭け璐�:', error)
+        //   })
+
+        if (!curSpeakPat.value && Math.random() > 0.7) {
+          initiateSpeak()
+        }
+      }, 500)
+    }
+
+    const startScrolling = () => {
+      getList()
+      timer.value = setInterval(() => {
+        getList()
+      }, 5000)
+    }
+
+    const nameDesensitize = (patName) => {
+      if (!patName) return ''
+      if (patName.length === 2) {
+        return patName.substring(0, 1) + '*'
+      } else if (patName.length === 3) {
+        return patName.substring(0, 1) + '*' + patName.substring(2, 3)
+      } else if (patName.length > 3) {
+        return patName.substring(0, 1) + '*' + '*' + patName.substring(3, patName.length)
+      }
+      return patName
+    }
+
+    const getStatusClass = (status) => {
+      if (status === 10 || status === 40 || status === 33 || status === 20 || status === 10)
+        return 'waiting'
+      if (status === 30) return 'in-progress'
+      if (status === 7 || status === 3 || status === 5) return 'completed'
+      return ''
+    }
+
+    const queueStatusConvert = (status) => {
+      const statusMap = {
+        3: '宸茶繃鍙�-鎺掗槦',
+        5: '宸茶繃鍙�',
+        7: '宸茶繃鍙�-瀹夎',
+        10: '鎺掗槦涓�',
+        12: '浜插拰',
+        13: '浜插拰-瀹夎',
+        15: '宸插彫鍥�',
+        20: '鍊欒瘖涓�',
+        30: '灏辫瘖涓�',
+        33: '宸查鐢�',
+        34: '宸插彫鍥�-瀹夎',
+        36: '瀹夎涓�',
+        40: '宸插氨璇�'
+      }
+      return statusMap[status] || '鏈煡鐘舵��'
+    }
+
+    const getCheckTypeName = (type) => {
+      const types = {
+        1: '甯歌蹇冪數鍥�',
+        2: '鍔ㄦ�佸績鐢靛浘',
+        3: '杩愬姩璇曢獙',
+        4: '蹇冪數鐩戞姢'
+      }
+      return types[type] || '鏈煡妫�鏌�'
+    }
+
+    const getSeqPrefix = (patient) => {
+      const types = {
+        1: 'A001',
+        2: 'A002',
+        3: 'A003',
+        4: 'A004'
+      }
+      return types[patient.bookCheckType] || ''
+    }
+
+    const initiateSpeak = () => {
+      const waitingPatients = installRelatedPatientList.value.filter((p) => p.status === 5)
+      if (waitingPatients.length === 0) {
+        announcementText.value = '褰撳墠娌℃湁绛夊緟瑁呮満鐨勬偅鑰�'
+        return
+      }
+
+      const patient = waitingPatients[0]
+      curSpeakPat.value = {
+        patName: patient.patName,
+        roomName: roomProfile.value.roomName
+      }
+
+      speak('璇�' + patient.patName + '鍒�' + roomProfile.value.roomName + '瑁呮満')
+    }
+
+    const speak = (msg) => {
+      announcementText.value = '姝e湪鍛煎彨: ' + msg
+
+      if (!speechSynthesis.value) {
+        console.warn('褰撳墠娴忚鍣ㄤ笉鏀寔璇煶鍚堟垚')
+        return
+      }
+
+      speechSynthesis.value.cancel()
+
+      const speech = new SpeechSynthesisUtterance()
+      speech.text = msg + '銆傘�傘��' + msg + '銆傘�傘��' + msg
+      speech.pitch = 1
+      speech.rate = 0.9
+      speech.volume = 1
+      speech.lang = 'zh-CN'
+
+      speechSynthesis.value.speak(speech)
+    }
+
+    const onSpeachEndEvent = (event) => {
+      curSpeakPat.value = null
+      announcementText.value = '绯荤粺杩愯涓�...'
+    }
+
+    const changeRoom = () => {
+      roomId.value = (roomId.value + 1) % 3
+      getRoomByIp()
+      announcementText.value = '姝e湪鍒囨崲璇婇棿...'
+    }
+
+    // 鐢熷懡鍛ㄦ湡閽╁瓙
+    onBeforeUnmount(() => {
+      if (timer.value) {
+        clearInterval(timer.value)
+      }
+    })
+
+    // 鍒濆鍖�
+    getRoomByIp()
+    startScrolling()
+
+    // 鍒濆鍖栬闊冲悎鎴�
+    if (speechSynthesis.value) {
+      speechSynthesis.value.onend = onSpeachEndEvent
+    }
+
+    return {
+      roomProfile,
+      checkRelatedPatientList,
+      installRelatedPatientList,
+      curSpeakPat,
+      announcementText,
+      roomId,
+      timer,
+      speechSynthesis,
+      searchRoomInput,
+      screenTypeText,
+      showCheckPanel,
+      showInstallPanel,
+      searchRoom,
+      getRoomByIp,
+      getList,
+      startScrolling,
+      nameDesensitize,
+      getStatusClass,
+      queueStatusConvert,
+      getCheckTypeName,
+      getSeqPrefix,
+      initiateSpeak,
+      speak,
+      onSpeachEndEvent,
+      changeRoom
+    }
+  }
+}
+</script>
+
+<style scoped>
+.room-screen-container {
+  height: 100vh;
   display: flex;
-  height: 100%;
+  flex-direction: column;
+  background: linear-gradient(135deg, #e6f0f8, #d9e4f0);
+  color: #333;
+  line-height: 1.5;
+  overflow: hidden;
+  padding: 10px;
 }
 
-.left, .right {
+.search-bar {
+  background: rgba(255, 255, 255, 0.8);
+  border-radius: 16px;
+  padding: 12px 15px;
+  margin-bottom: 10px;
+  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+  display: flex;
+  align-items: center;
+}
+
+.search-input {
   flex: 1;
-  border: 1px solid #ccc;
-  padding: 10px;
+  border: none;
+  background: rgba(240, 244, 249, 0.7);
+  border-radius: 12px;
+  padding: 8px 12px;
+  font-size: 0.9rem;
+  outline: none;
+  color: #4a5568;
+}
+
+.search-btn {
+  margin-left: 8px;
+  background: #5b8cff;
+  color: white;
+  border: none;
+  border-radius: 12px;
+  padding: 8px 15px;
+  font-size: 0.9rem;
+  cursor: pointer;
+  transition: all 0.3s;
+}
+
+.search-btn:hover {
+  background: #3a7bff;
+}
+
+.header {
+  background: rgba(255, 255, 255, 0.8);
+  border-radius: 16px;
+  padding: 12px 15px;
+  margin-bottom: 10px;
+  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+}
+
+.clinic-title {
+  font-size: 1.4rem;
+  font-weight: bold;
+  text-align: center;
+  margin-bottom: 5px;
+  color: #4a7dff;
+  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
+}
+
+.clinic-info {
+  display: flex;
+  justify-content: space-between;
+  width: 100%;
+  font-size: 0.9rem;
+  color: #555;
+}
+
+.room-name {
+  background: rgba(91, 140, 255, 0.1);
+  padding: 4px 10px;
+  border-radius: 20px;
+  min-width: 120px;
+  text-align: center;
+  color: #4a7dff;
+}
+
+.screen-type {
+  background: rgba(91, 140, 255, 0.1);
+  padding: 4px 10px;
+  border-radius: 20px;
+  color: #4a7dff;
+}
+
+.main-content {
+  flex: 1;
+  display: flex;
+  flex-direction: column;
+  gap: 12px;
+  overflow: hidden;
+}
+
+.panel {
+  background: rgba(255, 255, 255, 0.95);
+  border-radius: 14px;
+  padding: 12px;
+  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
+  display: flex;
+  flex-direction: column;
+  overflow: hidden;
+  flex: 1;
+  border: 1px solid rgba(0, 0, 0, 0.05);
+}
+
+.panel-header {
+  background: linear-gradient(90deg, #a8c4ff, #c0d3ff);
+  color: #2c3e50;
+  padding: 8px 12px;
+  border-radius: 8px;
+  margin-bottom: 10px;
+  font-size: 1rem;
+  font-weight: bold;
+  text-align: center;
+}
+
+.patient-list {
+  flex: 1;
+  overflow-y: auto;
+  -webkit-overflow-scrolling: touch;
+}
+
+.patient-item {
+  display: flex;
+  align-items: center;
+  padding: 10px 8px;
+  border-bottom: 1px solid #eee;
+  transition: all 0.3s;
+}
+
+.patient-item:last-child {
+  border-bottom: none;
+}
+
+.patient-item.warning {
+  background-color: #fdf6ec;
+}
+
+.patient-item.in-progress {
+  background-color: #f0f9eb;
+}
+
+.patient-item.completed {
+  background-color: #f4f4f5;
+}
+
+.patient-info {
+  display: flex;
+  flex: 1;
   min-width: 0;
 }
 
+.patient-number {
+  width: 80px;
+  font-weight: bold;
+  color: #5b8cff;
+  font-size: 0.95rem;
+  overflow: hidden;
+  text-overflow: ellipsis;
+}
+
+.patient-name {
+  width: 100px;
+  font-size: 0.95rem;
+  overflow: hidden;
+  text-overflow: ellipsis;
+}
+
+.patient-check-type {
+  flex: 1;
+  font-size: 0.95rem;
+  overflow: hidden;
+  text-overflow: ellipsis;
+}
+
+.patient-status {
+  width: 70px;
+  font-size: 0.8rem;
+  font-weight: bold;
+  text-align: center;
+  padding: 3px 8px;
+  border-radius: 10px;
+}
+
+.status-waiting {
+  background-color: #fdf6ec;
+  color: #e6a23c;
+}
+
+.status-in-progress {
+  background-color: #f0f9eb;
+  color: #67c23a;
+}
+
+.status-completed {
+  background-color: #f4f4f5;
+  color: #909399;
+}
+
+.patient-bed {
+  width: 60px;
+  font-size: 0.85rem;
+  text-align: right;
+  color: #666;
+}
+
+.footer {
+  background: rgba(255, 255, 255, 0.8);
+  border-radius: 16px;
+  padding: 12px 15px;
+  margin-top: 10px;
+  box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.1);
+  border: 1px solid rgba(0, 0, 0, 0.05);
+}
+
+.announcement {
+  background: rgba(91, 140, 255, 0.1);
+  padding: 8px 15px;
+  border-radius: 20px;
+  font-size: 0.9rem;
+  text-align: center;
+  margin-bottom: 12px;
+  min-height: 20px;
+  color: #4a7dff;
+}
+
+.controls {
+  display: grid;
+  grid-template-columns: repeat(3, 1fr);
+  gap: 8px;
+}
+
+.control-btn {
+  padding: 8px 5px;
+  background: rgba(91, 140, 255, 0.1);
+  border: none;
+  border-radius: 12px;
+  color: #4a7dff;
+  font-size: 0.85rem;
+  cursor: pointer;
+  transition: all 0.3s;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+}
+
+.control-btn i {
+  font-size: 1.2rem;
+  margin-bottom: 3px;
+}
+
+.control-btn:hover {
+  background: rgba(91, 140, 255, 0.2);
+}
+
+.control-btn:active {
+  transform: scale(0.95);
+}
+
+.empty-state {
+  text-align: center;
+  color: #999;
+  padding: 20px;
+  font-size: 0.9rem;
+}
+
+/* 婊氬姩鏉℃牱寮� */
+.patient-list::-webkit-scrollbar {
+  width: 5px;
+}
+
+.patient-list::-webkit-scrollbar-track {
+  background: #f1f1f1;
+  border-radius: 4px;
+}
+
+.patient-list::-webkit-scrollbar-thumb {
+  background: #c0c4cc;
+  border-radius: 4px;
+}
+
+.patient-list::-webkit-scrollbar-thumb:hover {
+  background: #909399;
+}
+
+/* 鍔ㄧ敾鏁堟灉 */
+@keyframes pulse {
+  0% {
+    transform: scale(1);
+  }
+
+  50% {
+    transform: scale(1.05);
+  }
+
+  100% {
+    transform: scale(1);
+  }
+}
+
+.pulse {
+  animation: pulse 2s infinite;
+}
+
+/* 鍝嶅簲寮忚皟鏁� */
+@media (max-width: 480px) {
+  .header {
+    padding: 10px 12px;
+  }
+
+  .clinic-title {
+    font-size: 1.2rem;
+  }
+
+  .clinic-info {
+    font-size: 0.8rem;
+  }
+
+  .panel {
+    padding: 10px;
+  }
+
+  .panel-header {
+    font-size: 0.9rem;
+    padding: 6px 10px;
+  }
+
+  .patient-item {
+    padding: 8px 6px;
+  }
+
+  .patient-number,
+  .patient-name {
+    width: 60px;
+    font-size: 0.9rem;
+  }
+
+  .patient-status {
+    width: 60px;
+    font-size: 0.7rem;
+  }
+
+  .patient-bed {
+    width: 50px;
+  }
+}
+
+@media (max-height: 600px) {
+  .header {
+    padding: 8px 10px;
+  }
+
+  .panel {
+    padding: 8px;
+  }
+
+  .patient-item {
+    padding: 6px 4px;
+  }
+}
 </style>

--
Gitblit v1.9.3