From 09dc74e264b6262cbe41c9c8476e24705871d4a6 Mon Sep 17 00:00:00 2001
From: yxh <172933527@qq.com>
Date: 星期日, 08 十一月 2026 23:31:17 +0800
Subject: [PATCH] yxh

---
 src/views/ecg/doctor/components/RoutinePanel.vue |  438 ++++++++++++++++++++++++++++++++++++++++++++++--------
 1 files changed, 373 insertions(+), 65 deletions(-)

diff --git a/src/views/ecg/doctor/components/RoutinePanel.vue b/src/views/ecg/doctor/components/RoutinePanel.vue
index de37be3..bdeb2b1 100644
--- a/src/views/ecg/doctor/components/RoutinePanel.vue
+++ b/src/views/ecg/doctor/components/RoutinePanel.vue
@@ -1,43 +1,84 @@
 <!-- 甯歌妫�鏌� 鍖荤敓鐣岄潰-->
 <template>
   <el-form class="patient-compact-form" ref="formRef" :model="formData" :rules="formRules" label-width="100px" v-loading="formLoading">
+    <!--
+      銆愭湰闇�姹傘�戠揣鎬ュ姞鍋氭搷浣滄彁绀猴紙缂栬緫鍖轰笂鏂癸紝甯搁┗锛�
+      绱ф�ョ梾浜轰笉鎺掗槦锛氬湪涓嬮潰涓変釜杈撳叆妗嗕换涓�涓噷杈撳叆鍚庢寜鍥炶溅锛屾煡鍒伴绾﹁褰曞嵆鍙洿鎺ュ仛妫�鏌ャ��
+    -->
+    <el-alert type="warning" :closable="false" class="emergency-tip">
+      <template #title>
+        <span class="emergency-tip__text">
+          鏈夌揣鎬ョ梾浜烘椂锛岃杈撳叆<span class="emergency-tip__key">鐢宠鍗曞彿</span>銆佹垨<span class="emergency-tip__key">灏辫瘖鍙�</span>銆佹垨<span class="emergency-tip__key">鎮h�呯紪鍙�</span>鍚庢寜<span class="emergency-tip__enter">鍥炶溅閿�</span>锛屾煡鍒扮梾浜洪绾﹁褰曞嵆鍙仛妫�鏌ワ紒锛侊紒
+        </span>
+      </template>
+    </el-alert>
     <!-- ===== 缂栬緫鍖猴紙闇�瑕佸綍鍏ョ殑瀛楁锛�===== -->
-    <el-row :gutter="20">
-      <el-col :span="6">
-        <el-form-item label="鐢宠鍗曞彿" prop="applyNo">
-          <el-input v-model="formData.applyNo" placeholder="璇疯緭鍏ョ敵璇峰崟鍙�" />
-        </el-form-item>
-      </el-col>
-       <el-col :span="6">
-        <el-form-item label="妫�鏌ラ」鐩�" prop="">
-          {{ formData?.checkType && getCheckTypeName(formData?.checkType) }}
-        </el-form-item>
-      </el-col>      
-        <el-col :span="6">
-        <el-form-item label="鎮h�呯紪鍙�" prop="patId">
-          <el-input v-model="formData.patId" placeholder="璇疯緭鍏ユ偅鑰呯紪鍙�" @input="getRentInfoByPatId" />
-          <Barcode v-if="displayBarCode" :value="displayBarCode" :width="100" />
-          <el-button @click="copyBarcode()">澶嶅埗</el-button>
-        </el-form-item>
-      </el-col>
-      <el-col :span="6">
-        <el-form-item label="鎮h�呭鍚�" prop="patName">
-          <el-input v-model="formData.patName" placeholder="璇疯緭鍏ユ偅鑰呭鍚�" />
-        </el-form-item>
-      </el-col>        
-    </el-row>
+      <el-row :gutter="4">
+        <el-col :xs="24" :sm="12" :md="12" :lg="6">
+          <el-form-item label="鐢宠鍗曞彿" prop="applyNo">
+            <!-- 銆愭湰闇�姹傦細绱ф�ュ姞鍋氥�戝洖杞﹀嵆鎸夌敵璇峰崟鍙锋煡杩戜竴涓湀鐨勯绾� -->
+            <el-input
+              v-model="formData.applyNo"
+              placeholder="璇疯緭鍏ョ敵璇峰崟鍙�"
+              @keyup.enter="searchEmergencyCandidates('applyNo')"
+            />
+          </el-form-item>
+        </el-col>
+        <el-col :xs="24" :sm="12" :md="12" :lg="6">
+          <el-form-item label="妫�鏌ラ」鐩�" prop="">
+            {{ formData?.checkType && getCheckTypeName(formData?.checkType) }}
+          </el-form-item>
+        </el-col>
+        <el-col :xs="24" :sm="12" :md="12" :lg="6">
+          <el-form-item label="灏辫瘖鍙�" prop="episodeId">
+            <!-- 銆愭湰闇�姹傦細绱ф�ュ姞鍋氥�戝洖杞﹀嵆鎸夊氨璇婂彿鏌ヨ繎涓�涓湀鐨勯绾� -->
+            <el-input
+              v-model="formData.episodeId"
+              placeholder="璇疯緭鍏ュ氨璇婃祦姘村彿"
+              @keyup.enter="searchEmergencyCandidates('episodeId')"
+            />
+            <!--
+              銆愭湰闇�姹傘�戞潯鐮佷粠銆屾偅鑰呯紪鍙枫�嶆尓鍒拌繖閲岋紙灏辫瘖鍙蜂笅鏂癸級锛�
+                路 鍐呭 = 灏辫瘖鍙凤紱榛樿鏄惁鏄剧ず鐢便�屾鏌ョ被鍨� 鈫� 鏄惁鏄剧ず鏉$爜銆嶉厤缃喅瀹氾紱
+                路 鍖荤敓鍙敤鍒囨崲鎸夐挳鎵嬪姩鏄鹃殣锛堟樉绀轰腑鈫掋�岄殣钘忋�嶏紱闅愯棌涓啋銆屾潯鐮併�嶏級锛�
+                路 銆屽鍒躲�嶅彧鍦ㄦ潯鐮佹樉绀烘椂鍑虹幇銆�
+            -->
+            <div v-if="showBarcodeToggle || showBarCode" class="barcode-row">
+              <Barcode v-if="showBarCode" :value="barcodeContent" :width="100" />
+              <el-button v-if="showBarcodeToggle" size="small" @click="toggleBarcode()">
+                {{ barcodeToggleLabel }}
+              </el-button>
+              <el-button v-if="showCopyButton" size="small" :disabled="!barcodeContent" @click="copyBarcode()">
+                澶嶅埗
+              </el-button>
+            </div>
+          </el-form-item>
+        </el-col>
+        <!-- 銆愭湰闇�姹傘�戞偅鑰呭鍚嶈繖涓�鍒楀凡鍘绘帀锛氫笅鏂� PatientInfoBlock 宸叉湁濮撳悕灞曠ず -->
+        <el-col :xs="24" :sm="12" :md="12" :lg="6">
+          <el-form-item label="鎮h�呯紪鍙�" prop="patId">
+            <!-- 銆愭湰闇�姹傦細绱ф�ュ姞鍋氥�戝洖杞﹀嵆鎸夋偅鑰呯紪鍙锋煡杩戜竴涓湀鐨勯绾� -->
+            <el-input
+              v-model="formData.patId"
+              placeholder="璇疯緭鍏ユ偅鑰呯紪鍙�"
+              @input="getRentInfoByPatId"
+              @keyup.enter="searchEmergencyCandidates('patId')"
+            />
+          </el-form-item>
+        </el-col>
+      </el-row>
 
     <!-- ===== 鎮h�呬俊鎭紙闇�姹�1锛�18 椤圭粺涓�灞曠ず锛�**涓�琛屽洓鍒�**锛�=====
          鍘熷厛鏈潰鏉挎妸 18 椤规墜鍐欏湪澶氳 el-col锛坰pan=6/18 娣锋帓锛夛紝
          鐜扮粺涓�鏀圭敤 PatientInfoBlock 缁勪欢锛屼笌棰勭害绛惧埌/璁惧棰嗙敤/瑁呮満/鎷嗘満鍚勯〉**鍙e緞涓�鑷�**銆� -->
     <PatientInfoBlock :data="formData" check-type-field="checkType" :span="6" />
     <el-row>     
-      <el-col :span="6">
+      <el-col :xs="24" :sm="12" :md="12" :lg="6">
         <el-form-item label="妫�鏌ユ椂闂�" prop="rentTime">
           <el-date-picker v-model="formData.rentTime" type="date" value-format="x" placeholder="閫夋嫨鏃堕棿" />
         </el-form-item>
       </el-col> 
-      <el-col :span="18">
+      <el-col :xs="24" :sm="24" :md="12" :lg="18">
         <el-form-item label="澶囨敞" prop="remark">
           <el-input v-model="formData.remark" placeholder="璇疯緭鍏ュ娉�" />
         </el-form-item>
@@ -50,8 +91,8 @@
   <el-button size="small" @click="resetForm()">閲� 缃�</el-button>
   <el-button size="small" @click="yddownload()" :loading="yddownloadLoading" :disabled="yddownloadLoading">骞虫澘杩愬姩蹇冪數鍥剧煡鎯呭悓鎰忎功</el-button>
   <el-button size="small" @click="sgdownload()" :loading="sgdownloadLoading" :disabled="sgdownloadLoading">椋熺蹇冭剰鐢电敓鐞嗚瘖鐤楃煡鎯呭悓鎰忎功</el-button>
-  <el-button size="small" v-if="needAutoFeeConfirm(formData.checkType)" @click="feeConfirm" :disabled="formLoading">纭垂</el-button>
-  <el-button size="small" v-if="needAutoFeeConfirm(formData.checkType)" @click="feeCancel" :disabled="formLoading">鍙栨秷纭垂</el-button>
+  <el-button size="small" v-if="needAutoFeeConfirm(formData.checkType)" @click="feeConfirm" :disabled="formLoading || formData.id == null">纭垂</el-button>
+  <el-button size="small" v-if="needAutoFeeConfirm(formData.checkType)" @click="feeCancel" :disabled="formLoading || formData.id == null">鍙栨秷纭垂</el-button>
   </div>
 
   <!-- 鍖荤敓瑁呮満鍒楄〃 -->
@@ -145,13 +186,84 @@
       @pagination="getList"
     />
   </div>
+
+  <!--
+    銆愭湰闇�姹傦細绱ф�ユ偅鑰呬笉鎺掗槦鐩存帴妫�鏌ャ�戦绾﹂�夋嫨妗�
+    瑙﹀彂锛氬湪銆岀敵璇峰崟鍙� / 灏辫瘖鍙� / 鎮h�呯紪鍙枫�嶄换涓�杈撳叆妗嗗唴鎸夊洖杞︺��
+    澶氭潯棰勭害鏃跺脊姝ゆ锛屾寜棰勭害鏃堕棿鍊掑簭锛堟渶杩戠殑鍦ㄥ墠锛夈��
+  -->
+  <Dialog v-model="emergencyVisible" title="閫夋嫨棰勭害璁板綍锛堢揣鎬ュ姞鍋氾級" width="880px" append-to-body>
+    <el-alert type="warning" :closable="false" class="mb-10px">
+      <template #title>
+        <span class="text-13px">
+          鎵惧埌 {{ emergencyList.length }} 鏉¢绾﹁褰曪細**鐐归�変竴琛�**锛堟暣琛岄珮浜� + 宸︿晶钃濇潯 + 銆屽凡閫夈�嶆爣绛撅級鍚庣偣銆岄�夋嫨骞舵鏌ャ�嶏紝
+          涔熷彲鐩存帴**鍙屽嚮**璇ヨ銆傞�変腑鍚庡彲鐩存帴妫�鏌ワ紝瀹屾垚鍚庡悓鏍疯繘鍏ャ�屽凡瀹屾垚鍒楄〃銆嶏紙涓嶆帓闃熴�佷笉鍗犲彿锛夈��
+        </span>
+      </template>
+    </el-alert>
+    <el-table
+      ref="emergencyTableRef"
+      class="emergency-table"
+      :data="emergencyList"
+      v-loading="emergencyLoading"
+      highlight-current-row
+      border
+      max-height="360px"
+      :row-class-name="emergencyRowClass"
+      @row-click="(row) => (emergencySelected = row)"
+      @current-change="(row) => (emergencySelected = row)"
+      @row-dblclick="(row) => confirmEmergency(row)"
+    >
+      <!-- 銆愭湰闇�姹傘�戦�変腑鏍囪瘑鍒楋細閫変腑琛屾樉绀恒�屸湏 宸查�夈�嶏紝閬垮厤鍙潬鑳屾櫙鑹插垎杈ㄤ笉娓� -->
+      <el-table-column label="閫夋嫨" width="80" align="center" fixed="left">
+        <template #default="scope">
+          <el-tag v-if="isEmergencySelected(scope.row)" type="primary" effect="dark" size="small">
+            鉁� 宸查��
+          </el-tag>
+          <span v-else class="text-gray-400">鈥�</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="棰勭害鏃ユ湡" align="center" prop="bookDate" width="120">
+        <template #default="scope">{{ formatDate(scope.row.bookDate, 'YYYY-MM-DD') }}</template>
+      </el-table-column>
+      <el-table-column label="鏃舵" align="center" width="120">
+        <template #default="scope">{{ formatTimeslot(scope.row.bookTimeslot) }}</template>
+      </el-table-column>
+      <el-table-column label="妫�鏌ラ」鐩�" align="center" min-width="130">
+        <template #default="scope">{{ getCheckTypeName(scope.row.bookCheckType) }}</template>
+      </el-table-column>
+      <el-table-column label="鎮h�呭悕绉�" align="center" prop="patName" min-width="100" />
+      <el-table-column label="鎮h�呯紪鍙�" align="center" prop="patId" min-width="110" />
+      <el-table-column label="鐢宠鍗曞彿" align="center" prop="applyNo" min-width="130" />
+      <el-table-column label="鐘舵��" align="center" width="90">
+        <template #default="scope">
+          <dict-tag :type="DICT_TYPE.ECG_STATUS" :value="scope.row.status" />
+        </template>
+      </el-table-column>
+    </el-table>
+    <template #footer>
+      <!-- 搴曢儴鍥炴樉宸查�夊摢涓�鏉★紝閬垮厤閫夐敊 -->
+      <span v-if="emergencySelected" class="emergency-selected-hint">
+        宸查�夛細{{ formatDate(emergencySelected.bookDate, 'YYYY-MM-DD') }}
+        {{ formatTimeslot(emergencySelected.bookTimeslot) }}
+        {{ getCheckTypeName(emergencySelected.bookCheckType) }}
+        <span class="text-gray-500">锛坽{ emergencySelected.patName }}锛�</span>
+      </span>
+      <el-button @click="emergencyVisible = false">鍙� 娑�</el-button>
+      <el-button type="primary" :disabled="!emergencySelected" @click="confirmEmergency()">
+        閫夋嫨骞舵鏌�
+      </el-button>
+    </template>
+  </Dialog>
 </template>
 
 <script setup lang="ts">
 import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
 
 import { DevRentApi, DevRentVO } from '@/api/ecg/devrent'
-import { dateFormatter } from '@/utils/formatTime'
+import { dateFormatter, formatDate } from '@/utils/formatTime'
+import { formatTimeslot } from '@/utils/formatter'
+import { AppointmentApi, AppointmentVO } from '@/api/ecg/appointment'
 import { JobRecordApi, JobRecordVO } from '@/api/ecg/jobrecord'
 import { isStringEmpty } from '@/utils/stringUtil'
 import { calculateAge, curDayEnd, curDayStart, formatTimestamp } from '@/utils/dateUtil'
@@ -239,7 +351,6 @@
     formData.value.doctorAdviceNo = queueVO?.doctorAdviceNo
   formData.value.patIdentityId = queueVO?.patIdentityId
   getFreeRentInfo(formData.value)
-  copyBarcode()
 }
 defineExpose({ setPatient, getList: () => getList() }) // 鎻愪緵 setPatient 鏂规硶锛岀敤浜庤缃偅鑰�
 
@@ -304,7 +415,106 @@
 })
 const formRef = ref() // 琛ㄥ崟 Ref
 
-const displayBarCode = ref<string>()
+
+// =====================================================================================
+// 銆愭湰闇�姹傦細绱ф�ユ偅鑰呬笉鎺掗槦鐩存帴妫�鏌ャ��
+//   鍦ㄣ�岀敵璇峰崟鍙� / 灏辫瘖鍙� / 鎮h�呯紪鍙枫�嶄换涓�杈撳叆妗嗗洖杞� 鈫� 鏌ヨ繎涓�涓湀銆佹湰绐楀彛妫�鏌ラ」鐩殑棰勭害璁板綍
+//   鈫� 1 鏉$洿鎺ヨ鍏ワ紱澶氭潯寮归�夋嫨妗嗭紙鎸夐绾︽椂闂村�掑簭锛夆啋 璇诲叆鍚庡彲鐩存帴銆屾鏌ュ畬鎴愩��
+//   鈫� 鍚庣鍦�"浠婂ぉ娌℃湁寰呮鏌ュ崟"鏃舵寜棰勭害鍗曡ˉ寤猴紝浠庤�屽儚鎺掗槦鎮h�呬竴鏍疯繘鍏ャ�屽凡瀹屾垚鍒楄〃銆�
+// =====================================================================================
+const emergencyMode = ref(false) // 褰撳墠琛ㄥ崟鏄惁鏉ヨ嚜"绱ф�ュ姞鍋�"
+const emergencyVisible = ref(false) // 閫夋嫨妗�
+const emergencyLoading = ref(false)
+const emergencyList = ref<AppointmentVO[]>([])
+const emergencySelected = ref<AppointmentVO | undefined>()
+/** 閫夋嫨琛ㄦ牸寮曠敤锛堜繚鐣欙細鍚庣画濡傞渶 scrollToRow 绛夎兘鍔涘彲鐢級 */
+const emergencyTableRef = ref<any>()
+
+/** 閫変腑鍒ゆ柇锛堟ā鏉块噷鐢紝閬垮厤鐩存帴姣旇緝瀵硅薄寮曠敤锛� */
+const isEmergencySelected = (row: AppointmentVO) =>
+  null != emergencySelected.value && emergencySelected.value.id === row?.id
+
+/** 閫変腑琛屽姞 is-selected 绫伙紝閰嶅悎涓嬫柟鏍峰紡鍋氥�屾暣琛岄珮浜� + 宸︿晶钃濇潯 + 鍔犵矖銆� */
+const emergencyRowClass = ({ row }: { row: AppointmentVO }) =>
+  isEmergencySelected(row) ? 'is-selected' : ''
+
+/** 鏈獥鍙o紙璇婂锛夊紑灞曠殑妫�鏌ラ」鐩紝鐢ㄤ簬杩囨护鍊欓�夐绾︼紱涓虹┖琛ㄧず涓嶉檺鍒� */
+const currentWindowCheckTypes = (): number[] | undefined => {
+  const fromProp = props.room?.checkTypes
+  const types =
+    Array.isArray(fromProp) && fromProp.length > 0 ? fromProp : (roomStore.room?.checkTypes as number[] | undefined)
+  return Array.isArray(types) && types.length > 0 ? [...types] : undefined
+}
+
+/** 鍥炶溅锛氭寜杈撳叆妗嗛噷鐨勫�兼煡棰勭害鍊欓�� */
+const searchEmergencyCandidates = async (field: 'applyNo' | 'episodeId' | 'patId') => {
+  const code = String((formData.value as Record<string, any>)[field] ?? '').trim()
+  if (!code) return
+  emergencyLoading.value = true
+  try {
+    const list = (await AppointmentApi.getEmergencyCandidates(code, currentWindowCheckTypes())) as AppointmentVO[]
+    const rows = Array.isArray(list) ? list : []
+    if (rows.length === 0) {
+      message.warning('杩戜竴涓湀鍐呮病鏈夋壘鍒版湰绐楀彛妫�鏌ラ」鐩殑棰勭害璁板綍')
+      return
+    }
+    if (rows.length === 1) {
+      applyAppointment(rows[0])
+      message.success('宸茶鍏ラ绾﹁褰曪紝鍙洿鎺ョ偣銆屾鏌ュ畬鎴愩��')
+      return
+    }
+    emergencyList.value = rows
+    emergencySelected.value = undefined
+    emergencyVisible.value = true
+  } finally {
+    emergencyLoading.value = false
+  }
+}
+
+/** 閫夋嫨妗嗙‘璁わ紙涔熸敮鎸佸弻鍑昏鐩存帴纭锛� */
+const confirmEmergency = (row?: AppointmentVO) => {
+  const target = row ?? emergencySelected.value
+  if (!target) return
+  applyAppointment(target)
+  emergencyVisible.value = false
+}
+
+/**
+ * 鎶婇绾﹀崟璇诲叆琛ㄥ崟銆�
+ * 娉ㄦ剰锛氳繖閲屾槸"绱ф�ュ姞鍋�"锛�**涓嶆帓闃�**鈥斺�斾笉寤� queue 琛屻�佷笉鍙栧彿锛�
+ * 銆屾鏌ュ畬鎴愩�嶆椂鐢卞悗绔寜闇�琛ュ缓銆屽緟妫�鏌ャ�嶆鏌ュ崟锛堣 DevRentServiceImpl#prepareEmergencyDevRent锛夈��
+ */
+const applyAppointment = (appt: AppointmentVO) => {
+  resetForm()
+  emergencyMode.value = true
+  formData.value.applyNo = appt.applyNo
+  formData.value.episodeId = appt.episodeId
+  formData.value.patId = appt.patId
+  formData.value.patName = appt.patName
+  formData.value.checkType = appt.bookCheckType
+  formData.value.patGender = appt.patGender
+  formData.value.patBirthday = appt.patBirthday
+  formData.value.patSrc = appt.patSrc
+  formData.value.tolerance = appt.tolerance
+  formData.value.doctor = appt.doctor
+  formData.value.doctorTime = appt.doctorTime
+  formData.value.registerDate = appt.registerDate
+  formData.value.paid = appt.paid
+  formData.value.doctorAdviceNo = appt.doctorAdviceNo
+  formData.value.patMobile = appt.patMobile
+  formData.value.patPhone = appt.patPhone
+  formData.value.patIdentityId = appt.patIdentityId
+  formData.value.outpatientNo = appt.outpatientNo
+  formData.value.patWardDesc = appt.patWardDesc
+  formData.value.patBedNo = appt.patBedNo
+  formData.value.medicalCard = appt.medicalCard
+  // 鏉$爜/鎵撳嵃灏忕エ渚濊禆 patDetails.source
+  formData.value.patDetails = {
+    source: appt.patSrc,
+    appointmentId: appt.id
+  } as unknown as typeof formData.value.patDetails
+  message.success('宸茶鍏ラ绾﹁褰曪紝鍙洿鎺ョ偣銆屾鏌ュ畬鎴愩��')
+}
 
 /** 鎻愪氦琛ㄥ崟 */
 const submitForm = async () => {
@@ -315,12 +525,16 @@
   try {
     formData.value.roomId = props.room.roomId
     formData.value.bedNo = props.room.bedNo
-    const data = formData.value as unknown as DevRentVO
-    await DevRentApi.routineFinish(data)
+    // 銆愭湰闇�姹傦細绱ф�ユ偅鑰呬笉鎺掗槦鐩存帴妫�鏌ャ�戝甫涓�"绱ф�ュ姞鍋�"鏍囪锛�
+    //   鍚庣鎹鍦ㄣ�屼粖澶╂病鏈夊緟妫�鏌ュ崟銆嶆椂鎸夐绾﹀崟琛ュ缓涓�琛岋紝浠庤�岃兘姝e父瀹屾垚骞跺啓鍏ャ�屽凡瀹屾垚鍒楄〃銆�
+    const data = formData.value as unknown as DevRentVO & { emergency?: boolean }
+    data.emergency = emergencyMode.value
+    // 鍚庣 routine-finish 宸茶繑鍥炴湰娆″畬鎴愮殑妫�鏌ュ崟 id锛堢揣鎬ュ姞鍋氭椂鏄湇鍔$鏂板缓鐨勯偅鏉★級
+    const rentId = (await DevRentApi.routineFinish(data)) as unknown as number | string | undefined
 
-    // 鑷姩纭垂
+    // 鑷姩纭垂锛氱敤杩斿洖鐨� rentId锛涙棤 id 鏃堕潤榛樿烦杩囷紙涓嶅啀寮广�岃鍏堟鏌ャ�嶏級
     if (needAutoFeeConfirm(formData.value.checkType)) {
-      feeConfirm()
+      feeConfirm(rentId)
     }
 
     message.success(t('鎿嶄綔鎴愬姛'))
@@ -360,6 +574,9 @@
     roomId: props.room.roomId,
     bedNo: props.room.bedNo
   }
+  // 銆愭湰闇�姹傘�戞崲鎮h��/閲嶇疆鏃讹細鏉$爜鏄鹃殣鍥炲埌"璺熼殢閰嶇疆榛樿"锛岀揣鎬ュ姞鍋氭爣璁版竻绌�
+  barcodeVisible.value = null
+  emergencyMode.value = false
   formRef.value?.resetFields()
 }
 const yddownload = async () => {
@@ -439,7 +656,6 @@
 
   formData.value.patId = tempPatId
   getFreeRentInfo(formData.value)
-  copyBarcode()
 }
 
 const getFreeRentInfo = async (devRentVO) => {
@@ -570,14 +786,21 @@
   message.success(t('鎿嶄綔鎴愬姛'))
 }
 
-const feeConfirm = async () => {
-  if (formData.value.id == null) {
-    message.error(t('璇峰厛妫�鏌�'))
+/**
+ * 纭垂銆�
+ * @param rentId 鏈妫�鏌ュ畬鎴愯繑鍥炵殑妫�鏌ュ崟 id锛涗笉浼犲垯鐢ㄨ〃鍗曢噷鐨� id銆�
+ * 銆愭湰娆′慨澶嶃�戝師瀹炵幇鍦� id 涓虹┖鏃跺脊銆岃鍏堟鏌ャ�嶁�斺�� 绱ф�ュ姞鍋氭偅鑰呮病鏈� id锛岀偣銆屾鏌ュ畬鎴愩�嶄細鍏堝脊杩欎釜閿欙紝
+ * 鍐嶅脊銆屾搷浣滄垚鍔熴�嶏紝璁╀汉璇互涓烘搷浣滃け璐ャ�傜幇鍦ㄦ敼涓洪潤榛樿烦杩囷紙鎸夐挳鏈韩涔熶細鍦ㄦ棤 id 鏃剁鐢級銆�
+ */
+const feeConfirm = async (rentId?: number | string | null) => {
+  const id = rentId ?? formData.value.id
+  if (id == null || id === '') {
+    console.warn('[feeConfirm] 鏃犳鏌ュ崟 id锛岃烦杩囩‘璐�')
     return
   }
 
   try {
-    const result = await DevRentApi.feeConfirm(formData.value.id)
+    const result = await DevRentApi.feeConfirm(id as number)
     if (0 == result) {
       //message.success(t('纭垂鎿嶄綔鎴愬姛'))
     }
@@ -587,8 +810,9 @@
 }
 
 const feeCancel = async () => {
-  if (formData.value.id == null) {
-    message.error(t('璇峰厛妫�鏌�'))
+  // 銆愭湰娆′慨澶嶃�戞棤妫�鏌ュ崟 id 鏃堕潤榛樿烦杩囷紙鎸夐挳宸茬鐢級锛屼笉鍐嶅脊銆岃鍏堟鏌ャ��
+  if (formData.value.id == null || formData.value.id === '') {
+    console.warn('[feeCancel] 鏃犳鏌ュ崟 id锛岃烦杩囧彇娑堢‘璐�')
     return
   }
 
@@ -601,40 +825,57 @@
     // 妗嗘灦 浼氱粰鍑� 鍚庡彴鐨� 閿欒淇℃伅
   }
 }
+/**
+ * 銆愭湰闇�姹傘�戞偅鑰呮潯鐮侊細浣嶇疆鍦ㄣ�屽氨璇婂彿銆嶄笅鏂癸紝鍐呭 = 灏辫瘖鍙凤紙episodeId锛夛紝鍙樉闅�
+ *
+ *  路 榛樿鍙鎬� = 銆屾鏌ョ被鍨� 鈫� 鏄惁鏄剧ず鏉$爜銆嶉厤缃噷**鍖呭惈璇ユ偅鑰呮潵婧�**
+ *      - 宸插嬀閫夎鏉ユ簮 鈫� 榛樿鏄剧ず
+ *      - 鏈厤缃� / 閰嶇疆閲屾病鏈夎鏉ユ簮 鈫� 榛樿涓嶆樉绀猴紙渚嬪浣忛櫌(3)閫氬父涓嶄細鍕鹃�夛級
+ *  路 鍖荤敓鍙敤鎸夐挳鎵嬪姩瑕嗙洊榛樿锛氭樉绀轰腑 鈫� 銆岄殣钘忋�嶏紱闅愯棌涓� 鈫� 銆屾潯鐮併��
+ *  路 銆屽鍒躲�嶆寜閽彧鍦ㄦ潯鐮佹樉绀烘椂鍑虹幇
+ */
+const barcodeVisible = ref<boolean | null>(null) // null = 鏈墜鍔ㄦ搷浣滐紝璺熼殢閰嶇疆榛樿
 
-const getDisplayBarcode = (): string => {
-  if (formData.value.checkType == null) return ''
+const patSourceValue = computed<number | null>(() => {
+  const source = formData.value.patDetails?.source ?? formData.value.patSrc
+  return source === null || source === undefined || source === '' ? null : Number(source)
+})
 
-  // 銆愭湰娆′慨澶嶃�戙�屾偅鑰呮潯鐮佹樉绀恒�嶆湭閰嶇疆锛坣ull/绌猴級鈫� 涓嶆樉绀猴紙鎸夌幇鍦虹‘璁ゅ彛寰勶級
-  const displayBarcode: number[] | undefined = checkTypeStore.getCheckTypeDispBarCode(formData.value.checkType!)
-  if (displayBarcode == null || displayBarcode.length === 0) return ''
+/** 閰嶇疆鍙e緞锛氳妫�鏌ョ被鍨嬬殑銆屾樉绀烘潯鐮併�嶆槸鍚﹀寘鍚綋鍓嶆偅鑰呮潵婧� */
+const barcodeEnabled = computed<boolean>(() => {
+  if (formData.value.checkType == null) return false
+  const displayBarcode: number[] | undefined = checkTypeStore.getCheckTypeDispBarCode(formData.value.checkType)
+  if (displayBarcode == null || displayBarcode.length === 0) return false
+  const patSource = patSourceValue.value
+  if (patSource == null) return false
+  return displayBarcode.map(Number).includes(patSource)
+})
 
-  // 銆愭湰娆′慨澶嶃�戞潵婧愪紭鍏堝彇 patDetails.source锛岀己澶辨椂鍥為��鍒板钩閾虹殑 patSrc銆�
-  // 鍘熸潵鍙 patDetails.source锛岃�� patDetails 鍘熷厛鍙湪"鑳芥煡鍒板緟妫�鏌ュ崟"鏃舵墠琚祴鍊硷紝
-  // 澶у鏁版儏鍐典笅鏄� undefined 鈫� 鏉$爜姘歌繙涓嶆樉绀恒��
-  const patSource = formData.value.patDetails?.source ?? formData.value.patSrc
-  if (patSource == null) return ''
-  if (!displayBarcode.map(Number).includes(Number(patSource))) return ''
+/** 鏉$爜 / 澶嶅埗鐨勫唴瀹癸細缁熶竴鍙栥�屽氨璇婂彿銆� */
+const barcodeContent = computed<string>(() => formData.value.episodeId ?? '')
 
-  return getBarcode()
-}
+/** 瀹為檯鏄惁鏄剧ず锛氭墜鍔ㄨ鐩栦紭鍏堬紝鍚﹀垯璺熼厤缃粯璁� */
+const barcodeVisibleEffective = computed<boolean>(() => barcodeVisible.value ?? barcodeEnabled.value)
 
-const getBarcode = (): string => {
-  if (formData.value.checkType == null) return ''
+/** 鏉$爜锛氬彲瑙佷笖鍐呭闈炵┖鎵嶆覆鏌� */
+const showBarCode = computed<boolean>(() => barcodeVisibleEffective.value && barcodeContent.value !== '')
 
-  const patSource = formData.value.patDetails?.source ?? formData.value.patSrc
-  if (patSource == null) return ''
+/** 銆屽鍒躲�嶆寜閽細鍙湪鏉$爜鏄剧ず鏃跺嚭鐜� */
+const showCopyButton = computed<boolean>(() => showBarCode.value)
 
-  // 闂ㄨ瘖/鎬ヨ瘖 鈫� 鐢宠鍗曞彿锛涗綇闄�/浣撴 鈫� 灏辫瘖娴佹按鍙�
-  if (1 === Number(patSource) || 2 === Number(patSource)) return formData.value.applyNo ?? ''
-  else if (3 === Number(patSource) || 4 === Number(patSource)) return formData.value.episodeId ?? ''
+/** 鍒囨崲鎸夐挳锛氬彧瑕佹湁灏辫瘖鍙峰氨缁欙紙涓嶅彈閰嶇疆闄愬埗锛岄厤缃彧绠�"榛樿鏄惁鏄剧ず"锛� */
+const showBarcodeToggle = computed<boolean>(() => barcodeContent.value !== '')
 
-  return ''
+/** 鍒囨崲鎸夐挳鏂囨锛氭樉绀轰腑 鈫� 闅愯棌锛涢殣钘忎腑 鈫� 鏉$爜 */
+const barcodeToggleLabel = computed<string>(() => (showBarCode.value ? '闅愯棌' : '鏉$爜'))
+
+const toggleBarcode = () => {
+  barcodeVisible.value = !barcodeVisibleEffective.value
 }
 
 const copyBarcode = async () => {
-  displayBarCode.value = getDisplayBarcode()
-  await navigator.clipboard.writeText(getBarcode())
+  if (!barcodeContent.value) return
+  await navigator.clipboard.writeText(barcodeContent.value)
 }
 
 /** 鍒濆鍖� **/
@@ -647,6 +888,73 @@
 <style scoped lang="scss">
 
 /* 銆愭湰娆¢渶姹傘�戙�屽凡瀹屾垚鍒楄〃銆嶆爣棰樻爮锛氬乏渚т富鑹茬珫绾� + 鍔犵矖灏忔爣棰橈紝绱у噾楂樺害涓嶆尋鍘嬭〃鏍� */
+/* 銆愭湰闇�姹傘�戠紪杈戝尯涓婃柟鐨勩�岀揣鎬ュ姞鍋氥�嶆搷浣滄彁绀猴細涓�琛屾樉绀恒�侀啋鐩絾涓嶅崰楂樺害 */
+.emergency-tip {
+  padding: 4px 10px;
+  margin-bottom: 6px;
+
+  :deep(.el-alert__title) {
+    padding: 0;
+    font-size: 13px;
+    line-height: 20px;
+  }
+
+  &__text {
+    color: var(--el-color-warning-dark-2);
+  }
+
+  /* 鍏抽敭瀛楁/鎸夐敭鍋氬己璋冿紝鏂逛究涓�鐪肩湅鎳傝杈撲粈涔堛�佹寜浠�涔� */
+  &__key {
+    font-weight: 600;
+    color: var(--el-color-danger);
+  }
+
+  &__enter {
+    padding: 0 4px;
+    margin: 0 2px;
+    border: 1px solid var(--el-color-danger);
+    border-radius: 3px;
+    font-weight: 600;
+    color: var(--el-color-danger);
+    background-color: var(--el-color-danger-light-9);
+  }
+}
+/* 銆愭湰闇�姹傘�戠揣鎬ュ姞鍋氾細棰勭害閫夋嫨妗嗙殑銆岄�変腑琛屻�嶈瓒冲鏄庢樉
+   锛堝師鏉ュ彧鏈夐粯璁ょ殑娴呰壊 current-row 鑳屾櫙锛岀幇鍦哄弽棣�"鍙槸鍙樻繁涓�鐐癸紝鐪嬩笉娓�"锛� */
+.emergency-table {
+  :deep(.el-table__row) {
+    cursor: pointer;
+  }
+  :deep(.el-table__row:hover > td) {
+    background-color: var(--el-color-primary-light-9) !important;
+  }
+  /* 閫変腑琛岋細涓昏壊鑳屾櫙 + 鍔犵矖 + 宸︿晶 4px 涓昏壊鏉� */
+  :deep(.el-table__row.is-selected > td) {
+    background-color: var(--el-color-primary-light-6) !important;
+    color: var(--el-color-primary-dark-2);
+    font-weight: 600;
+  }
+  :deep(.el-table__row.is-selected > td:first-child) {
+    box-shadow: inset 4px 0 0 var(--el-color-primary);
+  }
+}
+
+/* 閫夋嫨妗嗗簳閮ㄣ�屽凡閫夈�嶅洖鏄� */
+.emergency-selected-hint {
+  float: left;
+  line-height: 32px;
+  font-size: 13px;
+  color: var(--el-color-primary);
+  font-weight: 600;
+}
+/* 銆愭湰闇�姹傘�戝氨璇婂彿涓嬫柟鐨勬潯鐮佽锛氭潯鐮� + [闅愯棌|鏉$爜] + [澶嶅埗] 鍚屼竴琛岋紝绱у噾涓嶆拺楂� */
+.barcode-row {
+  display: flex;
+  align-items: center;
+  gap: 6px;
+  margin-top: 4px;
+  flex-wrap: wrap;
+}
 .records-title {
   display: flex;
   align-items: center;

--
Gitblit v1.9.3