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) + " "}} - </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