From 6ab4b1e0b68e4c347110e37018fa005603f53904 Mon Sep 17 00:00:00 2001
From: yxh <172933527@qq.com>
Date: 星期二, 29 九月 2026 23:49:04 +0800
Subject: [PATCH] ai优化

---
 src/utils/stringUtil.ts                              |   25 
 src/views/ecg/jobrecord/index.vue                    |   65 ++
 src/views/ecg/devrent/index.vue                      |   70 ++
 src/api/ecg/queue/index.ts                           |   22 
 src/views/ecg/doctor/components/DevInstallPanel.vue  |   50 +
 src/views/ecg/doctor/components/DevReadyPanel.vue    |   49 +
 src/views/ecg/doctor/components/PatientInfoBlock.vue |  210 +++++++
 src/api/ecg/jobrecord/index.ts                       |   18 
 src/views/ecg/appointment/alter.vue                  |   56 +
 src/views/ecg/doctor/components/RoutinePanel.vue     |   62 +
 src/views/ecg/appointment/index.vue                  |   51 +
 src/views/ecg/doctor/DevInstall.vue                  |  104 +++
 src/api/ecg/checktype/index.ts                       |    8 
 src/views/ecg/doctor/Routine.vue                     |  107 +++
 src/api/ecg/devrent/index.ts                         |   22 
 src/permission.ts                                    |  137 +++-
 src/views/ecg/doctor/DevDismantle.vue                |   24 
 src/api/ecg/appointment/index.ts                     |   16 
 src/views/ecg/appointment/AppointmentConfirm.vue     |   14 
 src/utils/auth.ts                                    |   11 
 src/hooks/web/useIdleLogout.ts                       |  142 ++++
 src/utils/dict.ts                                    |    8 
 src/views/ecg/doctor/index.vue                       |  102 +++
 src/utils/patientInfo.ts                             |  168 +++++
 src/api/ecg/doctor/index.ts                          |   35 +
 src/views/ecg/doctor/DevDataEntry.vue                |   24 
 src/views/ecg/queue/index.vue                        |   71 ++
 src/config/axios/service.ts                          |   16 
 src/views/ecg/checktype/CheckTypeForm.vue            |   21 
 29 files changed, 1,588 insertions(+), 120 deletions(-)

diff --git a/src/api/ecg/appointment/index.ts b/src/api/ecg/appointment/index.ts
index 181c91d..ddf795d 100644
--- a/src/api/ecg/appointment/index.ts
+++ b/src/api/ecg/appointment/index.ts
@@ -26,6 +26,22 @@
   bookCheckType: number // 棰勭害妫�鏌ョ被鍨�
   paid: number //宸蹭粯娆�
   bookSeqNum: number
+  // ========== 浠ヤ笅瀛楁鍚庣 AppointmentRespVO 涓�鐩存湁杩斿洖锛屾鍓� TS 鏈0鏄� ==========
+  // 闇�姹�1 浣跨敤锛氱姸鎬� / 寮�鍗曞尰甯� / 寮�鍗曟棩鏈� / 璺濅粖澶╂暟锛堢敱 doctorTime 璁$畻锛�/ 灏辫瘖鍗″彿
+  status?: string // 鐘舵�侊紙瀛楀吀 ecg_status锛�
+  doctor?: string // 寮�鍗曞尰甯�
+  doctorCode?: string // 寮�鍗曞尰甯堜唬鐮�
+  doctorTime?: Date | number | string // 寮�鍗曟棩鏈燂紙寮�鍗曟椂闂达級
+  registerDate?: Date | number | string // 鐧昏鏃堕棿
+  hospitalNo?: string // 浣忛櫌鍙�
+  medicalCard?: string // 灏辫瘖鍗″彿锛堝簱涓涓虹┖锛岄〉闈㈠洖閫�鍒� outpatientNo锛�
+  doctorAdviceNo?: string // 鍖诲槺鍙凤紙HIS root 2.16.156.10011.1.28锛涘簱涓巻鍙叉暟鎹负绌猴級
+  outpatientNo?: string // 闂ㄨ瘖鍙凤紙瀹炴祴閮ㄥ垎鏁版嵁瀛樼殑鏄韩浠借瘉鍙凤級
+  bookSrc?: number // 棰勭害鏉ユ簮锛�0浜哄伐 10骞冲彴
+  roomName?: string // 璇婂鍚嶇О
+  remark?: string // 澶囨敞
+  jjbz?: string // 鍔犳�ユ爣璁�
+  createTime?: Date | number | string // 鍒涘缓鏃堕棿
 }
 
 // 棰勭害 API
diff --git a/src/api/ecg/checktype/index.ts b/src/api/ecg/checktype/index.ts
index 3d57289..5cb1657 100644
--- a/src/api/ecg/checktype/index.ts
+++ b/src/api/ecg/checktype/index.ts
@@ -15,6 +15,14 @@
   affinityCheckTypes: number[] | null// 浜插拰鐨勬鏌ョ被鍨�
   notes: string  // 棰勭害娉ㄦ剰浜嬮」
   seqPrefix: string // 搴忓彿鍓嶇紑
+  /**
+   * 鎺掗槦搴忓彿瑙勫垯锛�
+   * 0=棰勭害鍙凤紙鐢ㄩ绾︾郴缁熺殑鍙凤紝涓嶅啀鍒嗛厤锛�
+   * 1=绛惧埌搴忓彿锛堝綋澶╁悓妫�鏌ョ被鍨嬭繛缁�掑锛屾瘡 9 涓鐣� 1 涓粰鍔犳�ワ級
+   * 2=鏃舵鍙凤紙鎸夐绾︽椂闂存缁欏彿锛�
+   * 鏈厤缃�(null/undefined) 鏃跺悗绔寜 2 澶勭悊锛屼笌鏀归�犲墠琛屼负涓�鑷淬��
+   */
+  seqRule: number | null
 }
 
 // 妫�鏌ョ被鍨� API
diff --git a/src/api/ecg/devrent/index.ts b/src/api/ecg/devrent/index.ts
index cc73c15..326dfe2 100644
--- a/src/api/ecg/devrent/index.ts
+++ b/src/api/ecg/devrent/index.ts
@@ -12,12 +12,26 @@
   patGender?: number | undefined | null // 鎮h�呮�у埆锛�1 鐢� 2 濂筹紙鍚庣浠庨绾﹀崟琛ラ綈锛屼粎灞曠ず锛�
   patDetails?: PatDetailsVO | undefined | null
   checkType?: number | undefined | null
-  tolerance?: string | number | undefined | null // 鏄惁澶氳�愯嵂锛氬悗绔负瀛楃涓� "0"(鍚�) / "1"(鏄�)
+  // 澶氳�愯嵂锛�0 鏃� / 1 澶氳�� / 2 澶氶噸鑰愯嵂锛堝悗绔负瀛楃涓诧級
+  tolerance?: string | number | undefined | null
   // 浠ヤ笅瀛楁鐢卞悗绔粠棰勭害鍗曡ˉ榻愶紝浠呯敤浜庡尰鐢熺灞曠ず锛屼笉鍙備笌鎻愪氦
-  patBirthday?: number | undefined | null // 鍑虹敓鏃ユ湡锛堟绉掓椂闂存埑锛�
-  registerDate?: number | undefined | null // 鐧昏鏃堕棿锛堟绉掓椂闂存埑锛�
+  patBirthday?: number | string | undefined | null // 鍑虹敓鏃ユ湡
+  registerDate?: number | string | undefined | null // 鐧昏鏃堕棿
   doctor?: string | undefined | null // 寮�鍗曞尰甯�
-  doctorTime?: number | undefined | null // 寮�鍗曟棩鏈燂紙姣鏃堕棿鎴筹級
+  doctorTime?: number | string | undefined | null // 寮�鍗曟棩鏈�
+  // 闇�姹�1锛氭偅鑰呬俊鎭� 18 椤癸紙鍚庣 DevRentRespVO 宸叉墿瀛楁锛屽潎鐢遍绾﹀崟鍥炲~锛�
+  patSrc?: number | undefined | null // 鎮h�呮潵婧愶細1闂ㄨ瘖 2鎬ヨ瘖 3浣忛櫌 4浣撴
+  patMobile?: string | undefined | null // 鎵嬫満鍙�
+  patPhone?: string | undefined | null // 鐢佃瘽
+  patWardDesc?: string | undefined | null // 鐥呭尯鍚嶇О
+  patBedNo?: string | undefined | null // 鐥呭簥鍙凤紙娉ㄦ剰涓嶆槸 bedNo锛屽悗鑰呮槸璇婄枟搴�/宸ヤ綅鍙凤級
+  medicalCard?: string | undefined | null // 灏辫瘖鍗″彿锛堝簱涓涓虹┖锛�
+  doctorAdviceNo?: string // 鍖诲槺鍙凤紙HIS root 2.16.156.10011.1.28锛涘簱涓巻鍙叉暟鎹负绌猴級
+  outpatientNo?: string | undefined | null // 闂ㄨ瘖鍙�
+  patIdentityId?: string | undefined | null // 韬唤璇佸彿
+  // 闃熷垪鐩稿叧锛堢敱 setPatient 浠� QueueVO 甯﹀叆锛屼粎鐢ㄤ簬鍙彿闈㈡澘灞曠ず锛�
+  seqNum?: number | undefined | null // 鎺掗槦搴忓彿
+  status?: number | undefined | null // 闃熷垪鐘舵�侊紙瀛楀吀 ecg_queue_status锛�
   rentTime?: number | undefined | null // 瑁呮満鏃堕棿
   returnTime?: number | undefined | null // 鎷嗘満鏃堕棿
   interference?: number | undefined | null // 骞叉壈鏁�
diff --git a/src/api/ecg/doctor/index.ts b/src/api/ecg/doctor/index.ts
index c936d0f..b6c70a7 100644
--- a/src/api/ecg/doctor/index.ts
+++ b/src/api/ecg/doctor/index.ts
@@ -145,6 +145,41 @@
   patientJump: async (params: PatientVO) => {
     return await request.get({ url: `/ecg/doctor/patient-jump`, params })
   },
+
+  // ==================== 闇�姹�2锛氭挙閿�銆屽彨鍙� / 妫�鏌ュ畬鎴愩�� ====================
+
+  // 鎾ら攢妫�鏌ュ畬鎴愶細宸插氨璇�(40) 鈫� 鍊欒瘖涓�(20)銆傚繀椤诲甫 patId + checkType 绮剧‘瀹氫綅
+  undoFinishPatient: async (params: PatientVO) => {
+    return await request.get({ url: `/ecg/doctor/undo-finish-patient`, params })
+  },
+
+  // 鎾ら攢鍙彿锛氬氨璇婁腑(30) 鈫� 鍊欒瘖涓�(20)
+  undoCallPatient: async (params: { roomId: number | null; bedNo: string | null }) => {
+    return await request.get({ url: `/ecg/doctor/undo-call-patient`, params })
+  },
+
+  // 鍙栨湰宸ヤ綅浠婃棩鏈�杩戜竴浣嶅凡瀹屾垚鎮h�咃紙渚涙挙閿�鎻愮ず锛�
+  lastFinishedPatient: async (params: { roomId: number | null; bedNo: string | null }) => {
+    return await request.get({ url: `/ecg/doctor/last-finished-patient`, params })
+  },
+
+  // ==================== 闇�姹�3锛氬仠姝㈠�欒瘖寮�鍏� ====================
+
+  // 鍋滄鍊欒瘖锛氫笉鍐嶆柊澧炲�欒瘖鎮h�咃紙宸叉湁鍊欒瘖浠嶅彲鍙彿锛�
+  stopReady: async (params: { roomId: number | null; bedNo: string | null }) => {
+    return await request.get({ url: `/ecg/doctor/stop-ready`, params })
+  },
+
+  // 鎭㈠鍊欒瘖锛氶噸鏂板紑濮嬫帴鏀跺�欒瘖鎮h��
+  resumeReady: async (params: { roomId: number | null; bedNo: string | null }) => {
+    return await request.get({ url: `/ecg/doctor/resume-ready`, params })
+  },
+
+  // 鏌ヨ鍋滄鍊欒瘖鐘舵��
+  getStopReady: async (params: { roomId: number | null; bedNo: string | null }) => {
+    return await request.get({ url: `/ecg/doctor/get-stop-ready`, params })
+  },
+
   // 涓嬭浇
  yddownload: async (id: number | string) => {
   return await request.get({ url: `/ecg/template/download/${id}` })
diff --git a/src/api/ecg/jobrecord/index.ts b/src/api/ecg/jobrecord/index.ts
index fa51b0e..1d1ffe6 100644
--- a/src/api/ecg/jobrecord/index.ts
+++ b/src/api/ecg/jobrecord/index.ts
@@ -13,6 +13,24 @@
   summary: number // 浣滀笟姒傝
   remark: string // 澶囨敞
   paid: number
+  // 闇�姹�1锛氭偅鑰呬俊鎭� 18 椤癸紙鍚庣鎸� job_record.rentId 鈫� dev_rent.applyNo 鈫� appointment 鎵归噺鍥炲~锛�
+  applyNo?: string // 鐢宠缂栧彿
+  episodeId?: string // 灏辫瘖娴佹按鍙�
+  patGender?: number // 鎬у埆
+  patBirthday?: number | string // 鍑虹敓鏃ユ湡
+  registerDate?: number | string // 鐧昏鏃堕棿
+  doctor?: string // 寮�鍗曞尰甯�
+  doctorTime?: number | string // 寮�鍗曟棩鏈�
+  patSrc?: number // 鎮h�呮潵婧愶細1闂ㄨ瘖 2鎬ヨ瘖 3浣忛櫌 4浣撴
+  patMobile?: string
+  patPhone?: string
+  patWardDesc?: string // 鐥呭尯
+  patBedNo?: string // 鐥呭簥鍙�
+  medicalCard?: string // 灏辫瘖鍗″彿
+  doctorAdviceNo?: string // 鍖诲槺鍙凤紙HIS root 2.16.156.10011.1.28锛涘簱涓巻鍙叉暟鎹负绌猴級
+  outpatientNo?: string // 闂ㄨ瘖鍙�
+  patIdentityId?: string // 韬唤璇佸彿
+  tolerance?: string // 澶氳�愯嵂锛�0鏃� 1澶氳�� 2澶氶噸鑰愯嵂
 }
 
 export interface JobStatisticVO {
diff --git a/src/api/ecg/queue/index.ts b/src/api/ecg/queue/index.ts
index aa52013..5200e0d 100644
--- a/src/api/ecg/queue/index.ts
+++ b/src/api/ecg/queue/index.ts
@@ -14,20 +14,30 @@
   bookSeqNum?: number //棰勭害搴忓彿
   isVip?: number // 鏄惁VIP鎮h��
   seqNum?: number // 鎺掗槦搴忓彿
-  status?: number // 5:杩囧彿 10:鎺掗槦涓� 15:宸插彫鍥� 20:鍊欒瘖鍑嗗 30:灏辫瘖涓� 40:灏辫瘖瀹屾垚
+  status?: number // 3:宸茶繃鍙�-鎺掗槦 5:杩囧彿 7:宸茶繃鍙�-瀹夎 10:鎺掗槦涓� 15:宸插彫鍥� 20:鍊欒瘖涓� 30:灏辫瘖涓� 33:宸查鐢� 34:宸插彫鍥�-瀹夎 36:瀹夎涓� 40:宸插氨璇�
   passed?: number // 杩囧彿鏍囪
   expired?: number // 棰勭害杩囨湡鏍囪
   jumpFlag?: number //鎻掗槦鏍囪
   roomId?: number // 璇婂缂栧彿
   roomName?: string // 璇婂鍚嶇О
-  bedNo?: string // 璇婄枟搴婄紪鍙�
+  bedNo?: string // 璇婄枟搴婄紪鍙凤紙宸ヤ綅鍙凤紝闈炵梾搴婂彿锛侊級
   patDetails?: PatDetailsVO
   // 浠ヤ笅瀛楁鐢卞悗绔粠棰勭害鍗曡ˉ榻愶紙queue 琛ㄤ笉瀛橈級
-  tolerance?: string // 鏄惁澶氳�愯嵂锛�0 鍚︼紝1 鏄�
-  patBirthday?: number // 鍑虹敓鏃ユ湡锛堟椂闂存埑锛�
-  registerDate?: number // 鐧昏鏃堕棿锛堟椂闂存埑锛�
+  tolerance?: string // 澶氳�愯嵂锛�0 鏃狅紝1 澶氳�愶紝2 澶氶噸鑰愯嵂
+  patBirthday?: number | string // 鍑虹敓鏃ユ湡
+  registerDate?: number | string // 鐧昏鏃堕棿
   doctor?: string // 寮�鍗曞尰甯�
-  doctorTime?: number // 寮�鍗曟棩鏈�/寮�鍗曟椂闂达紙鏃堕棿鎴筹級
+  doctorTime?: number | string // 寮�鍗曟棩鏈�/寮�鍗曟椂闂�
+  // 闇�姹�1锛氭偅鑰呬俊鎭� 18 椤癸紙鍚屾牱鐢卞悗绔粠棰勭害鍗曞钩閾哄洖濉級
+  patSrc?: number // 鎮h�呮潵婧愶細1闂ㄨ瘖 2鎬ヨ瘖 3浣忛櫌 4浣撴
+  patMobile?: string // 鎵嬫満鍙�
+  patPhone?: string // 鐢佃瘽
+  patWardDesc?: string // 鐥呭尯鍚嶇О
+  patBedNo?: string // 鐥呭簥鍙凤紙鐪熸鐨勭梾搴婂彿锛�
+  medicalCard?: string // 灏辫瘖鍗″彿锛堝簱涓涓虹┖锛�
+  doctorAdviceNo?: string // 鍖诲槺鍙凤紙HIS root 2.16.156.10011.1.28锛涘簱涓巻鍙叉暟鎹负绌猴級
+  outpatientNo?: string // 闂ㄨ瘖鍙�
+  patIdentityId?: string // 韬唤璇佸彿
 }
 
 // 鎺掗槦 API
diff --git a/src/config/axios/service.ts b/src/config/axios/service.ts
index 0a6b968..6044c2c 100644
--- a/src/config/axios/service.ts
+++ b/src/config/axios/service.ts
@@ -205,6 +205,17 @@
 }
 const handleAuthorized = () => {
   const { t } = useI18n()
+
+  // 銆愪慨澶嶃�戦壌鏉冨け璐ユ椂**绔嬪嵆**娓呯悊鏈湴鍑瘉涓庣敤鎴风紦瀛橈紝涓嶅啀绛夌敤鎴风偣鍑诲脊绐椼��
+  //
+  // 鍘熷洜锛氬師鍏堝彧鏈夊湪鐢ㄦ埛鐐广�岄噸鏂扮櫥褰曘�嶅悗鎵� removeToken/deleteUserCache銆�
+  // 鑻ョ敤鎴蜂笉鐐癸紙鎴栭〉闈㈠湪鍚姩闃舵灏辫寮傚父鎵撴柇銆佸脊绐楅兘娌℃樉绀哄嚭鏉ワ級锛�
+  // 澶辨晥鐨� token 涓庤剰鐨勭敤鎴风紦瀛樹細涓�鐩寸暀鍦� localStorage 閲岋紝
+  // 瀵艰嚧"鍒锋柊椤甸潰 鈫� 鍐嶆鐢ㄦ棫 token 閴存潈 鈫� 鍐嶆澶辫触"鐨勫惊鐜紝
+  // 琛ㄧ幇涓烘瘡娆″惎鍔ㄩ兘寮广�岀櫥褰曡秴鏃讹紝璇烽噸鏂扮櫥褰曘�嶃��
+  removeToken()
+  deleteUserCache()
+
   if (!isRelogin.show) {
     // 濡傛灉宸茬粡鍒伴噸鏂扮櫥褰曢〉闈㈠垯涓嶈繘琛屽脊绐楁彁绀�
     if (window.location.href.includes('login?redirect=')) {
@@ -219,13 +230,10 @@
       type: 'warning'
     }).then(() => {
       resetRouter() // 閲嶇疆闈欐�佽矾鐢辫〃
-      deleteUserCache() // 鍒犻櫎鐢ㄦ埛缂撳瓨
-      removeToken()
       isRelogin.show = false
       // 骞叉帀token鍚庡啀璧颁竴娆¤矾鐢辫瀹冭繃router.beforeEach鐨勬牎楠�
       //window.location.href = window.location.href
-      window.location.href ="/login"
-
+      window.location.href = '/login'
     })
   }
   return Promise.reject(t('sys.api.timeoutMessage'))
diff --git a/src/hooks/web/useIdleLogout.ts b/src/hooks/web/useIdleLogout.ts
new file mode 100644
index 0000000..2cc1ab6
--- /dev/null
+++ b/src/hooks/web/useIdleLogout.ts
@@ -0,0 +1,142 @@
+import { watch } from 'vue'
+import { useIdle } from '@vueuse/core'
+import { ElMessage } from 'element-plus'
+
+/**
+ * 绌洪棽瓒呮椂鑷姩閫�鍑猴紙闇�姹傦細30 鍒嗛挓涓嶆搷浣滄墠瑕佹眰閲嶆柊杈撳叆瀵嗙爜锛夈��
+ *
+ * 鑳屾櫙
+ * ----
+ * 鍚庣 token 鏄�**鍥哄畾鏈夋晥鏈�**锛坄system_oauth2_client.access_token_validity_seconds`锛�
+ * 褰撳墠 default 瀹㈡埛绔� = 3600 绉掞級锛屼笌"鐢ㄦ埛鏄惁鏈夋搷浣�"鏃犲叧銆�
+ * 鍥犳浼氬嚭鐜颁袱绉嶉兘涓嶇悊鎯崇殑鎯呭喌锛�
+ *   路 椤甸潰鎸傜潃涓嶅姩 鈫� 鍒扮偣琚涪锛堢敤鎴疯寰�"鎴戞病鍋滆繃鎬庝箞鍙堣鐧诲綍"锛夛紱
+ *   路 涓�鐩存搷浣� 鈫� token 鍒版湡涔熶細琚涪锛堟湡鏈涙槸"鎸佺画鎿嶄綔灏变笉璇ラ噸鐧�"锛夈��
+ *
+ * 鏈ā鍧楀湪鍓嶇琛ヤ笂**鐪熸鐨勭┖闂叉娴�**锛�
+ *   路 鏈変换浣曢紶鏍�/閿洏/瑙︽懜/婊氬姩鎿嶄綔 鈫� 璁℃椂鍣ㄩ噸缃紱
+ *   路 杩炵画 30 鍒嗛挓**鏃犱换浣曟搷浣�** 鈫� 涓诲姩娓呯悊鐧诲綍鎬佸苟璺宠浆鐧诲綍椤碉紙瑕佹眰閲嶆柊杈撳瘑鐮侊級锛�
+ *   路 鏈夋搷浣滄椂涓嶄富鍔ㄧ櫥鍑猴紙token 鑷韩鐨勭画鏈熺敱 axios 鎷︽埅鍣ㄧ殑 refresh-token 璐熻矗锛夈��
+ *
+ * 鐢ㄦ硶锛堝湪 permission.ts 涓皟鐢ㄤ竴娆″嵆鍙紝鍐呴儴鑷甫骞傜瓑淇濇姢锛夛細
+ *   setupIdleLogout()
+ */
+
+/** 绌洪棽闃堝�硷細30 鍒嗛挓锛堥渶姹傛寚瀹氾級 */
+export const IDLE_TIMEOUT_MINUTES = 30
+const IDLE_TIMEOUT_MS = IDLE_TIMEOUT_MINUTES * 60 * 1000
+
+/**
+ * 瑙嗕负"鏈夋搷浣�"鐨勪簨浠躲��
+ * 鍒绘剰**涓�**鍖呭惈 mousemove 鐨勯珮棰戣妭娴侀棶棰橈細useIdle 鍐呴儴宸插仛鑺傛祦锛�
+ * 涓� mousemove 鏄垽鏂�"浜鸿繕鍦ㄧ數鑴戝墠"鐨勬渶鍙潬淇″彿锛堜緥濡傚彧鏄槄璇婚〉闈㈡椂浼氱Щ鍔ㄩ紶鏍囷級銆�
+ *
+ * 娉ㄦ剰锛氳瘖闂村睆/鍙彿灞忔槸闀挎椂闂存棤浜烘搷浣滅殑灞曠ず椤甸潰锛屼絾閭d簺椤甸潰鍦ㄨ矾鐢辩櫧鍚嶅崟閲�
+ * 锛堣 permission.ts 鐨� whiteList锛夛紝涓嶄細杩涘叆鏈�昏緫銆�
+ */
+const ACTIVITY_EVENTS = [
+  'mousemove',
+  'mousedown',
+  'mouseup',
+  'wheel',
+  'keydown',
+  'keyup',
+  'touchstart',
+  'touchend',
+  'click',
+  'scroll'
+] as const
+
+let started = false
+let idleWatcher: (() => void) | null = null
+
+/** 鏄惁宸插惎鍔紙閬垮厤閲嶅娉ㄥ唽锛� */
+export function isIdleLogoutStarted(): boolean {
+  return started
+}
+
+/** 娓呯悊锛堜竴鑸笉闇�瑕佽皟鐢紱鐧诲嚭鍚庤嫢鍐嶇櫥褰曪紝鐢� resetIdleLogout 閲嶇疆锛� */
+export function stopIdleLogout(): void {
+  if (idleWatcher) {
+    idleWatcher()
+    idleWatcher = null
+  }
+  started = false
+}
+
+/**
+ * 鍚姩绌洪棽鐧诲嚭妫�娴嬨�傚箓绛夛細閲嶅璋冪敤鍙敓鏁堜竴娆°��
+ *
+ * @param onTimeout 鑷畾涔夎秴鏃跺姩浣滐紙榛樿锛氭竻鍑瘉 + 璺崇櫥褰曢〉锛�
+ */
+export function setupIdleLogout(onTimeout?: () => void): void {
+  if (started) return
+  started = true
+
+  const { idle, lastActive, stop } = useIdle(IDLE_TIMEOUT_MS, {
+    events: ACTIVITY_EVENTS as unknown as string[],
+    listen: true
+  })
+
+  // 鏆撮湶 stop 渚夸簬澶栭儴鍋滄
+  idleWatcher = stop
+
+  // useIdle 鐨� idle 鏄熀浜�"璺濅笂娆℃椿鍔ㄦ槸鍚﹁秴杩囬槇鍊�"鐨勫搷搴斿紡甯冨皵鍊笺��
+  // 杩欓噷鐢� watch 鑰屼笉鏄� interval锛岄伩鍏嶈疆璇㈠紑閿�銆�
+  watch(idle, (isIdle: boolean) => {
+    if (!isIdle) return
+    // 鍙屼繚闄╋細鍐嶆鏍稿璺濅笂娆℃椿鍔ㄧ‘瀹炲凡瓒呰繃闃堝��
+    const inactiveMs = Date.now() - (lastActive.value || 0)
+    if (inactiveMs < IDLE_TIMEOUT_MS) return
+
+    if (onTimeout) {
+      onTimeout()
+      return
+    }
+    doIdleLogout()
+  })
+}
+
+/**
+ * 瀹為檯鎵ц绌洪棽鐧诲嚭锛氭竻鐞嗘湰鍦板嚟璇佸苟璺宠浆鐧诲綍椤点��
+ *
+ * 涔嬫墍浠ヤ笉璋冪敤 userStore.loginOut()锛堥偅鏄�"涓诲姩閫�鍑�"锛夛細
+ *   路 閭d釜鎺ュ彛浼氳姹傚悗绔敞閿� token 鈥� 瀵规湰鍦烘櫙娌″繀瑕侊紝涓斿彲鑳藉洜缃戠粶闂鍗′綇锛�
+ *   路 绌洪棽鐧诲嚭鍙渶淇濊瘉鏈湴鍑瘉娓呭共鍑� + 鍥炲埌鐧诲綍椤点��
+ */
+function doIdleLogout(): void {
+  ElMessage.warning(`宸茶秴杩� ${IDLE_TIMEOUT_MINUTES} 鍒嗛挓鏈搷浣滐紝璇烽噸鏂扮櫥褰昤)
+
+  cleanupCredentials()
+
+  // 鐢� replace 閬垮厤鐢ㄦ埛鎸�"杩斿洖"鍥炲埌宸茬櫥鍑虹殑椤甸潰
+  const redirect = encodeURIComponent(window.location.pathname + window.location.search)
+  setTimeout(() => {
+    window.location.replace(`/login?redirect=${redirect}`)
+  }, 800)
+}
+
+/**
+ * 娓呯悊鐧诲綍鍑瘉涓庣敤鎴风紦瀛樸��
+ * 鐢ㄥ姩鎬� import 閬垮厤涓� permission.ts 褰㈡垚寰幆渚濊禆銆�
+ */
+function cleanupCredentials(): void {
+  import('@/utils/auth')
+    .then(({ removeToken }) => {
+      removeToken()
+      return import('@/hooks/web/useCache')
+    })
+    .then(({ deleteUserCache }) => {
+      deleteUserCache()
+    })
+    .catch((e) => {
+      // 鍏滃簳锛氬嵆浣� import 澶辫触涔熺洿鎺ユ竻 localStorage锛屼繚璇佷笉浼氬甫鐫�鏃� token 鍥炲埌棣栭〉
+      try {
+        localStorage.removeItem('ACCESS_TOKEN')
+        localStorage.removeItem('REFRESH_TOKEN')
+      } catch {
+        /* ignore */
+      }
+      console.error('[idle-logout] 娓呯悊鍑瘉澶辫触', e)
+    })
+}
diff --git a/src/permission.ts b/src/permission.ts
index d0bfdfd..85c14e2 100644
--- a/src/permission.ts
+++ b/src/permission.ts
@@ -1,7 +1,8 @@
 import router from './router'
 import type { RouteRecordRaw } from 'vue-router'
 import { isRelogin } from '@/config/axios/service'
-import { getAccessToken } from '@/utils/auth'
+import { getAccessToken, removeToken } from '@/utils/auth'
+import { deleteUserCache } from '@/hooks/web/useCache'
 import { useTitle } from '@/hooks/web/useTitle'
 import { useNProgress } from '@/hooks/web/useNProgress'
 import { usePageLoading } from '@/hooks/web/usePageLoading'
@@ -10,6 +11,8 @@
 import { useUserStoreWithOut } from '@/store/modules/user'
 import { usePermissionStoreWithOut } from '@/store/modules/permission'
 import { useRoomStoreWithOut } from "@/store/modules/room";
+// 闇�姹傦細30 鍒嗛挓鏃犳搷浣滄墠瑕佹眰閲嶆柊鐧诲綍锛堝墠绔┖闂叉娴嬶級
+import { setupIdleLogout } from '@/hooks/web/useIdleLogout'
 
 const { start, done } = useNProgress()
 
@@ -76,66 +79,104 @@
     return
   }
 
-  if (to.path === '/login') {
-    next({ path: '/' })
-    return
-  }
+  // ==========================================================================
+  // 銆愪慨澶嶃�戜互涓嬫墍鏈� await 閮藉繀椤诲寘鍦� try/catch 鍐呫��
+  //
+  // 鑳屾櫙锛歭ocalStorage 閲屽彲鑳芥畫鐣�**宸插け鏁堢殑 token**锛堟湇鍔$閲嶅惎銆佷护鐗岃繃鏈熺瓑锛夈��
+  // 姝ゆ椂 getAccessToken() 浠嶆湁鍊� 鈫� 瀹堝崼涓嶄細璺崇櫥褰曢〉 鈫� 缁х画鐢ㄦ棫 token 璇锋眰鍚庣
+  // 鈫� 401 鈫� handleAuthorized() 杩斿洖 Promise.reject('鐧诲綍瓒呮椂,璇烽噸鏂扮櫥褰�!')銆�
+  // 鍘熷厛璇� reject 鏃犱汉鎹曡幏锛屼細涓�璺啋娉″埌 setupRouter()锛屽鑷达細
+  //     [Vue Router warn] uncaught error during route navigation
+  //     [Vue Router warn] Unexpected error when starting the router
+  //     main.ts:76 Uncaught (in promise) 鐧诲綍瓒呮椂,璇烽噸鏂扮櫥褰�!
+  // **璺敱瀹夎澶辫触锛屾暣涓〉闈㈣捣涓嶆潵**锛堢敤鎴峰繀椤绘墜鍔ㄩ噸鏂扮櫥褰曟墠鎭㈠锛夈��
+  //
+  // 鐜板湪缁熶竴鍏滃簳锛氭棤璁洪壌鏉冨け璐ヨ繕鏄叾浠栧紓甯革紝閮芥竻鎺夋湰鍦板け鏁堝嚟璇佸苟杞櫥褰曢〉锛�
+  // 淇濊瘉璺敱鍣ㄤ竴瀹氳兘瀹屾垚鍒濆鍖栥��
+  //
+  // 娉細鍘熷厛姝ゅ杩樻湁 `if (to.path === '/login') next({path:'/'})`锛�
+  // 鍥� '/login' 宸插湪 whiteList 涓彁鍓� return锛岃鍒嗘敮姘镐笉鍙揪锛屽凡绉婚櫎銆�
+  // ==========================================================================
+  try {
+    // 鑾峰彇鎵�鏈夊瓧鍏�
+    const dictStore = useDictStoreWithOut()
+    const userStore = useUserStoreWithOut()
+    const roomStore = useRoomStoreWithOut()
+    const checkTypeStore = useCheckTypeStoreWithOut()
+    const permissionStore = usePermissionStoreWithOut()
+    if (!dictStore.getIsSetDict) {
+      await dictStore.setDictMap()
+    }
+    if (!checkTypeStore.getIsSetCheckType) {
+      await checkTypeStore.setCheckTypeMap()
+    }
 
-  // 鑾峰彇鎵�鏈夊瓧鍏�
-  const dictStore = useDictStoreWithOut()
-  const userStore = useUserStoreWithOut()
-  const roomStore = useRoomStoreWithOut()
-  const checkTypeStore = useCheckTypeStoreWithOut()
-  const permissionStore = usePermissionStoreWithOut()
-  if (!dictStore.getIsSetDict) {
-    await dictStore.setDictMap()
-  }
-  if (!checkTypeStore.getIsSetCheckType) {
-    await checkTypeStore.setCheckTypeMap()
-  }
-
-  if (userStore.getIsSetUser ) {
+    if (userStore.getIsSetUser) {
 
       // <<<銆愯瘖瀹ら�夋嫨銆�<<<
-      if ( to.path !== '/roomselect' &&
+      if (to.path !== '/roomselect' &&
           userStore.getRoles.includes("doctor") && !userStore.getRoles.includes("super_admin")
-          && !roomStore.getIsSetRoom ) {
-          next({path: `/roomselect?redirect=${to.fullPath}`})
-          return
+          && !roomStore.getIsSetRoom) {
+        next({ path: `/roomselect?redirect=${to.fullPath}` })
+        return
       }
 
       next()
       return
+    }
+
+    isRelogin.show = true
+    await userStore.setUserInfoAction()
+    isRelogin.show = false
+
+    // 鍚庣杩囨护鑿滃崟
+    await permissionStore.generateRoutes()
+    permissionStore.getAddRouters.forEach((route) => {
+      router.addRoute(route as unknown as RouteRecordRaw) // 鍔ㄦ�佹坊鍔犲彲璁块棶璺敱琛�
+    })
+
+    // <<<銆愯瘖瀹ら�夋嫨銆�<<<
+    if (to.path !== '/roomselect' &&
+        userStore.getRoles.includes("doctor") && !userStore.getRoles.includes("super_admin")
+        && !roomStore.getIsSetRoom) {
+      next({ path: `/roomselect?redirect=${to.fullPath}` })
+      return
+    }
+
+    const redirectPath = from.query.redirect || to.path
+    // 淇璺宠浆鏃朵笉甯﹀弬鏁扮殑闂
+    const redirect = decodeURIComponent(redirectPath as string)
+    const { paramsObject: query } = parseURL(redirect)
+    const nextData = to.path === redirect ? { ...to, replace: true } : { path: redirect, query }
+    next(nextData)
+  } catch (e) {
+    // 鍏滃簳锛氭竻鐞嗘湰鍦板け鏁堝嚟璇侊紝鏀捐鍒扮櫥褰曢〉锛岀粷涓嶈寮傚父涓柇璺敱鍒濆鍖�
+    console.warn('[permission] 璺敱瀹堝崼鎵ц澶辫触锛屽凡娓呯悊鏈湴鍑瘉骞惰浆鐧诲綍椤碉細', e)
+    isRelogin.show = false
+    removeToken()
+    deleteUserCache()
+    next(`/login?redirect=${to.fullPath}`)
   }
-
-  isRelogin.show = true
-  await userStore.setUserInfoAction()
-  isRelogin.show = false
-
-  // 鍚庣杩囨护鑿滃崟
-  await permissionStore.generateRoutes()
-  permissionStore.getAddRouters.forEach((route) => {
-    router.addRoute(route as unknown as RouteRecordRaw) // 鍔ㄦ�佹坊鍔犲彲璁块棶璺敱琛�
-  })
-
-  // <<<銆愯瘖瀹ら�夋嫨銆�<<<
-  if ( to.path !== '/roomselect' &&
-      userStore.getRoles.includes("doctor") && !userStore.getRoles.includes("super_admin")
-      && !roomStore.getIsSetRoom ) {
-    next({path: `/roomselect?redirect=${to.fullPath}`})
-    return
-  }
-
-  const redirectPath = from.query.redirect || to.path
-  // 淇璺宠浆鏃朵笉甯﹀弬鏁扮殑闂
-  const redirect = decodeURIComponent(redirectPath as string)
-  const {paramsObject: query} = parseURL(redirect)
-  const nextData = to.path === redirect ? {...to, replace: true} : {path: redirect, query}
-  next(nextData)
 })
 
 router.afterEach((to) => {
   useTitle(to?.meta?.title as string)
   done() // 缁撴潫Progress
   loadDone()
+
+  // ==========================================================================
+  // 闇�姹傦細**30 鍒嗛挓涓嶆搷浣�**鎵嶈姹傞噸鏂拌緭鍏ュ瘑鐮併��
+  //
+  // 鑳屾櫙锛氬悗绔� token 鏄浐瀹氭湁鏁堟湡锛坰ystem_oauth2_client.access_token_validity_seconds锛�
+  // 褰撳墠 default 瀹㈡埛绔� = 3600 绉掞級锛屼笌鐢ㄦ埛鏄惁鏈夋搷浣滄棤鍏� 鈥斺�� 鎸傜潃涓嶅姩涔熶細鍒扮偣琚涪銆�
+  // 杩欓噷鍦ㄥ墠绔ˉ涓�**鐪熸鐨勭┖闂叉娴�**锛�
+  //   路 鏈夐紶鏍�/閿洏/瑙︽懜/婊氬姩绛夋搷浣� 鈫� 璁℃椂閲嶇疆锛�
+  //   路 杩炵画 30 鍒嗛挓鏃犱换浣曟搷浣�   鈫� 涓诲姩娓呭嚟璇佸苟璺崇櫥褰曢〉銆�
+  // 浠〃鐩�/鍙彿灞忕瓑鐧藉悕鍗曢〉闈笉浼氳蛋鍒拌繖閲岋紝涓嶅彈褰卞搷銆�
+  //
+  // 鍙湪**宸茬櫥褰�**涓旈潪鐧诲綍椤垫椂鍚姩锛泂etupIdleLogout 鍐呴儴骞傜瓑锛岄噸澶嶈皟鐢ㄦ棤鍓綔鐢ㄣ��
+  // ==========================================================================
+  if (getAccessToken() && to.path !== '/login') {
+    setupIdleLogout()
+  }
 })
diff --git a/src/utils/auth.ts b/src/utils/auth.ts
index 784033d..caa0d5f 100644
--- a/src/utils/auth.ts
+++ b/src/utils/auth.ts
@@ -26,8 +26,15 @@
 
 // 鍒犻櫎token
 export const removeToken = () => {
-  //wsCache.delete(AccessTokenKey)
- // wsCache.delete(RefreshTokenKey)
+  // 銆愪慨澶嶃�戝師瀹炵幇鎶婁笅闈袱琛� wsCache.delete 娉ㄩ噴鎺変簡锛屼娇鏈嚱鏁版垚涓�**绌烘搷浣�**銆�
+  // 鑰屼互涓嬩笁澶勯兘渚濊禆瀹冩竻鐞嗗嚟璇侊紝绌烘搷浣滀細寮曞彂杩為攣闂锛�
+  //   1) store/modules/user.ts 鐨� loginOut()锛氶��鍑虹櫥褰曞悗 token 浠嶇暀鍦� localStorage锛�
+  //      涓嬫鎵撳紑椤甸潰鍙堟嬁鏃� token 鍘婚壌鏉� 鈫� 401 鈫� 鎻愮ず"鐧诲綍瓒呮椂,璇烽噸鏂扮櫥褰�!"锛�
+  //   2) config/axios/service.ts 鐨� handleAuthorized()锛�401 鏃舵竻涓嶆帀澶辨晥鍑瘉锛�
+  //      鍒锋柊椤甸潰浼氶噸澶嶈Е鍙戝悓鏍风殑澶辫触娴佺▼锛�
+  //   3) permission.ts 璺敱瀹堝崼鐨勫紓甯稿厹搴曪細娓呯悊鏃犳晥銆�
+  wsCache.delete(AccessTokenKey)
+  wsCache.delete(RefreshTokenKey)
 }
 
 /** 鏍煎紡鍖杢oken锛坖wt鏍煎紡锛� */
diff --git a/src/utils/dict.ts b/src/utils/dict.ts
index a1422ce..0495e05 100644
--- a/src/utils/dict.ts
+++ b/src/utils/dict.ts
@@ -149,6 +149,10 @@
   ECG_DEV_BRAND = 'ecg_dev_brand',
   ECG_DEV_CATEGORY = 'ecg_dev_category',
   ECG_PAT_SOURCE = 'ecg_patient_source',
-  ecg_tolerance = 'ecg_tolerance',
-  ecg_status = 'ecg_status',
+  // 澶氳�愶紙澶氶噸鑰愯嵂锛夛細0=鏃� 1=澶氳�� 2=澶氶噸鑰愯嵂锛堣 _prep/09_fix_tolerance_dict.sql锛�
+  // 娉細鍘熷厛鍛藉悕涓哄皬鍐� ecg_tolerance锛屼笌鍚岀粍 ECG_* 椋庢牸涓嶄竴鑷达紝姝ゅ缁熶竴涓� ECG_TOLERANCE銆�
+  ECG_TOLERANCE = 'ecg_tolerance',
+  ECG_STATUS = 'ecg_status',
+  // 鎺掗槦搴忓彿瑙勫垯锛�0=棰勭害鍙� 1=绛惧埌搴忓彿 2=鏃舵鍙凤紙check_type.seq_rule锛岃 _prep/22_*.sql锛�
+  ECG_SEQ_RULE = 'ecg_seq_rule',
 }
diff --git a/src/utils/patientInfo.ts b/src/utils/patientInfo.ts
new file mode 100644
index 0000000..9f5df11
--- /dev/null
+++ b/src/utils/patientInfo.ts
@@ -0,0 +1,168 @@
+import dayjs from 'dayjs'
+import { calculateAge } from '@/utils/dateUtil'
+
+/**
+ * 鎮h�呬俊鎭睍绀虹殑鍏叡鏍煎紡鍖栧伐鍏枫��
+ *
+ * 鑳屾櫙锛堥渶姹�1锛夛細鎮h�呬俊鎭渶鍦�**姣忎釜鐣岄潰**灞曠ず 18 椤癸細
+ *   娴佹按鍙枫�佹帓闃熷簭鍙枫�佸鍚嶃�佹�у埆銆佸嚭鐢熸棩鏈熴�佸勾榫勩�侀」鐩�佺梾鍖恒�佺梾搴婂彿銆�
+ *   鐧昏鏃堕棿銆佺姸鎬併�佹偅鑰呯數璇濄�佸紑鍗曟棩鏈熴�佽窛浠婂ぉ鏁般�佹潵婧愶紙闂ㄦ�ヤ綇浣撴锛夈��
+ *   闂ㄨ瘖鍙枫�佸尰鍢卞彿銆佸紑鍗曞尰甯�
+ *
+ * 鍏朵腑 **骞撮緞** 涓� **璺濅粖澶╂暟** 鏁版嵁搴撴棤瀵瑰簲鍒楋紝蹇呴』瀹炴椂璁$畻銆�
+ * 鍘熷厛璇ョ畻娉曞唴鑱斿湪 RoutinePanel.vue 涓紝澶氫釜鐣岄潰鑻ュ悇鑷鍒朵細閫犳垚鍙e緞涓嶄竴鑷�
+ * 锛堜緥濡備竴涓寜 doctorTime 绠椼�佸彟涓�涓寜 createTime 绠楋級锛屾晠鎶藉埌姝ゅ缁熶竴銆�
+ *
+ * 娉ㄦ剰锛�
+ *   路 鍚庣杩斿洖鐨勭敓鏃�/鏃ユ湡瀛楁澶氫负瀛楃涓诧紙"2026-09-29" / "2026-09-29 10:00:00"锛夛紝
+ *     鏁呰繖閲岀粺涓�鐢� dayjs 鍏煎瑙f瀽锛岄伩鍏� Date 鏋勯�犲湪涓嶅悓娴忚鍣ㄤ笅鐨勫樊寮傘��
+ *   路 鎷夸笉鍒板�兼椂缁熶竴杩斿洖 ''锛堣�屼笉鏄� "NaN宀�" / "NaN澶�"锛夈��
+ */
+
+/**
+ * 骞撮緞锛氱敱鐢熸棩瀹炴椂璁$畻锛岃繑鍥炲舰濡� "65宀�"锛涙棤鐢熸棩/鐢熸棩闈炴硶鏃惰繑鍥� ''
+ *
+ * 娉ㄦ剰锛氬簱涓� `pat_birthday` 鍙兘鏄� `LocalDate`锛�"2000-01-01"锛夋垨
+ * 鏃堕棿鎴�/ISO 瀛楃涓诧紱涔熷彲鑳藉瓨鍦ㄨ剰鍊硷紙濡� "0000-00-00"锛夈��
+ * dayjs 瀵硅剰鍊艰繑鍥� Invalid锛宍diff` 浼氬緱鍒� NaN锛屾晠杩欓噷鍏堟樉寮忔牎楠屻��
+ */
+export function formatAge(birthday?: string | number | Date | null): string {
+  if (birthday === undefined || birthday === null || birthday === '') return ''
+  const d = dayjs(birthday as any)
+  if (!d.isValid()) return ''
+  const age = calculateAge(birthday as unknown as Date)
+  if (!Number.isFinite(age) || age < 0 || age > 150) return ''
+  return `${age}宀乣
+}
+
+/**
+ * 璺濅粖澶╂暟锛氭寜**寮�鍗曟棩鏈�**锛坉octorTime锛夎绠楋紝杩斿洖褰㈠ "3澶�"锛涙棤鍊兼椂杩斿洖 ''
+ *
+ * 璇存槑锛氶渶姹�1 鐨�"璺濅粖澶╂暟"鏄粰鍖荤敓鍒ゆ柇"杩欏紶鍗曞瓙鍘嬩簡澶氫箙"锛�
+ *       鍥犳鍩哄噯蹇呴』鏄�**寮�鍗曟棩鏈�**锛岃�屼笉鏄垱寤烘椂闂�/鐧昏鏃堕棿銆�
+ */
+export function formatDaysFromOrder(orderTime?: string | number | Date | null): string {
+  if (orderTime === undefined || orderTime === null || orderTime === '') return ''
+  const d = dayjs(orderTime)
+  if (!d.isValid()) return ''
+  const days = dayjs().startOf('day').diff(d.startOf('day'), 'day')
+  if (!Number.isFinite(days)) return ''
+  return `${days}澶ー
+}
+
+/**
+ * 璺濅粖澶╂暟锛堟暟鍊肩増锛屼究浜庢帓搴�/鏉′欢鏍峰紡锛�
+ */
+export function daysFromOrder(orderTime?: string | number | Date | null): number | null {
+  if (orderTime === undefined || orderTime === null || orderTime === '') return null
+  const d = dayjs(orderTime)
+  if (!d.isValid()) return null
+  return dayjs().startOf('day').diff(d.startOf('day'), 'day')
+}
+
+/**
+ * 鏃ユ湡鏃堕棿鏍煎紡鍖栵紙绌哄�煎畨鍏級锛岄粯璁� "YYYY-MM-DD HH:mm:ss"
+ */
+export function formatDateTime(
+  value?: string | number | Date | null,
+  format = 'YYYY-MM-DD HH:mm:ss'
+): string {
+  if (value === undefined || value === null || value === '') return ''
+  const d = dayjs(value)
+  return d.isValid() ? d.format(format) : ''
+}
+
+/**
+ * 鏃ユ湡鏍煎紡鍖栵紙绌哄�煎畨鍏級锛岄粯璁� "YYYY-MM-DD"
+ */
+export function formatDateOnly(
+  value?: string | number | Date | null,
+  format = 'YYYY-MM-DD'
+): string {
+  return formatDateTime(value, format)
+}
+
+/**
+ * 绌哄�煎畨鍏ㄥ睍绀猴細null/undefined/'' 缁熶竴鏄剧ず涓� "-"
+ */
+export function displayOr(value?: string | number | null, placeholder = '-'): string {
+  if (value === undefined || value === null || value === '') return placeholder
+  return String(value)
+}
+
+/** 灏辫瘖鍗″彿鐨勮В鏋愮粨鏋滐細鍊� + 瀹為檯鏉ユ簮鏍囨敞 */
+export interface CardNoResult {
+  /** 灞曠ず鐢ㄥ�硷紙鏃犱换浣曞�欓�夋椂涓� '-'锛� */
+  value: string
+  /** 鍊肩殑鐪熷疄鏉ユ簮锛涙湁鐪熷崱鍙锋椂涓虹┖涓诧紙鏃犻渶鏍囨敞锛� */
+  from: '' | '闂ㄨ瘖鍙�' | '韬唤璇�' | '浣忛櫌鍙�'
+}
+
+/**
+ * 鍒ゆ柇涓�涓�兼槸鍚�"鍍忚韩浠借瘉鍙�"锛�18 浣嶆暟瀛楁湯浣嶅彲涓� X锛屾垨 15 浣嶇函鏁板瓧锛夈��
+ *
+ * 涓轰粈涔堥渶瑕佹寜**鍊肩殑褰㈡��**鍒ゆ柇锛岃�屼笉鏄寜瀛楁鍚嶏細
+ *   瀹炴祴 `appointment.outpatient_no` 娣峰悎瀛樻斁涓ょ被鍐呭 鈥斺��
+ *     18 浣嶈韩浠借瘉鏍煎紡 103604 琛岋紙65.2%锛�
+ *     12 浣嶇湡闂ㄨ瘖鍙�    54204 琛岋紙34.1%锛屽舰濡� 882609282283锛�
+ *   鑻ヤ竴寰嬫寜瀛楁鍚嶆爣娉ㄤ负銆岄棬璇婂彿銆嶏紝閭� 65% 鐨勮韩浠借瘉鍙蜂緷鐒惰閿欐爣銆�
+ */
+export function looksLikeIdCard(v?: string | null): boolean {
+  if (!v) return false
+  const s = String(v).trim()
+  return /^[0-9]{17}[0-9Xx]$/.test(s) || /^[0-9]{15}$/.test(s)
+}
+
+/**
+ * 瑙f瀽銆岄棬璇婂彿銆嶅垪鐨勫睍绀哄�间笌鏉ユ簮銆�
+ *
+ * 銆愯儗鏅�戝疄娴� HIS 鍦� S0201ECG 鎶ユ枃鐨� `patientPerson.id.item[1]`
+ * 锛坮oot `2.16.156.10011.1.15`锛屽畼鏂规枃妗f敞閲婂嵆銆屽尰淇濆崱鍙枫�嶏級
+ * **鎭掍负绌�**锛�222/222 鏉★級锛屽洜姝� `medical_card` 鍏ㄥ簱涓� NULL 鈥斺�� 璇﹁銆婇儴缃叉竻鍗曘��5.1銆�
+ *
+ * 銆愬垪鍚嶅彉鏇达紙缁忕‘璁わ級銆戠敱浜庤鍒�**瀹為檯灞曠ず鐨勬槸 `outpatient_no`**
+ * 锛堝疄娴� 159,116 琛岋細65% 褰㈠韬唤璇併��35% 涓洪棬璇婂彿锛沗medical_card` 鏃犱竴闈炵┖锛夛紝
+ * 椤甸潰鏍囩宸茬敱銆屽氨璇婂崱鍙枫�嶆敼涓恒��**闂ㄨ瘖鍙�**銆嶏紝閬垮厤鍖绘姢浜哄憳璇銆�
+ *
+ * 鍥為��浼樺厛绾т笌鏍囨敞瑙勫垯锛�
+ *   1. `medicalCard`               鈫� 鏃犳爣娉紙HIS 琛ラ綈鍗″彿鍚庝細璧版鍒嗘敮锛屾爣娉ㄨ嚜鍔ㄦ秷澶憋級
+ *   2. `outpatientNo` 闈炶韩浠借瘉褰㈡��  鈫� 鏍囨敞銆岄棬璇婂彿銆�
+ *   3. `outpatientNo` 鏄韩浠借瘉褰㈡��  鈫� 鏍囨敞銆岃韩浠借瘉銆�
+ *   4. `patIdentityId`             鈫� 鏍囨敞銆岃韩浠借瘉銆�
+ *   5. `hospitalNo`锛堜綇闄㈠彿锛�       鈫� 鏍囨敞銆屼綇闄㈠彿銆�
+ *   6. 閮芥病鏈�                      鈫� '-'
+ *
+ * > 鏍囨敞鐨勪綔鐢細`outpatient_no` 鏄�**娣峰悎鍒�**锛岄噷闈㈡棦鏈夌湡闂ㄨ瘖鍙蜂篃鏈夎韩浠借瘉鍙凤紝
+ * > 鏁呮寜**鍊煎舰鎬�**锛堣�岄潪瀛楁鍚嶏級鏍囨敞锛屼究浜庡尰鎶や汉鍛樺尯鍒嗐��
+ *
+ * @param row 鎮h��/棰勭害/闃熷垪/绉熻祦鏁版嵁瀵硅薄锛堝吋瀹瑰钩閾哄瓧娈典笌 patDetails锛�
+ */
+export function resolveCardNo(row: any): CardNoResult {
+  if (row === undefined || row === null) return { value: '-', from: '' }
+  const pd = row.patDetails || {}
+
+  const medical = firstNonEmpty(row.medicalCard, pd.medicalCard)
+  if (medical !== undefined) return { value: medical, from: '' }
+
+  const outpatient = firstNonEmpty(row.outpatientNo, pd.outpatientNo)
+  if (outpatient !== undefined) {
+    // 璇ュ垪瀹炴祴娣峰悎浜嗚韩浠借瘉鍙凤紝鎸夊舰鎬佹爣娉ㄨ�岄潪鎸夊瓧娈靛悕
+    return { value: outpatient, from: looksLikeIdCard(outpatient) ? '韬唤璇�' : '闂ㄨ瘖鍙�' }
+  }
+
+  const identity = firstNonEmpty(row.patIdentityId, pd.patIdentityId)
+  if (identity !== undefined) return { value: identity, from: '韬唤璇�' }
+
+  const hospital = firstNonEmpty(row.hospitalNo, pd.hospitalNo)
+  if (hospital !== undefined) return { value: hospital, from: '浣忛櫌鍙�' }
+
+  return { value: '-', from: '' }
+}
+
+/** 鍙栫涓�涓潪绌猴紙null/undefined/'' 鍧囪涓虹┖锛夊�硷紝鍏ㄧ┖鏃惰繑鍥� undefined */
+export function firstNonEmpty(...vals: any[]): string | undefined {
+  for (const v of vals) {
+    if (v !== undefined && v !== null && v !== '') return String(v)
+  }
+  return undefined
+}
diff --git a/src/utils/stringUtil.ts b/src/utils/stringUtil.ts
index ab955b6..1093bf7 100644
--- a/src/utils/stringUtil.ts
+++ b/src/utils/stringUtil.ts
@@ -3,10 +3,23 @@
   return value == null || value.trim() === '';
 }
 
-export function genderFormat(value: number): string {
-  if ( 1===value ) {
-    return "鐢�";
-  } else {
-    return "濂�";
-  }
+/**
+ * 鎬у埆鏍煎紡鍖栵紙1 鐢� / 2 濂筹級銆�
+ *
+ * 銆愪慨姝c�戝師瀹炵幇鏄� `if (1===value) "鐢�" else "濂�"` 鈥斺�� 浼氭妸**浠讳綍闈� 1 鐨勫��**閮藉綋鎴�"濂�"锛�
+ * 鍖呮嫭 0锛堟湭鐭ワ級涓� null/undefined銆傚疄娴嬪簱涓� `pat_gender = 0` 鏈� 2,123 琛�
+ * 锛堣 AppointmentServiceImpl 鐨� UNKNOWN_GENDER 甯搁噺璇箟锛夛紝杩欎簺鎮h�呬細琚�**閿欐樉涓哄コ鎬�**銆�
+ *
+ * 鍙﹀娉ㄦ剰锛歁ySQL 鐨� `tinyint(1)` 浼氳 JDBC 椹卞姩鏄犲皠涓� Boolean锛�
+ * 鏁呰繖閲屽悓鏃跺吋瀹� boolean / 瀛楃涓叉暟瀛楋紙"1"銆�"2"锛夌瓑褰㈡�併��
+ */
+export function genderFormat(value: number | string | boolean | null | undefined): string {
+  if (value === null || value === undefined || value === '') return '鏈煡'
+  if (value === true) return '鐢�'
+  if (value === false) return '鏈煡'
+  const n = Number(value)
+  if (n === 1) return '鐢�'
+  if (n === 2) return '濂�'
+  // 0 = 鏈煡锛圚IS 鏈彁渚涳級锛屼笉瑕侀粯璁ゆ垚"濂�"
+  return '鏈煡'
 }
diff --git a/src/views/ecg/appointment/AppointmentConfirm.vue b/src/views/ecg/appointment/AppointmentConfirm.vue
index d4d2b98..d78ced3 100644
--- a/src/views/ecg/appointment/AppointmentConfirm.vue
+++ b/src/views/ecg/appointment/AppointmentConfirm.vue
@@ -52,17 +52,9 @@
       </el-form-item>
 
       <el-form-item label="澶氳�愯嵂" prop="tolerance">
-        <el-tag type="info" v-if="formData.tolerance == 0">鍚�</el-tag>
-        <el-tag type="danger" v-else>鏄�</el-tag>
-        <!-- <el-radio-group v-model="formData.tolerance" readonly>
-          <el-radio
-            v-for="dict in getIntDictOptions(DICT_TYPE.ecg_tolerance)"
-            :key="dict.value"
-            :value="dict.value"
-          >
-            {{ dict.label }}
-          </el-radio>
-        </el-radio-group> -->
+        <!-- 闇�姹�6锛氱粺涓�璧板瓧鍏� ecg_tolerance锛�0=鏃� 1=澶氳�� 2=澶氶噸鑰愯嵂锛夛紱NULL 鎸�"鏃�"鏄剧ず锛圦12锛夈��
+             鍘熷厛纭紪鐮� v-if==0鈫掑惁 / v-else鈫掓槸锛屾枃妗堜笌瀛楀吀涓嶄竴鑷淬�� -->
+        <dict-tag :type="DICT_TYPE.ECG_TOLERANCE" :value="formData.tolerance ?? 0" />
       </el-form-item>
     </div>
     <div class="form-row">
diff --git a/src/views/ecg/appointment/alter.vue b/src/views/ecg/appointment/alter.vue
index 111919d..1ce575b 100644
--- a/src/views/ecg/appointment/alter.vue
+++ b/src/views/ecg/appointment/alter.vue
@@ -220,6 +220,56 @@
       />
       <el-table-column label="寮�鍗曞尰鐢�" align="center" prop="doctor" width="110px" />
       <el-table-column label="鎵嬫満" align="center" prop="patMobile" />
+      <!-- 闇�姹�1锛氳ˉ榻愭偅鑰呬俊鎭� 18 椤逛腑缂哄け鐨勶紙骞撮緞/鎬у埆/鏉ユ簮/鐧昏鏃堕棿/寮�鍗曟棩鏈�/璺濅粖澶╂暟/鐘舵��/闂ㄨ瘖鍙�/澶氳�愶級 -->
+      <el-table-column label="鎬у埆" align="center" width="70px">
+        <template #default="scope">
+          <!-- 1鐢�/2濂筹紱0 鎴栫己澶憋紙HIS 鏈彁渚涳紝瀹炴祴搴撲腑鏈� 2123 琛�=0锛夋樉绀�"鏈煡" -->
+          <dict-tag v-if="scope.row.patGender === 1 || scope.row.patGender === 2"
+                    :type="DICT_TYPE.SYSTEM_USER_SEX" :value="scope.row.patGender" />
+          <span v-else>鏈煡</span>
+        </template>
+      </el-table-column>
+      <!-- 闇�姹�1锛氬尰鍢卞彿锛圚IS observationRequest.id.item[root=2.16.156.10011.1.28]锛夈��
+           璇ヨ妭鐐瑰湪瑙勮寖涓潪蹇呴』椤癸紝鍘嗗彶鏁版嵁锛堟柊澧炲垪涔嬪墠閲囬泦鐨勶級涓虹┖锛屾樉绀� '-'銆� -->
+      <el-table-column label="鍖诲槺鍙�" align="center" prop="doctorAdviceNo" min-width="110px">
+        <template #default="scope">
+          {{ scope.row.doctorAdviceNo || '-' }}
+        </template>
+      </el-table-column>
+      <el-table-column label="骞撮緞" align="center" width="80px">
+        <template #default="scope">{{ formatAge(scope.row.patBirthday) || '-' }}</template>
+      </el-table-column>
+      <el-table-column label="鏉ユ簮" align="center" width="90px">
+        <template #default="scope">
+          <dict-tag v-if="scope.row.patSrc !== undefined && scope.row.patSrc !== null"
+                    :type="DICT_TYPE.ECG_PAT_SOURCE" :value="scope.row.patSrc" />
+          <span v-else>-</span>
+        </template>
+      </el-table-column>
+      <!-- 鏈垪鏍囩鐢便�屽氨璇婂崱鍙枫�嶆敼涓恒�岄棬璇婂彿銆嶏紙缁忕‘璁わ級锛歮edical_card 鍏ㄥ簱涓虹┖锛�
+           璇ュ垪瀹為檯鏄剧ず outpatient_no锛況esolveCardNo 缁欏嚭**鏉ユ簮鏍囨敞**锛堣瑙併�婇儴缃叉竻鍗曘��5.1锛夈�� -->
+      <el-table-column label="闂ㄨ瘖鍙�" align="center" min-width="140px">
+        <template #default="scope">
+          <span>{{ resolveCardNo(scope.row).value }}</span>
+          <el-tag v-if="resolveCardNo(scope.row).from" size="small" type="info" effect="plain" class="ml-1">
+            {{ resolveCardNo(scope.row).from }}
+          </el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="澶氳��" align="center" width="110px">
+        <template #default="scope">
+          <dict-tag :type="DICT_TYPE.ECG_TOLERANCE" :value="scope.row.tolerance ?? 0" />
+        </template>
+      </el-table-column>
+      <el-table-column label="鐧昏鏃堕棿" align="center" min-width="150px">
+        <template #default="scope">{{ formatDateTime(scope.row.registerDate) || '-' }}</template>
+      </el-table-column>
+      <el-table-column label="寮�鍗曟棩鏈�" align="center" min-width="150px">
+        <template #default="scope">{{ formatDateTime(scope.row.doctorTime) || '-' }}</template>
+      </el-table-column>
+      <el-table-column label="璺濅粖澶╂暟" align="center" width="90px">
+        <template #default="scope">{{ formatDaysFromOrder(scope.row.doctorTime) || '-' }}</template>
+      </el-table-column>
       <!--      <el-table-column label="鐢佃瘽" align="center" prop="patPhone" />-->
       <!--      <el-table-column label="韬唤璇佸彿" align="center" prop="patIdentityId" />-->
       <!-- <el-table-column label="绉戝浠g爜" align="center" prop="patDeptCode" /> -->
@@ -245,8 +295,8 @@
             v-hasPermi="['ecg:appointment:update']"
           >
             <dict-tag
-              v-if="scope.row.status"
-              :type="DICT_TYPE.ecg_status"
+              v-if="scope.row.status !== null && scope.row.status !== undefined && scope.row.status !== ''"
+              :type="DICT_TYPE.ECG_STATUS"
               :value="scope.row.status"
             />
             <div v-else>鐘舵�佺紪杈�</div>
@@ -310,6 +360,8 @@
 import AppointmentForm from './AppointmentForm.vue'
 import { useCheckTypeStore } from '@/store/modules/checkType'
 import { getCheckTypeName } from '../../../utils/checkTypeFormatter'
+// 闇�姹�1锛氬勾榫� / 璺濅粖澶╂暟 / 鏃ユ湡鏍煎紡鍖栵紙搴撲腑鏃犲搴斿垪锛岄渶瀹炴椂璁$畻锛�
+import { formatAge, formatDaysFromOrder, formatDateTime, resolveCardNo } from '@/utils/patientInfo'
 import { status } from 'nprogress'
 import { log } from 'node:console'
 
diff --git a/src/views/ecg/appointment/index.vue b/src/views/ecg/appointment/index.vue
index 1001f92..df9b147 100644
--- a/src/views/ecg/appointment/index.vue
+++ b/src/views/ecg/appointment/index.vue
@@ -138,6 +138,27 @@
       <el-table-column label="灏辫瘖娴佹按鍙�" align="center" prop="episodeId" min-width="110px"/>
       <el-table-column label="鐢宠鍙�" align="center" prop="applyNo" min-width="110px"/>
       <el-table-column label="缂栧彿" align="center" prop="patId" />
+      <!-- 鏈垪鏍囩鐢便�屽氨璇婂崱鍙枫�嶆敼涓恒�岄棬璇婂彿銆嶏紙缁忕‘璁わ級銆傚師鍥狅紙璇﹁銆婇儴缃叉竻鍗曘��5.1锛夛細
+           HIS 鍦ㄥ崱鍙锋Ы浣嶄紶绌猴紝medical_card 鍏ㄥ簱 159,116 琛�**鏃犱竴闈炵┖**锛�
+           瀹炴祴璇ュ垪 99.9% 鏄剧ず鐨勬槸 outpatient_no锛�65% 褰㈠韬唤璇併��35% 涓洪棬璇婂彿锛夈��
+           鑻ョ户缁彨銆屽氨璇婂崱鍙枫�嶄細璁╁尰鎶や汉鍛樿璇伙紝鏁呮寜瀹為檯鍚箟鍛藉悕銆�
+           resolveCardNo 浠嶆寜鍊煎舰鎬佺粰鍑�**鏉ユ簮鏍囨敞**锛堣韩浠借瘉/浣忛櫌鍙�/闂ㄨ瘖鍙凤級锛�
+           渚夸簬鍖哄垎娣峰湪 outpatient_no 閲岀殑韬唤璇佸彿銆� -->
+      <el-table-column label="闂ㄨ瘖鍙�" align="center" min-width="140px">
+        <template #default="scope">
+          <span>{{ resolveCardNo(scope.row).value }}</span>
+          <el-tag v-if="resolveCardNo(scope.row).from" size="small" type="info" effect="plain" class="ml-1">
+            {{ resolveCardNo(scope.row).from }}
+          </el-tag>
+        </template>
+      </el-table-column>
+      <!-- 闇�姹�1锛氬尰鍢卞彿锛圚IS observationRequest.id.item[root=2.16.156.10011.1.28]锛夈��
+           璇ヨ妭鐐瑰湪瑙勮寖涓潪蹇呴』椤癸紝鍘嗗彶鏁版嵁锛堟柊澧炲垪涔嬪墠閲囬泦鐨勶級涓虹┖锛屾樉绀� '-'銆� -->
+      <el-table-column label="鍖诲槺鍙�" align="center" prop="doctorAdviceNo" min-width="110px">
+        <template #default="scope">
+          {{ scope.row.doctorAdviceNo || '-' }}
+        </template>
+      </el-table-column>
 <!--
       <el-table-column label="缂磋垂" align="center" prop="paid">
         <template #default="scope">
@@ -150,6 +171,34 @@
           {{scope.row.patName}} <dict-tag :type="DICT_TYPE.SYSTEM_USER_SEX" :value="scope.row.patGender" />
           <dict-tag :type="DICT_TYPE.ECG_PAT_SOURCE" :value="scope.row.patSrc" />
         </template>
+      </el-table-column>
+      <!-- 闇�姹�1锛氱姸鎬� -->
+      <!-- 娉ㄦ剰锛氬繀椤绘樉寮忓垽绌猴紝涓嶈兘鐢� v-if="scope.row.status" 鈥斺��
+           鐘舵�� '0'锛堟湭鐧昏锛夋槸鍚堟硶鍊硷紝鐪熷�煎垽鏂細鎶婂畠璇垽涓�"鏃犳暟鎹�"鑰屾樉绀� '-' -->
+      <el-table-column label="鐘舵��" align="center" prop="status" width="110px">
+        <template #default="scope">
+          <dict-tag
+            v-if="scope.row.status !== null && scope.row.status !== undefined && scope.row.status !== ''"
+            :type="DICT_TYPE.ECG_STATUS"
+            :value="scope.row.status"
+          />
+          <span v-else>-</span>
+        </template>
+      </el-table-column>
+      <!-- 闇�姹�1锛氬勾榫勶紙搴撲腑鏃犳鍒楋紝鐢辩敓鏃ュ疄鏃惰绠楋級 -->
+      <el-table-column label="骞撮緞" align="center" width="80px">
+        <template #default="scope">{{ formatAge(scope.row.patBirthday) }}</template>
+      </el-table-column>
+      <!-- 闇�姹�1锛氬紑鍗曟棩鏈� + 璺濅粖澶╂暟 -->
+      <el-table-column label="寮�鍗曟棩鏈�" align="center" min-width="150px">
+        <template #default="scope">{{ formatDateTime(scope.row.doctorTime) }}</template>
+      </el-table-column>
+      <el-table-column label="璺濅粖澶╂暟" align="center" width="90px">
+        <template #default="scope">{{ formatDaysFromOrder(scope.row.doctorTime) }}</template>
+      </el-table-column>
+      <!-- 闇�姹�1锛氬紑鍗曞尰甯� -->
+      <el-table-column label="寮�鍗曞尰甯�" align="center" prop="doctor" min-width="100px">
+        <template #default="scope">{{ scope.row.doctor || '-' }}</template>
       </el-table-column>
       <el-table-column
           label="棰勭害鏃ユ湡"
@@ -216,6 +265,8 @@
 <script setup lang="ts">
 import {DICT_TYPE} from '@/utils/dict'
 import { dateFormatter2 } from '@/utils/formatTime'
+// 闇�姹�1锛氬勾榫� / 璺濅粖澶╂暟 / 寮�鍗曟棩鏈熸牸寮忓寲锛堝簱涓棤瀵瑰簲鍒楋紝闇�瀹炴椂璁$畻锛�
+import { formatAge, formatDaysFromOrder, formatDateTime, resolveCardNo } from '@/utils/patientInfo'
 import download from '@/utils/download'
 import { AppointmentApi, AppointmentVO } from '@/api/ecg/appointment'
 import AppointmentForm from './AppointmentForm.vue'
diff --git a/src/views/ecg/checktype/CheckTypeForm.vue b/src/views/ecg/checktype/CheckTypeForm.vue
index bc720df..2d95175 100644
--- a/src/views/ecg/checktype/CheckTypeForm.vue
+++ b/src/views/ecg/checktype/CheckTypeForm.vue
@@ -52,8 +52,20 @@
       <el-form-item label="棰勭害娉ㄦ剰浜嬮」" prop="notes">
         <el-input v-model="formData.notes" placeholder="璇疯緭鍏ラ绾︽敞鎰忎簨椤�" />
       </el-form-item>
-      <el-form-item label="搴忓彿鍓嶇紑" prop="notes">
+      <el-form-item label="搴忓彿鍓嶇紑" prop="seqPrefix">
         <el-input v-model="formData.seqPrefix" placeholder="璇疯緭鍏ュ簭鍙峰墠缂�" />
+      </el-form-item>
+      <!-- 闇�姹傦細鎺掗槦搴忓彿瑙勫垯锛堢鍒版椂濡備綍缁欐偅鑰呮帓闃熷簭鍙凤級 -->
+      <el-form-item label="鎺掗槦搴忓彿瑙勫垯" prop="seqRule">
+        <el-select v-model="formData.seqRule" placeholder="璇烽�夋嫨鎺掗槦搴忓彿瑙勫垯" class="w-full">
+          <el-option v-for="dict in getIntDictOptions(DICT_TYPE.ECG_SEQ_RULE)"
+                     :key="dict.value" :label="dict.label" :value="dict.value" />
+        </el-select>
+        <div class="text-12px text-gray-500 leading-5 mt-1">
+          棰勭害鍙凤細鐢ㄩ绾︾郴缁熶笅鍙戠殑鍙凤紝绛惧埌涓嶅啀鍒嗛厤锛�<br />
+          绛惧埌搴忓彿锛氬綋澶╁悓妫�鏌ョ被鍨嬪唴杩炵画閫掑锛堢 1 涓鍒�=1 鍙凤級锛屾瘡 9 涓彿棰勭暀 1 涓粰鍔犳�ワ紱<br />
+          鏃舵鍙凤細鎸夐绾︽椂闂存缁欏彿锛�<b>涓嶉�夋椂榛樿姝ら」</b>锛屼笌鏀归�犲墠琛屼负涓�鑷达級銆�
+        </div>
       </el-form-item>
       <el-form-item label="浜插拰鐨勬鏌ョ被鍨�" prop="affinityCheckTypes">
         <el-checkbox-group v-model="formData.affinityCheckTypes">
@@ -97,7 +109,9 @@
   timeslotReservedNum: undefined,
   affinityCheckTypes: [],
   notes: undefined,
-  seqPrefix: undefined
+  seqPrefix: undefined,
+  // 鎺掗槦搴忓彿瑙勫垯锛氱暀绌哄嵆鎸夊悗绔粯璁わ紙鏃舵鍙凤級澶勭悊锛屼笌鏀归�犲墠琛屼负涓�鑷�
+  seqRule: undefined
 })
 const formRules = reactive({
 })
@@ -160,7 +174,8 @@
     timeslotReservedNum: undefined,
     affinityCheckTypes: [],
     notes: undefined,
-    seqPrefix: undefined
+    seqPrefix: undefined,
+    seqRule: undefined
   }
   formRef.value?.resetFields()
 }
diff --git a/src/views/ecg/devrent/index.vue b/src/views/ecg/devrent/index.vue
index ae84885..cef7a19 100644
--- a/src/views/ecg/devrent/index.vue
+++ b/src/views/ecg/devrent/index.vue
@@ -94,6 +94,73 @@
       <el-table-column label="璁惧缂栧彿" align="center" prop="devId" />
       <el-table-column label="鎮h�呯紪鍙�" align="center" prop="patId" />
       <el-table-column label="鎮h�呭悕绉�" align="center" prop="patName" />
+      <!-- 闇�姹�1锛氶棬璇婂彿 + 鍖诲槺鍙凤紙姝ゅ墠杩欎袱涓〉闈㈤仐婕忎簡璇ュ垪锛屾湰娆¤ˉ榻愶級
+           鏍囩鐢便�屽氨璇婂崱鍙枫�嶆敼涓恒�岄棬璇婂彿銆嶏紙缁忕‘璁わ級锛歮edical_card 鍏ㄥ簱涓虹┖锛�
+           璇ュ垪瀹為檯鏄剧ず outpatient_no锛堣瑙併�婇儴缃叉竻鍗曘��5.1锛夈�� -->
+      <el-table-column label="闂ㄨ瘖鍙�" align="center" min-width="140px">
+        <template #default="scope">
+          <span>{{ resolveCardNo(scope.row).value }}</span>
+          <el-tag v-if="resolveCardNo(scope.row).from" size="small" type="info" effect="plain" class="ml-1">
+            {{ resolveCardNo(scope.row).from }}
+          </el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="鍖诲槺鍙�" align="center" prop="doctorAdviceNo" min-width="110px">
+        <template #default="scope">
+          {{ scope.row.doctorAdviceNo || '-' }}
+        </template>
+      </el-table-column>
+
+      <!-- 闇�姹�1锛氳ˉ榻愭偅鑰呬俊鎭紙鍚庣 DevRentRespVO 宸叉墿瀛楁骞跺洖濉級 -->
+      <el-table-column label="鎬у埆" align="center" width="70px">
+        <template #default="scope">
+          <!-- 1鐢�/2濂筹紱0 鎴栫己澶憋紙HIS 鏈彁渚涳紝瀹炴祴搴撲腑鏈� 2123 琛�=0锛夋樉绀�"鏈煡" -->
+          <dict-tag v-if="scope.row.patGender === 1 || scope.row.patGender === 2"
+                    :type="DICT_TYPE.SYSTEM_USER_SEX" :value="scope.row.patGender" />
+          <span v-else>鏈煡</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="鍑虹敓鏃ユ湡" align="center" width="110px">
+        <template #default="scope">{{ formatDateOnly(scope.row.patBirthday) || '-' }}</template>
+      </el-table-column>
+      <el-table-column label="骞撮緞" align="center" width="80px">
+        <template #default="scope">{{ formatAge(scope.row.patBirthday) || '-' }}</template>
+      </el-table-column>
+      <el-table-column label="鏉ユ簮" align="center" width="90px">
+        <template #default="scope">
+          <dict-tag v-if="scope.row.patSrc !== undefined && scope.row.patSrc !== null"
+                    :type="DICT_TYPE.ECG_PAT_SOURCE" :value="scope.row.patSrc" />
+          <span v-else>-</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="鐥呭尯" align="center" min-width="110px">
+        <template #default="scope">{{ scope.row.patWardDesc || scope.row.patDetails?.wardDesc || '-' }}</template>
+      </el-table-column>
+      <el-table-column label="鐥呭簥鍙�" align="center" width="90px">
+        <template #default="scope">{{ scope.row.patBedNo || scope.row.patDetails?.bedNo || '-' }}</template>
+      </el-table-column>
+      <el-table-column label="鎮h�呯數璇�" align="center" min-width="120px">
+        <template #default="scope">
+          {{ scope.row.patMobile || scope.row.patPhone || scope.row.patDetails?.mobile || '-' }}
+        </template>
+      </el-table-column>
+      <el-table-column label="鐧昏鏃堕棿" align="center" min-width="150px">
+        <template #default="scope">{{ formatDateTime(scope.row.registerDate) || '-' }}</template>
+      </el-table-column>
+      <el-table-column label="寮�鍗曟棩鏈�" align="center" min-width="150px">
+        <template #default="scope">{{ formatDateTime(scope.row.doctorTime) || '-' }}</template>
+      </el-table-column>
+      <el-table-column label="璺濅粖澶╂暟" align="center" width="90px">
+        <template #default="scope">{{ formatDaysFromOrder(scope.row.doctorTime) || '-' }}</template>
+      </el-table-column>
+      <el-table-column label="寮�鍗曞尰甯�" align="center" min-width="100px">
+        <template #default="scope">{{ scope.row.doctor || '-' }}</template>
+      </el-table-column>
+      <el-table-column label="澶氳��" align="center" width="110px">
+        <template #default="scope">
+          <dict-tag :type="DICT_TYPE.ECG_TOLERANCE" :value="scope.row.tolerance ?? 0" />
+        </template>
+      </el-table-column>
       <el-table-column label="妫�鏌ョ被鍨�" align="center" prop="checkType" width="100px">
         <template #default="scope">
           <span>{{getCheckTypeName(scope.row.checkType)}}</span>
@@ -174,6 +241,9 @@
 import DevRentForm from './DevRentForm.vue'
 import {tranlateCheckState} from "../../../utils/statusFormatter";
 import {getCheckTypeName} from "../../../utils/checkTypeFormatter";
+// 闇�姹�1锛氭偅鑰呬俊鎭� 18 椤癸紙瀛楀吀 + 骞撮緞/璺濅粖澶╂暟绛夊疄鏃惰绠楋級
+import { DICT_TYPE } from '@/utils/dict'
+import { formatAge, formatDaysFromOrder, formatDateTime, formatDateOnly, resolveCardNo } from '@/utils/patientInfo'
 
 /** 瑁呮満鎷嗘満 鍒楄〃 */
 defineOptions({ name: 'DevRent' })
diff --git a/src/views/ecg/doctor/DevDataEntry.vue b/src/views/ecg/doctor/DevDataEntry.vue
index d03ab97..ac809e3 100644
--- a/src/views/ecg/doctor/DevDataEntry.vue
+++ b/src/views/ecg/doctor/DevDataEntry.vue
@@ -15,8 +15,10 @@
             <el-input v-model="formData.patName" placeholder="璇疯緭鍏ユ偅鑰呭悕绉�" />
           </el-form-item>
           <el-form-item label="鎮h�呮弿杩�" prop="patDeptDesc">
-            绉戝: {{formData?.patDetails?.deptDesc}} 鐥呭尯: {{formData?.patDetails?.wardDesc}} 搴婁綅: {{formData?.patDetails?.bedNo}}
+            绉戝: {{ formData?.patDetails?.deptDesc || '-' }} 鐥呭尯: {{ formData.patWardDesc || formData?.patDetails?.wardDesc || '-' }} 搴婁綅: {{ formData.patBedNo || formData?.patDetails?.bedNo || '-' }}
           </el-form-item>
+          <!-- 闇�姹�1锛氭偅鑰呬俊鎭� 18 椤癸紙鍚庣 DevRentRespVO 宸叉墿瀛楁骞跺洖濉級 -->
+          <PatientInfoBlock :data="formData" check-type-field="checkType" />
           <el-form-item label="褰曞叆鏃堕棿" prop="entryTime">
             <el-date-picker
                 v-model="formData.entryTime"
@@ -151,6 +153,8 @@
 import {JobRecordApi, JobRecordVO} from "@/api/ecg/jobrecord";
 import {isStringEmpty} from "@/utils/stringUtil";
 import {curDayEnd, curDayStart} from "@/utils/dateUtil";
+// 闇�姹�1锛氭偅鑰呬俊鎭� 18 椤圭粺涓�灞曠ず鍧�
+import PatientInfoBlock from "@/views/ecg/doctor/components/PatientInfoBlock.vue";
 
 /** 瑁呮満鎷嗘満 琛ㄥ崟 */
 defineOptions({ name: 'DevDataEntry' })
@@ -236,6 +240,24 @@
     category: '',
     brand: '',
     model: '',
+    // 闇�姹�1锛氭偅鑰呬俊鎭� 18 椤癸紙PatientInfoBlock 渚濊禆杩欎簺瀛楁锛�
+    // 涓嶅垵濮嬪寲浼氬鑷� Vue 鍦ㄦā鏉夸腑璇诲彇鏈畾涔夊睘鎬у苟鍛婅锛�
+    applyNo: undefined,
+    episodeId: undefined,
+    patGender: undefined,
+    patBirthday: undefined,
+    registerDate: undefined,
+    doctor: undefined,
+    doctorTime: undefined,
+    patSrc: undefined,
+    patMobile: undefined,
+    patPhone: undefined,
+    medicalCard: undefined,
+    outpatientNo: undefined,
+    patIdentityId: undefined,
+    tolerance: undefined,
+    status: undefined,
+    seqNum: undefined,
   }
   formRef.value?.resetFields()
 }
diff --git a/src/views/ecg/doctor/DevDismantle.vue b/src/views/ecg/doctor/DevDismantle.vue
index 724af68..2570b4d 100644
--- a/src/views/ecg/doctor/DevDismantle.vue
+++ b/src/views/ecg/doctor/DevDismantle.vue
@@ -16,8 +16,10 @@
             <el-input v-model="formData.patName" placeholder="璇疯緭鍏ユ偅鑰呭悕绉�" />
           </el-form-item>
           <el-form-item label="鎮h�呮弿杩�" prop="patDeptDesc">
-            绉戝: {{formData?.patDetails?.deptDesc}} 鐥呭尯: {{formData?.patDetails?.wardDesc}} 搴婁綅: {{formData?.patDetails?.bedNo}}
+            绉戝: {{ formData?.patDetails?.deptDesc || '-' }} 鐥呭尯: {{ formData.patWardDesc || formData?.patDetails?.wardDesc || '-' }} 搴婁綅: {{ formData.patBedNo || formData?.patDetails?.bedNo || '-' }}
           </el-form-item>
+          <!-- 闇�姹�1锛氭偅鑰呬俊鎭� 18 椤癸紙鍚庣 DevRentRespVO 宸叉墿瀛楁骞跺洖濉級 -->
+          <PatientInfoBlock :data="formData" check-type-field="checkType" />
           <el-form-item label="瑁呮満鏃堕棿" prop="rentTime">
             <el-date-picker
                 v-model="formData.rentTime"
@@ -152,6 +154,8 @@
 import {calculateHours, curDayEnd, curDayStart} from "@/utils/dateUtil";
 import {AppointmentApi} from "@/api/ecg/appointment";
 import {tranlateDevState} from "../../../utils/statusFormatter";
+// 闇�姹�1锛氭偅鑰呬俊鎭� 18 椤圭粺涓�灞曠ず鍧�
+import PatientInfoBlock from "@/views/ecg/doctor/components/PatientInfoBlock.vue";
 
 /** 瑁呮満鎷嗘満 琛ㄥ崟 */
 defineOptions({ name: 'DevrDismantle' })
@@ -287,6 +291,24 @@
     brand: '',
     model: '',
     devState: undefined,
+    // 闇�姹�1锛氭偅鑰呬俊鎭� 18 椤癸紙PatientInfoBlock 渚濊禆杩欎簺瀛楁锛�
+    // 涓嶅垵濮嬪寲浼氬鑷� Vue 鍦ㄦā鏉夸腑璇诲彇鏈畾涔夊睘鎬у苟鍛婅锛�
+    applyNo: undefined,
+    episodeId: undefined,
+    patGender: undefined,
+    patBirthday: undefined,
+    registerDate: undefined,
+    doctor: undefined,
+    doctorTime: undefined,
+    patSrc: undefined,
+    patMobile: undefined,
+    patPhone: undefined,
+    medicalCard: undefined,
+    outpatientNo: undefined,
+    patIdentityId: undefined,
+    tolerance: undefined,
+    status: undefined,
+    seqNum: undefined,
   }
   formRef.value?.resetFields()
 }
diff --git a/src/views/ecg/doctor/DevInstall.vue b/src/views/ecg/doctor/DevInstall.vue
index 823f41a..dc24d8f 100644
--- a/src/views/ecg/doctor/DevInstall.vue
+++ b/src/views/ecg/doctor/DevInstall.vue
@@ -9,7 +9,7 @@
 import QueuePanel from "@/views/ecg/doctor/components/QueuePanel.vue";
 import {DoctorApi, PatientStatisticVO, RoomBedVO} from '@/api/ecg/doctor';
 import {QueueVO} from "@/api/ecg/queue";
-import {ElNotification} from "element-plus";
+import {ElMessage, ElMessageBox, ElNotification} from "element-plus";
 import {useRoomStore} from "@/store/modules/room";
 
 const roomStore = useRoomStore();
@@ -102,6 +102,95 @@
     state.value = true
   else if (queueVO2.status === 30)
     state.value = false
+  // 闇�姹�3锛氬悓姝�"鍋滄鍊欒瘖"寮�鍏崇姸鎬�
+  await loadStopReady()
+}
+
+// ==================== 闇�姹�3锛氬仠姝㈠�欒瘖寮�鍏� ====================
+// 寮�鍚悗銆愬凡鏈夊�欒瘖鐥呬汉缁х画鍙彿锛屼絾涓嶅啀鏂板鍊欒瘖鐥呬汉銆戯紱鍏抽棴鍚庢仮澶嶃��
+// 娉細瑁呮満宸ヤ綅(opType=2)鏈韩涓嶈繘"鍒嗘祦闃熷垪"锛岃寮�鍏冲瑁呮満宸ヤ綅
+//     涓昏鐢ㄤ簬"鍋滄鎺ユ敹鏂扮殑寰呰鏈烘偅鑰�"鐨勮涔夌粺涓�涓庣姸鎬佸彲瑙併��
+const stopReady = ref<boolean>(false)
+const stopReadyFlag = ref<boolean>(true)
+
+const loadStopReady = async () => {
+  try {
+    stopReady.value = await DoctorApi.getStopReady(roomBedVO.value)
+  } catch (e) {
+    // 鏌ヨ澶辫触涓嶆墦鏂疆璇�
+  } finally {
+    stopReadyFlag.value = false
+  }
+}
+
+const onStopReadyChange = async (val: boolean) => {
+  stopReadyFlag.value = true
+  try {
+    if (val) {
+      await DoctorApi.stopReady(roomBedVO.value)
+      ElMessage.success('宸插仠姝㈠�欒瘖锛氫笉鍐嶆帴鏀舵柊鐨勫�欒瘖鎮h�咃紝宸叉湁鎮h�呬粛鍙甯稿彨鍙�')
+    } else {
+      await DoctorApi.resumeReady(roomBedVO.value)
+      ElMessage.success('宸叉仮澶嶅�欒瘖锛氬紑濮嬫帴鏀舵柊鐨勫�欒瘖鎮h��')
+    }
+    await initLoad()
+  } catch (e) {
+    stopReady.value = !val
+  } finally {
+    stopReadyFlag.value = false
+  }
+}
+
+// ==================== 闇�姹�2锛氭挙閿�鍙彿 / 鎾ら攢瑁呮満瀹屾垚 ====================
+const undoFlag = ref<boolean>(false)
+
+const undoCall = async () => {
+  try {
+    await ElMessageBox.confirm(
+      '纭畾瑕佹挙閿�鏈鍙彿鍚楋紵璇ユ偅鑰呭皢鍥炲埌鍊欒瘖鍖猴紝鍙噸鏂板彨鍙枫��',
+      '鎾ら攢鍙彿',
+      { type: 'warning', confirmButtonText: '纭畾鎾ら攢', cancelButtonText: '鍙栨秷' }
+    )
+  } catch {
+    return
+  }
+  undoFlag.value = true
+  try {
+    const msg = await DoctorApi.undoCallPatient(roomBedVO.value)
+    ElMessage.success(msg || '宸叉挙閿�鍙彿')
+    await initLoad()
+  } finally {
+    undoFlag.value = false
+  }
+}
+
+const undoFinish = async () => {
+  const last = await DoctorApi.lastFinishedPatient(roomBedVO.value)
+  if (!last || !last.patId) {
+    ElMessage.warning('鏈伐浣嶄粖鏃ユ殏鏃犲凡瀹屾垚鐨勬鏌ヨ褰�')
+    return
+  }
+  try {
+    await ElMessageBox.confirm(
+      `纭畾鎾ら攢銆�${last.patName || last.patId}銆嶇殑瀹屾垚鎿嶄綔鍚楋紵璇ユ偅鑰呭皢鍥炲埌鍊欒瘖鍖恒�俙,
+      '鎾ら攢瀹屾垚',
+      { type: 'warning', confirmButtonText: '纭畾鎾ら攢', cancelButtonText: '鍙栨秷' }
+    )
+  } catch {
+    return
+  }
+  undoFlag.value = true
+  try {
+    const msg = await DoctorApi.undoFinishPatient({
+      ...roomBedVO.value,
+      patId: last.patId,
+      checkType: last.bookCheckType
+    } as any)
+    ElMessage.success(msg || '宸叉挙閿�瀹屾垚')
+    await initLoad()
+  } finally {
+    undoFlag.value = false
+  }
 }
 
 const bedControl = async () => {
@@ -202,6 +291,19 @@
       <el-button :disabled="passFlag" type="primary" @click="passNextPatient">杩囧彿</el-button>
       <el-button  type="primary" @click="callAgain">閲嶅彨</el-button>
       <el-button :disabled="bedControlFlag" type="primary" @click="bedControl">{{state?'鏆傚仠':'鎭㈠'}}</el-button>
+      <!-- 闇�姹�3锛氬仠姝㈠�欒瘖寮�鍏筹紙宸叉湁鍊欒瘖鐥呬汉缁х画鍙彿锛屼絾涓嶅啀鏂板鍊欒瘖鐥呬汉锛� -->
+      <el-switch
+        v-model="stopReady"
+        :disabled="stopReadyFlag"
+        active-text="鍋滄鍊欒瘖"
+        inactive-text="姝e父鎺ヨ瘖"
+        inline-prompt
+        style="margin-left: 12px; --el-switch-on-color: #e6a23c"
+        @change="onStopReadyChange"
+      />
+      <!-- 闇�姹�2锛氭挙閿�璇偣鍙彿 / 鎾ら攢瀹屾垚锛堝潎鍥炲埌鍊欒瘖鍖猴級 -->
+      <el-button :disabled="undoFlag" type="warning" plain @click="undoCall">鎾ら攢鍙彿</el-button>
+      <el-button :disabled="undoFlag" type="warning" plain @click="undoFinish">鎾ら攢瀹屾垚</el-button>
     </el-container>
   </el-container>
 </template>
diff --git a/src/views/ecg/doctor/Routine.vue b/src/views/ecg/doctor/Routine.vue
index b0244a0..5b1db4c 100644
--- a/src/views/ecg/doctor/Routine.vue
+++ b/src/views/ecg/doctor/Routine.vue
@@ -9,7 +9,7 @@
 import QueuePanel from '@/views/ecg/doctor/components/QueuePanel.vue'
 import { DoctorApi, PatientStatisticVO, RoomBedVO, } from '@/api/ecg/doctor'
 import { QueueVO } from '@/api/ecg/queue'
-import { ElNotification } from 'element-plus'
+import { ElMessage, ElMessageBox, ElNotification } from 'element-plus'
 import RoutinePanel from '@/views/ecg/doctor/components/RoutinePanel.vue'
 import { useRoomStore } from '@/store/modules/room'
 
@@ -59,6 +59,96 @@
 const bedControlFlag = ref<boolean>(true)
 const finishFlag = ref<boolean>(true)
 const passFlag = ref<boolean>(true)
+
+// ==================== 闇�姹�3锛氬仠姝㈠�欒瘖寮�鍏� ====================
+// 璇箟锛氬紑鍚悗銆愬凡鏈夊�欒瘖鐥呬汉缁х画鍙彿锛屼絾涓嶅啀鏂板鍊欒瘖鐥呬汉銆戯紱鍏抽棴鍚庢仮澶嶃��
+// 涓庝笂闈㈢殑"鏆傚仠/鎭㈠"鏄�**涓や釜鐙珛姒傚康**锛氭殏鍋滀細鎶婂氨璇婁腑鎮h�呭己鍒跺畬鎴愩��
+// 骞舵妸鍊欒瘖鎮h�呰涪鍑哄伐浣嶏紱鏈紑鍏冲彧鎷︽埅"鏂板"锛屼笉鍔ㄥ凡鏈夋偅鑰呫��
+const stopReady = ref<boolean>(false)
+const stopReadyFlag = ref<boolean>(true) // 闃茶繛鐐�
+
+const loadStopReady = async () => {
+  try {
+    stopReady.value = await DoctorApi.getStopReady(roomBedVO)
+  } catch (e) {
+    // 鏌ヨ澶辫触涓嶆墦鏂疆璇紱淇濇寔涓婁竴娆$姸鎬�
+  } finally {
+    stopReadyFlag.value = false
+  }
+}
+
+const onStopReadyChange = async (val: boolean) => {
+  stopReadyFlag.value = true
+  try {
+    if (val) {
+      await DoctorApi.stopReady(roomBedVO)
+      ElMessage.success('宸插仠姝㈠�欒瘖锛氫笉鍐嶆帴鏀舵柊鐨勫�欒瘖鎮h�咃紝宸叉湁鎮h�呬粛鍙甯稿彨鍙�')
+    } else {
+      await DoctorApi.resumeReady(roomBedVO)
+      ElMessage.success('宸叉仮澶嶅�欒瘖锛氬紑濮嬫帴鏀舵柊鐨勫�欒瘖鎮h��')
+    }
+    await initLoad()
+  } catch (e) {
+    // 澶辫触鍥炴粴寮�鍏虫樉绀�
+    stopReady.value = !val
+  } finally {
+    stopReadyFlag.value = false
+  }
+}
+
+// ==================== 闇�姹�2锛氭挙閿�鍙彿 / 鎾ら攢妫�鏌ュ畬鎴� ====================
+const undoFlag = ref<boolean>(false)
+
+/** 鎾ら攢璇偣"鍙彿"锛氭妸褰撳墠灏辫瘖涓殑鎮h�呴��鍥炲�欒瘖鍖� */
+const undoCall = async () => {
+  try {
+    await ElMessageBox.confirm(
+      '纭畾瑕佹挙閿�鏈鍙彿鍚楋紵璇ユ偅鑰呭皢鍥炲埌鍊欒瘖鍖猴紝鍙噸鏂板彨鍙枫��',
+      '鎾ら攢鍙彿',
+      { type: 'warning', confirmButtonText: '纭畾鎾ら攢', cancelButtonText: '鍙栨秷' }
+    )
+  } catch {
+    return // 鐢ㄦ埛鍙栨秷
+  }
+  undoFlag.value = true
+  try {
+    const msg = await DoctorApi.undoCallPatient(roomBedVO)
+    ElMessage.success(msg || '宸叉挙閿�鍙彿')
+    await initLoad()
+  } finally {
+    undoFlag.value = false
+  }
+}
+
+/** 鎾ら攢"妫�鏌ュ畬鎴�"锛氭妸鏈�杩戜竴浣嶅凡瀹屾垚鎮h�呴��鍥炲�欒瘖鍖� */
+const undoFinish = async () => {
+  const last = await DoctorApi.lastFinishedPatient(roomBedVO)
+  if (!last || !last.patId) {
+    ElMessage.warning('鏈伐浣嶄粖鏃ユ殏鏃犲凡瀹屾垚鐨勬鏌ヨ褰�')
+    return
+  }
+  try {
+    await ElMessageBox.confirm(
+      `纭畾鎾ら攢銆�${last.patName || last.patId}銆嶇殑妫�鏌ュ畬鎴愬悧锛熻鎮h�呭皢鍥炲埌鍊欒瘖鍖恒�俙,
+      '鎾ら攢妫�鏌ュ畬鎴�',
+      { type: 'warning', confirmButtonText: '纭畾鎾ら攢', cancelButtonText: '鍙栨秷' }
+    )
+  } catch {
+    return // 鐢ㄦ埛鍙栨秷
+  }
+  undoFlag.value = true
+  try {
+    const msg = await DoctorApi.undoFinishPatient({
+      ...roomBedVO,
+      patId: last.patId,
+      checkType: last.bookCheckType
+    } as any)
+    ElMessage.success(msg || '宸叉挙閿�妫�鏌ュ畬鎴�')
+    await initLoad()
+  } finally {
+    undoFlag.value = false
+  }
+}
 
 const finishNextPatient = async () => {
   finishFlag.value = true
@@ -116,6 +206,8 @@
   const queueVO2 = await DoctorApi.bedDoctorGet(roomBedVO)
   if (queueVO2.status === 20) state.value = true
   else if (queueVO2.status === 30) state.value = false
+  // 闇�姹�3锛氬悓姝�"鍋滄鍊欒瘖"寮�鍏崇姸鎬侊紙鍏朵粬鍖荤敓/鍏朵粬缁堢鏀瑰姩鍚庢湰绔篃鑳界湅鍒帮級
+  await loadStopReady()
 }
 
 const bedControl = async () => {
@@ -245,6 +337,19 @@
       <el-button :disabled="bedControlFlag" type="primary" @click="bedControl">{{
         state ? '鏆傚仠' : '鎭㈠'
       }}</el-button>
+      <!-- 闇�姹�3锛氬仠姝㈠�欒瘖寮�鍏筹紙宸叉湁鍊欒瘖鐥呬汉缁х画鍙彿锛屼絾涓嶅啀鏂板鍊欒瘖鐥呬汉锛� -->
+      <el-switch
+        v-model="stopReady"
+        :disabled="stopReadyFlag"
+        active-text="鍋滄鍊欒瘖"
+        inactive-text="姝e父鎺ヨ瘖"
+        inline-prompt
+        style="margin-left: 12px; --el-switch-on-color: #e6a23c"
+        @change="onStopReadyChange"
+      />
+      <!-- 闇�姹�2锛氭挙閿�璇偣鍙彿 / 鎾ら攢妫�鏌ュ畬鎴愶紙鍧囧洖鍒板�欒瘖鍖猴級 -->
+      <el-button :disabled="undoFlag" type="warning" plain @click="undoCall">鎾ら攢鍙彿</el-button>
+      <el-button :disabled="undoFlag" type="warning" plain @click="undoFinish">鎾ら攢瀹屾垚</el-button>
     </el-container>
   </el-container>
 </template>
diff --git a/src/views/ecg/doctor/components/DevInstallPanel.vue b/src/views/ecg/doctor/components/DevInstallPanel.vue
index 80e8cba..cf4b4ae 100644
--- a/src/views/ecg/doctor/components/DevInstallPanel.vue
+++ b/src/views/ecg/doctor/components/DevInstallPanel.vue
@@ -15,9 +15,11 @@
           <el-input v-model="formData.patName" placeholder="璇疯緭鍏ユ偅鑰呭悕绉�" />
         </el-form-item>
         <el-form-item label="鎮h�呮弿杩�" prop="patDetails">
-          <dict-tag :type="DICT_TYPE.ECG_PAT_SOURCE" :value="formData.patDetails?.source || ''" />
-          {{ formData?.patDetails?.deptDesc }} {{ formData?.patDetails?.wardDesc }} {{ formData?.patDetails?.bedNo }}
+          <dict-tag :type="DICT_TYPE.ECG_PAT_SOURCE" :value="formData.patSrc ?? formData.patDetails?.source ?? ''" />
+          {{ formData.patWardDesc || formData?.patDetails?.wardDesc || '-' }} {{ formData.patBedNo || formData?.patDetails?.bedNo || '-' }}
         </el-form-item>
+        <!-- 闇�姹�1锛氭偅鑰呬俊鎭� 18 椤圭粺涓�灞曠ず锛堝悗绔凡浠庨绾﹀崟骞抽摵鍥炲~锛宻etPatient 宸茶祴鍊煎埌 formData锛� -->
+        <PatientInfoBlock :data="formData" check-type-field="checkType" :span="12" />
         <el-form-item label="瑁呮満鏃堕棿" prop="rentTime">
           <el-date-picker v-model="formData.rentTime" type="date" value-format="x" placeholder="閫夋嫨瑁呮満鏃堕棿" />
         </el-form-item>
@@ -33,10 +35,8 @@
           <el-input v-model="formData.remark" placeholder="璇疯緭鍏ュ娉�" />
         </el-form-item>
         <el-form-item label="澶氳�愯嵂" prop="tolerance">
-          <el-tag v-if="formData.tolerance == 0" type="info">鍚�</el-tag>
-          <el-tag v-else-if="formData.tolerance == 1" type="danger">鏄�</el-tag>
-          <!-- 鍙�夛細闃叉鏁版嵁寮傚父鏃剁殑鍏滃簳 -->
-          <el-tag v-else type="warning">鏈煡</el-tag>
+          <!-- 闇�姹�6锛氱粺涓�璧板瓧鍏� ecg_tolerance锛�0=鏃� 1=澶氳�� 2=澶氶噸鑰愯嵂锛夛紱NULL 鎸�"鏃�"鏄剧ず锛圦12锛� -->
+          <dict-tag :type="DICT_TYPE.ECG_TOLERANCE" :value="formData.tolerance ?? 0" />
         </el-form-item>
       </el-col>
     </el-row>
@@ -107,6 +107,8 @@
 import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
 import { tranlateDevState } from "../../../../utils/statusFormatter";
 import { getCheckTypeName } from "../../../../utils/checkTypeFormatter";
+// 闇�姹�1锛氭偅鑰呬俊鎭� 18 椤圭粺涓�灞曠ず鍧�
+import PatientInfoBlock from "@/views/ecg/doctor/components/PatientInfoBlock.vue";
 
 /** 璁惧瑁呮満 琛ㄥ崟 */
 defineComponent({ name: 'DevInstallPanel' })
@@ -166,6 +168,23 @@
   formData.value.patName = queueVO?.patName
   formData.value.checkType = queueVO?.bookCheckType
   formData.value.tolerance = queueVO?.tolerance // 澶氳�愯嵂锛屽悗绔粠棰勭害鍗曡ˉ榻�
+  // 闇�姹�1锛氫互涓嬪钩閾哄瓧娈电敱鍚庣浠庨绾﹀崟鍥炲~鍒� QueueRespVO锛�
+  // 蹇呴』鏄惧紡璧嬪�肩粰 formData锛屽惁鍒欐ā鏉块噷璇讳笉鍒般��
+  formData.value.patGender = queueVO?.patGender
+  formData.value.patBirthday = queueVO?.patBirthday
+  formData.value.registerDate = queueVO?.registerDate
+  formData.value.doctor = queueVO?.doctor
+  formData.value.doctorTime = queueVO?.doctorTime
+  formData.value.patSrc = queueVO?.patSrc
+  formData.value.patMobile = queueVO?.patMobile
+  formData.value.patPhone = queueVO?.patPhone
+  formData.value.patWardDesc = queueVO?.patWardDesc
+  formData.value.patBedNo = queueVO?.patBedNo
+  formData.value.medicalCard = queueVO?.medicalCard
+  formData.value.outpatientNo = queueVO?.outpatientNo
+    // 闇�姹�1锛氬尰鍢卞彿锛堟鍓� 3 涓潰鏉块兘閬楁紡浜嗚瀛楁鐨勮祴鍊硷紝瀵艰嚧 PatientInfoBlock 鎭掓樉绀� '-'锛�
+    formData.value.doctorAdviceNo = queueVO?.doctorAdviceNo
+  formData.value.patIdentityId = queueVO?.patIdentityId
   getReadyRentInfo(formData.value)    // 鑾峰彇棰嗙敤淇℃伅
   copyBarcode()
 }
@@ -213,6 +232,25 @@
     detachment: undefined,
     remark: undefined,
     checkType: undefined,
+    // 闇�姹�1锛歅atientInfoBlock 渚濊禆鐨勫钩閾哄瓧娈碉紙鐢� setPatient 浠� QueueVO 璧嬪�硷級
+    applyNo: undefined,
+    episodeId: undefined,
+    patGender: undefined,
+    patBirthday: undefined,
+    registerDate: undefined,
+    doctor: undefined,
+    doctorTime: undefined,
+    patSrc: undefined,
+    patMobile: undefined,
+    patPhone: undefined,
+    patWardDesc: undefined,
+    patBedNo: undefined,
+    medicalCard: undefined,
+    doctorAdviceNo: undefined,
+    outpatientNo: undefined,
+    patIdentityId: undefined,
+    status: undefined,
+    seqNum: undefined,
   }
   formRef.value?.resetFields()
   devInfo.value = {
diff --git a/src/views/ecg/doctor/components/DevReadyPanel.vue b/src/views/ecg/doctor/components/DevReadyPanel.vue
index a568504..831a7fb 100644
--- a/src/views/ecg/doctor/components/DevReadyPanel.vue
+++ b/src/views/ecg/doctor/components/DevReadyPanel.vue
@@ -29,11 +29,13 @@
         <el-input v-model="formData.patName" placeholder="璇疯緭鍏ユ偅鑰呭悕绉�" />
       </el-form-item>
      </el-col>
+     <!-- 闇�姹�1锛氭偅鑰呬俊鎭� 18 椤圭粺涓�灞曠ず锛堝悗绔凡浠庨绾﹀崟骞抽摵鍥炲~锛宻etPatient 宸茶祴鍊煎埌 formData锛� -->
+     <PatientInfoBlock :data="formData" check-type-field="checkType" :span="12" />
       <el-col :span="12">
   
       <el-form-item label="鎮h�呮弿杩�" prop="patDeptDesc">
-        <dict-tag v-if="formData.patDetails?.source" :type="DICT_TYPE.ECG_PAT_SOURCE" :value="formData.patDetails?.source" />
-        {{formData?.patDetails?.deptDesc}} {{formData?.patDetails?.wardDesc}} {{formData?.patDetails?.bedNo}}
+        <dict-tag v-if="formData.patSrc ?? formData.patDetails?.source" :type="DICT_TYPE.ECG_PAT_SOURCE" :value="formData.patSrc ?? formData.patDetails?.source" />
+        {{ formData.patWardDesc || formData?.patDetails?.wardDesc || '-' }} {{ formData.patBedNo || formData?.patDetails?.bedNo || '-' }}
       </el-form-item>
            </el-col>
       <el-col :span="12">
@@ -58,8 +60,8 @@
            </el-col>
       <el-col :span="12">
        <el-form-item label="澶氳�愯嵂" prop="tolerance">
-         <el-tag type="info" v-if="formData.tolerance == 0">鍚�</el-tag>
-        <el-tag type="danger" v-else>鏄�</el-tag>
+         <!-- 闇�姹�6锛氱粺涓�璧板瓧鍏� ecg_tolerance锛�0=鏃� 1=澶氳�� 2=澶氶噸鑰愯嵂锛夛紱NULL 鎸�"鏃�"鏄剧ず锛圦12锛� -->
+         <dict-tag :type="DICT_TYPE.ECG_TOLERANCE" :value="formData.tolerance ?? 0" />
         </el-form-item>
              </el-col>
       </el-row>
@@ -174,6 +176,8 @@
 import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
 import {tranlateDevState} from "@/utils/statusFormatter";
 import {getCheckTypeName, needAutoFeeConfirm} from "../../../../utils/checkTypeFormatter";
+// 闇�姹�1锛氭偅鑰呬俊鎭� 18 椤圭粺涓�灞曠ず鍧�
+import PatientInfoBlock from "@/views/ecg/doctor/components/PatientInfoBlock.vue";
 
 /** 璁惧棰嗙敤 琛ㄥ崟 */
 defineComponent({ name: 'DevReadyPanel' })
@@ -312,6 +316,26 @@
     remark: undefined,
     patDetails: undefined,
     paid: undefined,
+    // 闇�姹�1锛歅atientInfoBlock 渚濊禆鐨勫钩閾哄瓧娈碉紝鍏堝垵濮嬪寲涓� undefined锛�
+    // 闅忓悗鐢� setPatient 浠� QueueVO 璧嬪�硷紙涓嶅垵濮嬪寲浼氳涓嶅埌灞炴�э級
+    applyNo: undefined,
+    episodeId: undefined,
+    patGender: undefined,
+    patBirthday: undefined,
+    registerDate: undefined,
+    doctor: undefined,
+    doctorTime: undefined,
+    patSrc: undefined,
+    patMobile: undefined,
+    patPhone: undefined,
+    patWardDesc: undefined,
+    patBedNo: undefined,
+    medicalCard: undefined,
+    doctorAdviceNo: undefined,
+    outpatientNo: undefined,
+    patIdentityId: undefined,
+    status: undefined,
+    seqNum: undefined,
   }
   formRef.value?.resetFields()
 
@@ -331,6 +355,23 @@
   formData.value.patName = queueVO?.patName
   formData.value.checkType = queueVO?.bookCheckType
   formData.value.tolerance = queueVO?.tolerance // 澶氳�愯嵂锛屽悗绔粠棰勭害鍗曡ˉ榻�
+  // 闇�姹�1锛氫互涓嬪钩閾哄瓧娈电敱鍚庣浠庨绾﹀崟鍥炲~鍒� QueueRespVO锛�
+  // 蹇呴』鏄惧紡璧嬪�肩粰 formData锛屽惁鍒欐ā鏉块噷璇讳笉鍒帮紙鍘熷厛鍙祴鍊间簡涓婇潰 6 涓級銆�
+  formData.value.patGender = queueVO?.patGender
+  formData.value.patBirthday = queueVO?.patBirthday
+  formData.value.registerDate = queueVO?.registerDate
+  formData.value.doctor = queueVO?.doctor
+  formData.value.doctorTime = queueVO?.doctorTime
+  formData.value.patSrc = queueVO?.patSrc
+  formData.value.patMobile = queueVO?.patMobile
+  formData.value.patPhone = queueVO?.patPhone
+  formData.value.patWardDesc = queueVO?.patWardDesc
+  formData.value.patBedNo = queueVO?.patBedNo
+  formData.value.medicalCard = queueVO?.medicalCard
+  formData.value.outpatientNo = queueVO?.outpatientNo
+    // 闇�姹�1锛氬尰鍢卞彿锛堟鍓� 3 涓潰鏉块兘閬楁紡浜嗚瀛楁鐨勮祴鍊硷紝瀵艰嚧 PatientInfoBlock 鎭掓樉绀� '-'锛�
+    formData.value.doctorAdviceNo = queueVO?.doctorAdviceNo
+  formData.value.patIdentityId = queueVO?.patIdentityId
   getFreeRentInfo(formData.value)  // 寰呮鏌ョ殑淇℃伅  @ dev_rent 琛�
   copyBarcode()
 }
diff --git a/src/views/ecg/doctor/components/PatientInfoBlock.vue b/src/views/ecg/doctor/components/PatientInfoBlock.vue
new file mode 100644
index 0000000..f8713d4
--- /dev/null
+++ b/src/views/ecg/doctor/components/PatientInfoBlock.vue
@@ -0,0 +1,210 @@
+<!--
+  鎮h�呬俊鎭睍绀哄潡锛堥渶姹�1锛�18 椤圭粺涓�灞曠ず锛�
+
+  鑳屾櫙锛�
+    闇�姹傝姹傘�屾祦姘村彿銆佹帓闃熷簭鍙枫�佸鍚嶃�佹�у埆銆佸嚭鐢熸棩鏈熴�佸勾榫勩�侀」鐩�佺梾鍖恒�佺梾搴婂彿銆�
+    鐧昏鏃堕棿銆佺姸鎬併�佹偅鑰呯數璇濄�佸紑鍗曟棩鏈熴�佽窛浠婂ぉ鏁般�佹潵婧愩�侀棬璇婂彿銆佸尰鍢卞彿銆佸紑鍗曞尰甯堛��
+    鍦�**姣忎釜鐣岄潰**閮芥湁銆�
+
+    锛堝師濮嬮渶姹傚啓鐨勬槸銆屽氨璇婂崱鍙枫�嶏紱鍥� HIS 鍦ㄥ崱鍙锋Ы浣嶄紶绌恒�乵edical_card 鍏ㄥ簱涓虹┖锛�
+      璇ヤ綅缃疄闄呭睍绀� outpatient_no锛岀粡纭鏍囩鏀逛负銆岄棬璇婂彿銆嶁�斺�旇瑙併�婇儴缃叉竻鍗曘��5.1銆傦級
+
+  涓轰粈涔堝仛鎴愮粍浠讹細
+    鏈� 10+ 涓晫闈㈤渶瑕佸悓涓�濂楀瓧娈点�傝嫢鍚勮嚜澶嶅埗绮樿创锛屼細鍑虹幇
+      路 鍙e緞涓嶄竴鑷达紙鏌愪釜椤甸潰鐢� createTime 褰撳紑鍗曟棩鏈燂級
+      路 鏀逛竴澶勬紡涓�澶�
+    鍥犳缁熶竴鍒拌繖閲岋紱鍚勯〉闈㈠彧闇�浼犳暟鎹璞°��
+
+  鏁版嵁鍏煎鎬э細
+    涓嶅悓椤甸潰鐨勬暟鎹舰鎬佺暐鏈夊樊寮傦紝鏈粍浠舵寜浠ヤ笅浼樺厛绾у彇鍊硷細
+      1) 鍚庣骞抽摵瀛楁锛圦ueueRespVO / AppointmentRespVO / DevRentRespVO 鏂板鐨� patWardDesc 绛夛級
+      2) patDetails JSON 蹇収锛堟棫鏁版嵁鍙兘鍙湪杩欓噷鏈夛級
+      3) '-' 鍗犱綅
+-->
+<script setup lang="ts">
+import { computed } from 'vue'
+import { DICT_TYPE } from '@/utils/dict'
+import {
+  formatAge,
+  formatDaysFromOrder,
+  formatDateOnly,
+  formatDateTime,
+  resolveCardNo
+} from '@/utils/patientInfo'
+import { getCheckTypeName } from '@/utils/checkTypeFormatter'
+
+const props = defineProps<{
+  /** 鎮h��/鎺掗槦/棰勭害/绉熻祦 鏁版嵁瀵硅薄锛堝舰鎬佸吋瀹癸紝瑙佹枃浠跺ご璇存槑锛� */
+  data: any
+  /** 妫�鏌ラ」鐩瓧娈靛悕锛氶槦鍒楃敤 bookCheckType锛岀璧佺敤 checkType */
+  checkTypeField?: string
+  /** 鐘舵�佸瓧鍏革細闃熷垪鐢� ecg_queue_status锛岄绾﹀崟鐢� ecg_status */
+  statusDict?: string
+  /** 鏄惁鏄剧ず鎺掗槦搴忓彿锛堥绾﹁褰曠瓑鏃犳瀛楁鐨勯〉闈㈠彲鍏抽棴锛� */
+  showSeqNum?: boolean
+  /**
+   * 鏄惁鏄剧ず鍖诲槺鍙凤紝榛樿 **true**銆�
+   *
+   * 鍘嗗彶璇存槑锛氭棭鏈熸帓鏌ュ緱鍑�"HIS 鎶ユ枃涓笉瀛樺湪鍖诲槺鍙�"鐨勭粨璁猴紝鏁呭綋鏃堕粯璁ゅ叧闂紝
+   * 浠ュ厤鐢ㄧ敵璇峰彿鍐掑厖銆�**璇ョ粨璁哄凡琚帹缈�** 鈥斺�� HIS銆婁氦浜掓湇鍔¢�氱敤鎺ュ彛鏂囨。銆�
+   * 6.1/6.4/6.5 鏄庣‘ `observationRequest.id.item[root=2.16.156.10011.1.28]`
+   * 鍗炽�屽尰鍢盜D/鍖诲槺鍙枫�嶏紝涓斿疄娴� S0201ECG 220 鏉°�丼0202ECG 29 鏉″潎鎼哄甫璇ュ�笺��
+   * 鍚庣宸叉柊澧� `doctorAdviceNo` 瀛楁骞跺湪瑙f瀽鏃堕噰闆嗭紝鏁呮澶勯粯璁ゆ樉绀恒��
+   *
+   * 娉ㄦ剰璇ヨ妭鐐瑰湪瑙勮寖涓�**闈炲繀椤婚」**锛屽巻鍙叉暟鎹紙鏂板鍒椾箣鍓嶉噰闆嗙殑锛変负绌� 鈫�
+   * 鏄剧ず `-`锛屽睘棰勬湡銆�
+   */
+  showAdviceNo?: boolean
+  /** 姣忓垪鏍呮牸瀹藉害锛堥粯璁� 6 = 涓�琛� 4 涓級 */
+  span?: number
+}>()
+
+const d = computed(() => props.data || {})
+const pd = computed(() => d.value.patDetails || {})
+const colSpan = computed(() => props.span ?? 6)
+// 鍖诲槺鍙烽粯璁ゆ樉绀猴紙璇﹁ props 璇存槑锛夛紱浠呭湪鏄惧紡浼� false 鏃堕殣钘�
+const showAdvice = computed(() => props.showAdviceNo !== false)
+const checkField = computed(() => props.checkTypeField ?? 'bookCheckType')
+
+/** 鍙栫涓�涓湁鍊肩殑鍊欓�� */
+function pick(...vals: any[]): any {
+  for (const v of vals) {
+    if (v !== undefined && v !== null && v !== '') return v
+  }
+  return undefined
+}
+
+const phone = computed(() =>
+  pick(d.value.patMobile, d.value.patPhone, pd.value.mobile) ?? '-'
+)
+const ward = computed(() => pick(d.value.patWardDesc, pd.value.wardDesc) ?? '-')
+// 娉ㄦ剰锛歞.bedNo 鍦� queue 閲屾槸銆愯瘖鐤楀簥/宸ヤ綅鍙枫�戯紝鐪熸鐨勭梾搴婂彿鏄� patBedNo / patDetails.bedNo
+const patBed = computed(() => pick(d.value.patBedNo, pd.value.bedNo) ?? '-')
+
+const cardNo = computed(() => resolveCardNo(d.value))
+const source = computed(() => pick(d.value.patSrc, pd.value.source))
+const checkType = computed(() => d.value[checkField.value])
+</script>
+
+<template>
+  <el-row :gutter="20">
+    <el-col :span="colSpan">
+      <el-form-item label="灏辫瘖娴佹按鍙�">
+        {{ d.episodeId || '-' }}
+      </el-form-item>
+    </el-col>
+    <el-col v-if="showSeqNum" :span="colSpan">
+      <el-form-item label="鎺掗槦搴忓彿">
+        {{ pick(d.seqNum, d.bookSeqNum) ?? '-' }}
+      </el-form-item>
+    </el-col>
+    <el-col :span="colSpan">
+      <el-form-item label="鐢宠缂栧彿">
+        {{ d.applyNo || '-' }}
+      </el-form-item>
+    </el-col>
+    <el-col :span="colSpan">
+      <!-- 鏍囩鐢便�屽氨璇婂崱鍙枫�嶆敼涓恒�岄棬璇婂彿銆嶏紙缁忕‘璁わ紝璇﹁銆婇儴缃叉竻鍗曘��5.1锛夛細
+           HIS 鍦ㄥ崱鍙锋Ы浣嶄紶绌猴紝medical_card 鍏ㄥ簱 159,116 琛屾棤涓�闈炵┖锛�
+           璇ヤ綅缃疄闄呭睍绀� outpatient_no銆俢ardNo.from 鏍囨敞鍊肩殑鐪熷疄鏉ユ簮锛�
+           鐢ㄤ簬鍖哄垎娣峰湪璇ュ瓧娈甸噷鐨勮韩浠借瘉鍙� / 浣忛櫌鍙枫�� -->
+      <el-form-item label="闂ㄨ瘖鍙�">
+        <span>{{ cardNo.value }}</span>
+        <el-tag v-if="cardNo.from" size="small" type="info" effect="plain" class="ml-1">
+          {{ cardNo.from }}
+        </el-tag>
+      </el-form-item>
+    </el-col>
+
+    <el-col :span="colSpan">
+      <el-form-item label="濮撳悕">
+        {{ d.patName || '-' }}
+      </el-form-item>
+    </el-col>
+    <el-col :span="colSpan">
+      <el-form-item label="鎬у埆">
+        <!-- 1 鐢� / 2 濂筹紱0 鎴栫己澶憋紙HIS 鏈彁渚涳紝瀹炴祴搴撲腑鏈� 2123 琛� = 0锛夋樉绀�"鏈煡"銆�
+             娉ㄦ剰涓嶈兘鐩存帴鎶� 0 浜ょ粰 dict-tag 鈥斺�� 瀛楀吀閲屾病鏈� 0 杩欎竴椤癸紝浼氭覆鏌撴垚绌虹櫧銆� -->
+        <dict-tag v-if="d.patGender === 1 || d.patGender === 2 || d.patGender === '1' || d.patGender === '2'"
+                  :type="DICT_TYPE.SYSTEM_USER_SEX" :value="d.patGender" />
+        <span v-else>鏈煡</span>
+      </el-form-item>
+    </el-col>
+    <el-col :span="colSpan">
+      <el-form-item label="鍑虹敓鏃ユ湡">
+        {{ formatDateOnly(d.patBirthday) || '-' }}
+      </el-form-item>
+    </el-col>
+    <el-col :span="colSpan">
+      <el-form-item label="骞撮緞">
+        {{ formatAge(d.patBirthday) || '-' }}
+      </el-form-item>
+    </el-col>
+
+    <el-col :span="colSpan">
+      <el-form-item label="椤圭洰">
+        {{ checkType ? getCheckTypeName(checkType) : '-' }}
+      </el-form-item>
+    </el-col>
+    <el-col :span="colSpan">
+      <el-form-item label="鏉ユ簮">
+        <dict-tag v-if="source !== undefined" :type="DICT_TYPE.ECG_PAT_SOURCE" :value="source" />
+        <span v-else>-</span>
+      </el-form-item>
+    </el-col>
+    <el-col :span="colSpan">
+      <el-form-item label="鐥呭尯">
+        {{ ward }}
+      </el-form-item>
+    </el-col>
+    <el-col :span="colSpan">
+      <el-form-item label="鐥呭簥鍙�">
+        {{ patBed }}
+      </el-form-item>
+    </el-col>
+
+    <el-col :span="colSpan">
+      <el-form-item label="鎮h�呯數璇�">
+        {{ phone }}
+      </el-form-item>
+    </el-col>
+    <el-col :span="colSpan">
+      <el-form-item label="鐧昏鏃堕棿">
+        {{ formatDateTime(d.registerDate) || '-' }}
+      </el-form-item>
+    </el-col>
+    <el-col :span="colSpan">
+      <el-form-item label="寮�鍗曟棩鏈�">
+        {{ formatDateTime(d.doctorTime) || '-' }}
+      </el-form-item>
+    </el-col>
+    <el-col :span="colSpan">
+      <el-form-item label="璺濅粖澶╂暟">
+        {{ formatDaysFromOrder(d.doctorTime) || '-' }}
+      </el-form-item>
+    </el-col>
+
+    <el-col :span="colSpan">
+      <el-form-item label="寮�鍗曞尰甯�">
+        {{ d.doctor || '-' }}
+      </el-form-item>
+    </el-col>
+    <el-col :span="colSpan">
+      <el-form-item label="鐘舵��">
+        <dict-tag v-if="d.status !== undefined && d.status !== null && statusDict"
+                  :type="statusDict" :value="d.status" />
+        <span v-else>-</span>
+      </el-form-item>
+    </el-col>
+    <el-col :span="colSpan">
+      <el-form-item label="澶氳��">
+        <dict-tag :type="DICT_TYPE.ECG_TOLERANCE" :value="d.tolerance ?? 0" />
+      </el-form-item>
+    </el-col>
+    <el-col v-if="showAdvice" :span="colSpan">
+      <el-form-item label="鍖诲槺鍙�">
+        {{ d.doctorAdviceNo || '-' }}
+      </el-form-item>
+    </el-col>
+  </el-row>
+</template>
diff --git a/src/views/ecg/doctor/components/RoutinePanel.vue b/src/views/ecg/doctor/components/RoutinePanel.vue
index 32526e4..bfebfcd 100644
--- a/src/views/ecg/doctor/components/RoutinePanel.vue
+++ b/src/views/ecg/doctor/components/RoutinePanel.vue
@@ -24,7 +24,10 @@
 
       <el-col :span="6">
         <el-form-item label="鑱旂郴鐢佃瘽" prop="episodeId">
-          {{ formData?.patDetails?.mobile }}
+          <!-- 淇锛氬師璇� `patDetails.mobile`锛坬ueue 琛ㄧ殑 JSON 蹇収锛屽彧鍚� source/mobile/wardDesc/bedNo 鍥涘瓧娈碉級銆�
+               鑰� setPatient 宸叉妸鍚庣浠� appointment 鍥炲~鐨�**骞抽摵瀛楁** `patMobile` 璧嬭繘 formData锛�
+               鏁呭簲浠ュ钩閾哄瓧娈典紭鍏堬紝patDetails 浠呬綔鏃ф暟鎹洖閫�銆� -->
+          {{ formData.patMobile || formData?.patDetails?.mobile || '-' }}
         </el-form-item>
       </el-col>
     </el-row>
@@ -57,9 +60,14 @@
       </el-col>
       <el-col :span="18">
         <el-form-item label="绉戝鐥呭尯" prop="patDetails">
-          <dict-tag v-if="formData.patDetails?.source" :type="DICT_TYPE.ECG_PAT_SOURCE"
-            :value="formData.patDetails?.source" />
-          {{ formData?.patDetails?.deptDesc }}-{{ formData?.patDetails?.wardDesc }}-{{ formData?.patDetails?.bedNo }}
+          <!-- 淇锛氭潵婧愪笌鐥呭尯/搴婂彿鍘熻 `patDetails.*`锛坬ueue 琛ㄧ殑 JSON 蹇収锛屽彲鑳芥粸鍚庝笖甯哥己鐥呭尯锛夛紝
+               鏀逛负**骞抽摵瀛楁浼樺厛**锛堝悗绔凡浠� appointment 鍥炲~ patSrc/patWardDesc/patBedNo锛夛紝
+               patDetails 浠呬綔鏃ф暟鎹洖閫�銆� -->
+          <dict-tag v-if="formData.patSrc ?? formData.patDetails?.source"
+                    :type="DICT_TYPE.ECG_PAT_SOURCE"
+                    :value="formData.patSrc ?? formData.patDetails?.source" />
+          {{ formData.patWardDesc || formData?.patDetails?.wardDesc || '-' }}
+          - {{ formData.patBedNo || formData?.patDetails?.bedNo || '-' }}
         </el-form-item></el-col>
 
 
@@ -77,7 +85,13 @@
       </el-col>
       <el-col :span="6">
         <el-form-item label="鍖诲槺鍙�">
-          {{ formData.applyNo }}
+          <!-- 淇锛氭澶勫師鍏堢粦瀹氱殑鏄� `formData.applyNo`锛堢敵璇峰崟鍙凤級锛�
+               涓庛�屽尰鍢卞彿銆嶆槸**涓や釜涓嶅悓鐨勬爣璇�**锛�
+                 鐢宠鍗曞彿 apply_no           = HIS root 2.16.156.10011.1.24锛屼緥 2126091700011
+                 鍖诲槺鍙�   doctor_advice_no   = HIS root 2.16.156.10011.1.28锛屼緥 112663505
+               鍘熷啓娉曟槸鎶婄敵璇峰崟鍙峰啋鍏呮垚鍖诲槺鍙凤紝灞炰簬閿欒灞曠ず銆�
+               鐜版敼涓鸿鍚庣鏂伴噰闆嗙殑 doctorAdviceNo锛堣鑺傜偣瑙勮寖涓潪蹇呴』椤癸紝鍘嗗彶鏁版嵁涓虹┖ 鈫� 鏄剧ず '-'锛夈�� -->
+          {{ formData.doctorAdviceNo || '-' }}
         </el-form-item>
       </el-col><el-col :span="6">
         <el-form-item label="鐧昏鏃堕棿">
@@ -85,6 +99,21 @@
         </el-form-item>
       </el-col>
 
+    </el-row>
+    <!-- 闇�姹�1锛氳ˉ榻愭湰闈㈡澘鍘熷厛缂哄け鐨勪袱椤癸紙鎺掗槦搴忓彿銆佺姸鎬侊級锛屼娇 18 椤归綈鍏� -->
+    <el-row>
+      <el-col :span="6">
+        <el-form-item label="鎺掗槦搴忓彿">
+          {{ formData?.seqNum ?? formData?.bookSeqNum ?? '-' }}
+        </el-form-item>
+      </el-col>
+      <el-col :span="6">
+        <el-form-item label="鐘舵��">
+          <dict-tag v-if="formData?.status !== undefined && formData?.status !== null"
+                    :type="DICT_TYPE.ECG_QUEUE_STATUS" :value="formData.status" />
+          <span v-else>-</span>
+        </el-form-item>
+      </el-col>
     </el-row>
     <el-row>
       <el-col :span="6">
@@ -99,9 +128,9 @@
       </el-col>
       <el-col :span="6">
         <el-form-item label="澶氳�愯嵂" prop="tolerance">
-          <el-tag v-if="formData.tolerance == 0" type="info">鍚�</el-tag>
-          <el-tag v-else-if="formData.tolerance == 1" type="danger">鏄�</el-tag>
-          <el-tag v-else type="warning">鏈煡</el-tag>
+          <!-- 闇�姹�6锛氱粺涓�璧板瓧鍏� ecg_tolerance锛�0=鏃� 1=澶氳�� 2=澶氶噸鑰愯嵂锛夛紱
+               NULL 鎸�"鏃�"鏄剧ず锛圦12锛夈�傚師鍏堢‖缂栫爜"鍚�/鏄�/鏈煡"涓夊垎鏀紝涓庡瓧鍏搁噸澶嶄笖鏂囨涓嶇銆� -->
+          <dict-tag :type="DICT_TYPE.ECG_TOLERANCE" :value="formData.tolerance ?? 0" />
         </el-form-item>
       </el-col>
       <el-col :span="6">
@@ -212,12 +241,26 @@
   formData.value.checkType = queueVO?.bookCheckType
   // 浠ヤ笅瀛楁鐢卞悗绔粠棰勭害鍗曡ˉ榻愶紙queue 琛ㄤ笉瀛橈級锛岀敤浜庡尰鐢熺灞曠ず
   formData.value.patGender = queueVO?.patGender
-  formData.value.patGender = queueVO?.patGender
   formData.value.tolerance = queueVO?.tolerance
   formData.value.patBirthday = queueVO?.patBirthday
   formData.value.registerDate = queueVO?.registerDate
   formData.value.doctor = queueVO?.doctor
   formData.value.doctorTime = queueVO?.doctorTime
+  // 闇�姹�1锛氳ˉ榻愭帓闃熷簭鍙� / 鐘舵�� / 鐥呭尯 / 搴婂彿 / 鐢佃瘽 / 鏉ユ簮 / 闂ㄨ瘖鍙�
+  // 杩欎簺骞抽摵瀛楁鐢卞悗绔� QueueServiceImpl#fillAppointmentInfo 鍥炲~锛�
+  // 鍘熷厛杩欓噷娌℃湁璧嬪�硷紝瀵艰嚧妯℃澘閲岃涓嶅埌锛堟樉绀轰负绌猴級銆�
+  formData.value.seqNum = queueVO?.seqNum
+  formData.value.status = queueVO?.status
+  formData.value.patSrc = queueVO?.patSrc
+  formData.value.patMobile = queueVO?.patMobile
+  formData.value.patPhone = queueVO?.patPhone
+  formData.value.patWardDesc = queueVO?.patWardDesc
+  formData.value.patBedNo = queueVO?.patBedNo
+  formData.value.medicalCard = queueVO?.medicalCard
+  formData.value.outpatientNo = queueVO?.outpatientNo
+    // 闇�姹�1锛氬尰鍢卞彿锛堟鍓� 3 涓潰鏉块兘閬楁紡浜嗚瀛楁鐨勮祴鍊硷紝瀵艰嚧 PatientInfoBlock 鎭掓樉绀� '-'锛�
+    formData.value.doctorAdviceNo = queueVO?.doctorAdviceNo
+  formData.value.patIdentityId = queueVO?.patIdentityId
   getFreeRentInfo(formData.value)
   copyBarcode()
 }
@@ -336,6 +379,7 @@
     remark: undefined,
     patDetails: undefined,
     paid: undefined,
+    doctorAdviceNo: undefined,
     roomId: props.room.roomId,
     bedNo: props.room.bedNo
   }
diff --git a/src/views/ecg/doctor/index.vue b/src/views/ecg/doctor/index.vue
index 0db67bd..ade5683 100644
--- a/src/views/ecg/doctor/index.vue
+++ b/src/views/ecg/doctor/index.vue
@@ -10,7 +10,7 @@
 import QueuePanel from "@/views/ecg/doctor/components/QueuePanel.vue";
 import {DoctorApi, PatientStatisticVO, RoomBedVO} from '@/api/ecg/doctor';
 import {QueueVO} from "@/api/ecg/queue";
-import {ElNotification} from "element-plus";
+import {ElMessage, ElMessageBox, ElNotification} from "element-plus";
 import DevReadyPanel from "@/views/ecg/doctor/components/DevReadyPanel.vue";
 import {useRoomStore} from "@/store/modules/room";
 
@@ -71,6 +71,91 @@
   }
 }
 
+// ==================== 闇�姹�3锛氬仠姝㈠�欒瘖寮�鍏� ====================
+// 寮�鍚悗銆愬凡鏈夊�欒瘖鐥呬汉缁х画鍙彿锛屼絾涓嶅啀鏂板鍊欒瘖鐥呬汉銆戯紱鍏抽棴鍚庢仮澶嶃��
+const stopReady = ref<boolean>(false)
+const stopReadyFlag = ref<boolean>(true)
+
+const loadStopReady = async () => {
+  try {
+    stopReady.value = await DoctorApi.getStopReady(roomBedVO)
+  } catch (e) {
+    // 鏌ヨ澶辫触涓嶆墦鏂疆璇�
+  } finally {
+    stopReadyFlag.value = false
+  }
+}
+
+const onStopReadyChange = async (val: boolean) => {
+  stopReadyFlag.value = true
+  try {
+    if (val) {
+      await DoctorApi.stopReady(roomBedVO)
+      ElMessage.success('宸插仠姝㈠�欒瘖锛氫笉鍐嶆帴鏀舵柊鐨勫�欒瘖鎮h�咃紝宸叉湁鎮h�呬粛鍙甯稿彨鍙�')
+    } else {
+      await DoctorApi.resumeReady(roomBedVO)
+      ElMessage.success('宸叉仮澶嶅�欒瘖锛氬紑濮嬫帴鏀舵柊鐨勫�欒瘖鎮h��')
+    }
+    await initLoad()
+  } catch (e) {
+    stopReady.value = !val
+  } finally {
+    stopReadyFlag.value = false
+  }
+}
+
+// ==================== 闇�姹�2锛氭挙閿�鍙彿 / 鎾ら攢妫�鏌ュ畬鎴� ====================
+const undoFlag = ref<boolean>(false)
+
+const undoCall = async () => {
+  try {
+    await ElMessageBox.confirm(
+      '纭畾瑕佹挙閿�鏈鍙彿鍚楋紵璇ユ偅鑰呭皢鍥炲埌鍊欒瘖鍖猴紝鍙噸鏂板彨鍙枫��',
+      '鎾ら攢鍙彿',
+      { type: 'warning', confirmButtonText: '纭畾鎾ら攢', cancelButtonText: '鍙栨秷' }
+    )
+  } catch {
+    return
+  }
+  undoFlag.value = true
+  try {
+    const msg = await DoctorApi.undoCallPatient(roomBedVO)
+    ElMessage.success(msg || '宸叉挙閿�鍙彿')
+    await initLoad()
+  } finally {
+    undoFlag.value = false
+  }
+}
+
+const undoFinish = async () => {
+  const last = await DoctorApi.lastFinishedPatient(roomBedVO)
+  if (!last || !last.patId) {
+    ElMessage.warning('鏈伐浣嶄粖鏃ユ殏鏃犲凡瀹屾垚鐨勬鏌ヨ褰�')
+    return
+  }
+  try {
+    await ElMessageBox.confirm(
+      `纭畾鎾ら攢銆�${last.patName || last.patId}銆嶇殑妫�鏌ュ畬鎴愬悧锛熻鎮h�呭皢鍥炲埌鍊欒瘖鍖恒�俙,
+      '鎾ら攢妫�鏌ュ畬鎴�',
+      { type: 'warning', confirmButtonText: '纭畾鎾ら攢', cancelButtonText: '鍙栨秷' }
+    )
+  } catch {
+    return
+  }
+  undoFlag.value = true
+  try {
+    const msg = await DoctorApi.undoFinishPatient({
+      ...roomBedVO,
+      patId: last.patId,
+      checkType: last.bookCheckType
+    } as any)
+    ElMessage.success(msg || '宸叉挙閿�妫�鏌ュ畬鎴�')
+    await initLoad()
+  } finally {
+    undoFlag.value = false
+  }
+}
+
 const callAgain = async () => {
   await DoctorApi.callPatientAgain(roomBedVO)
 }
@@ -103,6 +188,8 @@
     state.value = true
   else if (queueVO2.status === 30)  // 宸ヤ綅鐘舵�� 鏆傚仠
     state.value = false
+  // 闇�姹�3锛氬悓姝�"鍋滄鍊欒瘖"寮�鍏崇姸鎬�
+  await loadStopReady()
 }
 
 const bedControl = async () => {
@@ -201,6 +288,19 @@
       <el-button :disabled="passFlag" type="primary" @click="passNextPatient">杩囧彿</el-button>
       <el-button  type="primary" @click="callAgain">閲嶅彨</el-button>
       <el-button :disabled="bedControlFlag" type="primary" @click="bedControl">{{state?'鏆傚仠':'鎭㈠'}}</el-button>
+      <!-- 闇�姹�3锛氬仠姝㈠�欒瘖寮�鍏筹紙宸叉湁鍊欒瘖鐥呬汉缁х画鍙彿锛屼絾涓嶅啀鏂板鍊欒瘖鐥呬汉锛� -->
+      <el-switch
+        v-model="stopReady"
+        :disabled="stopReadyFlag"
+        active-text="鍋滄鍊欒瘖"
+        inactive-text="姝e父鎺ヨ瘖"
+        inline-prompt
+        style="margin-left: 12px; --el-switch-on-color: #e6a23c"
+        @change="onStopReadyChange"
+      />
+      <!-- 闇�姹�2锛氭挙閿�璇偣鍙彿 / 鎾ら攢妫�鏌ュ畬鎴愶紙鍧囧洖鍒板�欒瘖鍖猴級 -->
+      <el-button :disabled="undoFlag" type="warning" plain @click="undoCall">鎾ら攢鍙彿</el-button>
+      <el-button :disabled="undoFlag" type="warning" plain @click="undoFinish">鎾ら攢瀹屾垚</el-button>
     </el-container>
   </el-container>
 </template>
diff --git a/src/views/ecg/jobrecord/index.vue b/src/views/ecg/jobrecord/index.vue
index f0661fa..8b66e84 100644
--- a/src/views/ecg/jobrecord/index.vue
+++ b/src/views/ecg/jobrecord/index.vue
@@ -137,6 +137,68 @@
       <el-table-column label="璁惧缂栧彿" align="center" prop="devId" />
       <el-table-column label="鎮h�呯紪鍙�" align="center" prop="patId" />
       <el-table-column label="鎮h�呭悕绉�" align="center" prop="patName" />
+      <!-- 闇�姹�1锛氶棬璇婂彿 + 鍖诲槺鍙凤紙姝ゅ墠杩欎袱涓〉闈㈤仐婕忎簡璇ュ垪锛屾湰娆¤ˉ榻愶級
+           鏍囩鐢便�屽氨璇婂崱鍙枫�嶆敼涓恒�岄棬璇婂彿銆嶏紙缁忕‘璁わ級锛歮edical_card 鍏ㄥ簱涓虹┖锛�
+           璇ュ垪瀹為檯鏄剧ず outpatient_no锛堣瑙併�婇儴缃叉竻鍗曘��5.1锛夈�� -->
+      <el-table-column label="闂ㄨ瘖鍙�" align="center" min-width="140px">
+        <template #default="scope">
+          <span>{{ resolveCardNo(scope.row).value }}</span>
+          <el-tag v-if="resolveCardNo(scope.row).from" size="small" type="info" effect="plain" class="ml-1">
+            {{ resolveCardNo(scope.row).from }}
+          </el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="鍖诲槺鍙�" align="center" prop="doctorAdviceNo" min-width="110px">
+        <template #default="scope">
+          {{ scope.row.doctorAdviceNo || '-' }}
+        </template>
+      </el-table-column>
+
+      <!-- 闇�姹�1锛氳ˉ榻愭偅鑰呬俊鎭紙鍚庣 JobRecordDO 宸叉墿瀛楁骞舵寜 rentId 鎵归噺鍥炲~锛� -->
+      <el-table-column label="鎬у埆" align="center" width="70px">
+        <template #default="scope">
+          <!-- 1鐢�/2濂筹紱0 鎴栫己澶憋紙HIS 鏈彁渚涳級鏄剧ず"鏈煡" -->
+          <dict-tag v-if="scope.row.patGender === 1 || scope.row.patGender === 2"
+                    :type="DICT_TYPE.SYSTEM_USER_SEX" :value="scope.row.patGender" />
+          <span v-else>鏈煡</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="鍑虹敓鏃ユ湡" align="center" width="110px">
+        <template #default="scope">{{ formatDateOnly(scope.row.patBirthday) || '-' }}</template>
+      </el-table-column>
+      <el-table-column label="骞撮緞" align="center" width="80px">
+        <template #default="scope">{{ formatAge(scope.row.patBirthday) || '-' }}</template>
+      </el-table-column>
+      <el-table-column label="鏉ユ簮" align="center" width="90px">
+        <template #default="scope">
+          <dict-tag v-if="scope.row.patSrc !== undefined && scope.row.patSrc !== null"
+                    :type="DICT_TYPE.ECG_PAT_SOURCE" :value="scope.row.patSrc" />
+          <span v-else>-</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="鐥呭尯" align="center" min-width="110px">
+        <template #default="scope">{{ scope.row.patWardDesc || '-' }}</template>
+      </el-table-column>
+      <el-table-column label="鐥呭簥鍙�" align="center" width="90px">
+        <template #default="scope">{{ scope.row.patBedNo || '-' }}</template>
+      </el-table-column>
+      <el-table-column label="鎮h�呯數璇�" align="center" min-width="120px">
+        <template #default="scope">{{ scope.row.patMobile || scope.row.patPhone || '-' }}</template>
+      </el-table-column>
+      <el-table-column label="寮�鍗曟棩鏈�" align="center" min-width="150px">
+        <template #default="scope">{{ formatDateTime(scope.row.doctorTime) || '-' }}</template>
+      </el-table-column>
+      <el-table-column label="璺濅粖澶╂暟" align="center" width="90px">
+        <template #default="scope">{{ formatDaysFromOrder(scope.row.doctorTime) || '-' }}</template>
+      </el-table-column>
+      <el-table-column label="寮�鍗曞尰甯�" align="center" min-width="100px">
+        <template #default="scope">{{ scope.row.doctor || '-' }}</template>
+      </el-table-column>
+      <el-table-column label="澶氳��" align="center" width="110px">
+        <template #default="scope">
+          <dict-tag :type="DICT_TYPE.ECG_TOLERANCE" :value="scope.row.tolerance ?? 0" />
+        </template>
+      </el-table-column>
       <el-table-column
         label="浣滀笟鏃堕棿"
         align="center"
@@ -192,6 +254,9 @@
 import download from '@/utils/download'
 import { JobRecordApi, JobRecordVO } from '@/api/ecg/jobrecord'
 import JobRecordForm from './JobRecordForm.vue'
+// 闇�姹�1锛氭偅鑰呬俊鎭� 18 椤癸紙瀛楀吀 + 骞撮緞/璺濅粖澶╂暟绛夊疄鏃惰绠楋級
+import { DICT_TYPE } from '@/utils/dict'
+import { formatAge, formatDaysFromOrder, formatDateTime, formatDateOnly, resolveCardNo } from '@/utils/patientInfo'
 
 /** 宸ヤ綔璁板綍 鍒楄〃锛堝綋鍓嶆湭琚换浣曡彍鍗�/浠g爜寮曠敤锛屼繚鐣欏鐢級 */
 // 鍘� name 涓� 'JobRecord'锛屼笌 JobStatistic.vue 閲嶅悕锛堝悗鑰呮槸鑿滃崟 2839 鍞竴鍦ㄧ敤鐨勯〉闈級銆�
diff --git a/src/views/ecg/queue/index.vue b/src/views/ecg/queue/index.vue
index f202487..b1d5f8f 100644
--- a/src/views/ecg/queue/index.vue
+++ b/src/views/ecg/queue/index.vue
@@ -182,22 +182,76 @@
 <!--      <el-table-column label="id" align="center" prop="id" />-->
       <el-table-column label="灏辫瘖娴佹按鍙�" align="center" prop="episodeId" min-width="110px"/>
       <el-table-column label="鐢宠鍙�" align="center" prop="applyNo" min-width="110px"/>
+      <el-table-column label="鎺掗槦搴忓彿" align="center" prop="seqNum" />
+      <el-table-column label="棰勭害鍙�" align="center" prop="bookSeqNum" />
       <el-table-column label="鎮h�呯紪鍙�" align="center" prop="patId" />
-      <el-table-column label="鎮h�呭鍚�" align="center" min-width="160px">
+      <!-- 鏈垪鏍囩鐢便�屽氨璇婂崱鍙枫�嶆敼涓恒�岄棬璇婂彿銆嶏紙缁忕‘璁わ級銆傚師鍥狅紙璇﹁銆婇儴缃叉竻鍗曘��5.1锛夛細
+           HIS 鍦ㄥ崱鍙锋Ы浣嶄紶绌猴紝medical_card 鍏ㄥ簱 159,116 琛�**鏃犱竴闈炵┖**锛�
+           瀹炴祴璇ュ垪 99.9% 鏄剧ず鐨勬槸 outpatient_no锛�65% 褰㈠韬唤璇併��35% 涓洪棬璇婂彿锛夈��
+           resolveCardNo 浠嶆寜鍊煎舰鎬佺粰鍑�**鏉ユ簮鏍囨敞**锛堣韩浠借瘉/浣忛櫌鍙�/闂ㄨ瘖鍙凤級銆� -->
+      <el-table-column label="闂ㄨ瘖鍙�" align="center" min-width="140px">
         <template #default="scope">
-          {{scope.row.patName}} ({{genderFormat(scope.row.patGender)}})
-          <dict-tag :type="DICT_TYPE.ECG_PAT_SOURCE" :value="scope.row.patDetails?.source" />
+          <span>{{ resolveCardNo(scope.row).value }}</span>
+          <el-tag v-if="resolveCardNo(scope.row).from" size="small" type="info" effect="plain" class="ml-1">
+            {{ resolveCardNo(scope.row).from }}
+          </el-tag>
         </template>
+      </el-table-column>
+      <!-- 闇�姹�1锛氬尰鍢卞彿锛圚IS observationRequest.id.item[root=2.16.156.10011.1.28]锛夈��
+           璇ヨ妭鐐瑰湪瑙勮寖涓潪蹇呴』椤癸紝鍘嗗彶鏁版嵁锛堟柊澧炲垪涔嬪墠閲囬泦鐨勶級涓虹┖锛屾樉绀� '-'銆� -->
+      <el-table-column label="鍖诲槺鍙�" align="center" prop="doctorAdviceNo" min-width="110px">
+        <template #default="scope">
+          {{ scope.row.doctorAdviceNo || '-' }}
+        </template>
+      </el-table-column>
+      <el-table-column label="鎮h�呭鍚�" align="center" prop="patName" min-width="90px" />
+      <el-table-column label="鎬у埆" align="center" prop="patGender" width="70px">
+        <template #default="scope">{{ genderFormat(scope.row.patGender) }}</template>
+      </el-table-column>
+      <el-table-column label="鏉ユ簮" align="center" width="90px">
+        <template #default="scope">
+          <!-- 浼樺厛鐢ㄩ绾﹀崟骞抽摵鍊硷紝鍥為��鍒� patDetails 蹇収 -->
+          <dict-tag :type="DICT_TYPE.ECG_PAT_SOURCE"
+                    :value="scope.row.patSrc ?? scope.row.patDetails?.source ?? 0" />
+        </template>
+      </el-table-column>
+      <el-table-column label="鍑虹敓鏃ユ湡" align="center" min-width="110px">
+        <template #default="scope">{{ formatDateOnly(scope.row.patBirthday) }}</template>
+      </el-table-column>
+      <el-table-column label="骞撮緞" align="center" width="80px">
+        <template #default="scope">{{ formatAge(scope.row.patBirthday) }}</template>
       </el-table-column>
       <el-table-column label="妫�鏌ョ被鍨�" align="center" prop="bookCheckType" min-width="100px">
         <template #default="scope">
           {{getCheckTypeName(scope.row.bookCheckType)}}
         </template>
       </el-table-column>
-      <el-table-column label="鎮h�呰鎯�" align="center" prop="patDetails" min-width="300px">
+      <el-table-column label="鐥呭尯" align="center" min-width="110px">
+        <template #default="scope">{{ scope.row.patWardDesc || scope.row.patDetails?.wardDesc || '-' }}</template>
+      </el-table-column>
+      <el-table-column label="鐥呭簥鍙�" align="center" width="90px">
         <template #default="scope">
-          <span>{{scope.row.patDetails?.mobile}} {{scope.row.patDetails?.wardDesc}} {{scope.row.patDetails?.bedNo}}</span>
+          <!-- 娉ㄦ剰锛歴cope.row.bedNo 鏄�愯瘖鐤楀簥銆�(宸ヤ綅)锛屼笉鏄梾搴婂彿锛�
+               鐥呭簥鍙峰彇 patBedNo / patDetails.bedNo -->
+          {{ scope.row.patBedNo || scope.row.patDetails?.bedNo || '-' }}
         </template>
+      </el-table-column>
+      <el-table-column label="鎮h�呯數璇�" align="center" min-width="120px">
+        <template #default="scope">
+          {{ scope.row.patMobile || scope.row.patPhone || scope.row.patDetails?.mobile || '-' }}
+        </template>
+      </el-table-column>
+      <el-table-column label="鐧昏鏃堕棿" align="center" min-width="150px">
+        <template #default="scope">{{ formatDateTime(scope.row.registerDate) }}</template>
+      </el-table-column>
+      <el-table-column label="寮�鍗曟棩鏈�" align="center" min-width="150px">
+        <template #default="scope">{{ formatDateTime(scope.row.doctorTime) }}</template>
+      </el-table-column>
+      <el-table-column label="璺濅粖澶╂暟" align="center" width="90px">
+        <template #default="scope">{{ formatDaysFromOrder(scope.row.doctorTime) }}</template>
+      </el-table-column>
+      <el-table-column label="寮�鍗曞尰甯�" align="center" prop="doctor" min-width="100px">
+        <template #default="scope">{{ scope.row.doctor || '-' }}</template>
       </el-table-column>
       <el-table-column label="棰勭害鏃舵" align="center" prop="bookTimeslot" min-width="100px">
         <template #default="scope">
@@ -209,11 +263,10 @@
           <dict-tag :type="DICT_TYPE.ECG_QUEUE_STATUS" :value="scope.row.status" />
         </template>
       </el-table-column>
-      <el-table-column label="棰勭害鍙�" align="center" prop="bookSeqNum" />
-      <el-table-column label="鎺掗槦鍙�" align="center" prop="seqNum" />
       <el-table-column label="澶氳�愯嵂" width="150" align="center" prop="tolerance" >
          <template #default="scope">
-          <dict-tag :type="DICT_TYPE.ecg_tolerance" :value="scope.row.tolerance" />
+          <!-- 闇�姹�6锛氬鑰愯蛋瀛楀吀锛汵ULL 鎸�"鏃�"鏄剧ず锛圦12锛� -->
+          <dict-tag :type="DICT_TYPE.ECG_TOLERANCE" :value="scope.row.tolerance ?? 0" />
         </template>
       </el-table-column>
       <el-table-column label="VIP" align="center" prop="isVip" />
@@ -256,6 +309,8 @@
 import AppointmentForm from "@/views/ecg/appointment/AppointmentForm.vue";
 import {genderFormat} from "@/utils/stringUtil";
 import {getCheckTypeName} from "../../../utils/checkTypeFormatter";
+// 闇�姹�1锛氭偅鑰呬俊鎭� 18 椤圭殑鍏叡鏍煎紡鍖栵紙骞撮緞銆佽窛浠婂ぉ鏁扮瓑锛�
+import { formatAge, formatDaysFromOrder, formatDateTime, formatDateOnly, resolveCardNo } from '@/utils/patientInfo'
 
 /** 鎺掗槦 鍒楄〃 */
 defineOptions({ name: 'queue' })

--
Gitblit v1.9.3