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

---
 src/store/modules/room.ts |  216 ++++++++++++++++++++++++++++++++++++++++++++++-------
 1 files changed, 185 insertions(+), 31 deletions(-)

diff --git a/src/store/modules/room.ts b/src/store/modules/room.ts
index 9ae973d..d751770 100644
--- a/src/store/modules/room.ts
+++ b/src/store/modules/room.ts
@@ -38,6 +38,10 @@
   reason?: 'nomatch' | 'occupied' | 'multi' | 'ip_invalid' | 'ip_is_server' | 'error'
   /** 琚崰鐢ㄦ椂鐨勫崰鐢ㄤ汉锛屼究浜庢彁绀� */
   occupiedBy?: string | null
+  /** 銆愭湰闇�姹傘�戣鍗犵敤鏃跺懡涓殑鍊欓�夊伐浣嶏紙渚�"鏄惁鎺ョ"纭鍚庣洿鎺ヨ皟鐢� takeOverBed锛� */
+  roomId?: number | null
+  bedNo?: string | null
+  roomName?: string | null
 }
 
 interface RoomInfoVO {
@@ -54,6 +58,13 @@
    * 涓よ�呯浉鍚� 鈫� 鍙搷浣滐紱涓嶅悓 鈫� 鍙鍥磋銆�
    */
   currentSeat: RoomSeatResp | null
+  /**
+   * 銆愭湰闇�姹偮蜂竴浜哄宸ヤ綅銆戝綋鍓嶇櫥褰曚汉鍗犳嵁鐨�**鍏ㄩ儴**宸ヤ綅锛堣妭鍋囨棩鍊肩彮澶氬矖浣嶏級銆�
+   *
+   * 涓� `currentSeat` 鐨勫尯鍒細`currentSeat` 鍙槸"榛樿/棣栭�夊彇"鐨勯偅涓�涓紙椤舵爮鏂囨鐢級锛�
+   * `mySeats` 鎵嶆槸瀹屾暣闆嗗悎锛沗getCanOperate` 鐢ㄥ畠鍒ゆ柇"褰撳墠鏌ョ湅鐨勫伐浣嶆槸鍚﹀睘浜庢垜"銆�
+   */
+  mySeats: RoomSeatResp[]
   /** 褰撳墠鏌ョ湅宸ヤ綅鐨勪富浜虹殑濮撳悕锛堝洿瑙傛椂鐢ㄤ簬鎻愮ず"姝e湪鍥磋 X锛堜富浜� 寮犱笁锛�"锛� */
   viewOwnerName: string | null
   /** 褰撳墠鏌ョ湅鐨勫伐浣嶇幇鍦ㄦ槸鍚�**鏃犱汉鎿嶄綔**锛堜富浜哄凡绂诲骇锛涘彧鎻愮ず锛屼笉鑷姩鎺ョ锛� */
@@ -81,6 +92,8 @@
     roomSelectMode: -1,
     // 褰撳墠鍏ュ骇鐨勫伐浣嶏紙椤舵爮鏄剧ず锛涙湭鍏ュ骇涓� null锛�
     currentSeat: null,
+    // 銆愭湰闇�姹偮蜂竴浜哄宸ヤ綅銆戞垜鍗犳嵁鐨勫叏閮ㄥ伐浣嶏紙鏈叆搴т负绌烘暟缁勶級
+    mySeats: [],
     // 姝e湪鏌ョ湅鐨勫伐浣嶇殑涓讳汉濮撳悕锛堝洿瑙傛彁绀虹敤锛�
     viewOwnerName: null,
     // 姝e湪鏌ョ湅鐨勫伐浣嶇幇鍦ㄦ槸鍚︽棤浜烘搷浣滐紙涓讳汉宸茬搴� 鈫� 鍙彁绀猴紝涓嶈嚜鍔ㄦ帴绠★級
@@ -98,16 +111,35 @@
     getCurrentSeat(): RoomSeatResp | null {
       return this.currentSeat
     },
+    /** 銆愭湰闇�姹偮蜂竴浜哄宸ヤ綅銆戞垜鍗犳嵁鐨勫叏閮ㄥ伐浣� */
+    getMySeats(): RoomSeatResp[] {
+      return this.mySeats || []
+    },
+    /** 銆愭湰闇�姹偮蜂竴浜哄宸ヤ綅銆戞垜鍗犳嵁鐨勫伐浣嶆暟閲忥紙椤舵爮鎻愮ず"鎴戠殑宸ヤ綅 N 涓�"锛� */
+    getMySeatCount(): number {
+      return (this.mySeats || []).length
+    },
     /**
      * 銆愪富/鍥磋銆戝綋鍓嶆槸鍚�**鍙互鎿嶄綔涓氬姟**銆�
      *
-     * 鍒ゅ畾锛氭垜鍏ュ骇鐨勫伐浣� == 鎴戞鍦ㄧ湅鐨勫伐浣嶏紙鏈嶅姟绔彟鏈変竴閬撶‖鏍¢獙锛歞oc_id 蹇呴』鏄垜锛夈��
-     * 涓� false 鏃跺墠绔簲绂佺敤鎵�鏈夊啓鎿嶄綔鎸夐挳锛岀晫闈㈡樉绀�"鍥磋妯″紡 路 鍙"銆�
+     * 鍒ゅ畾锛堟湰闇�姹傛敼涓�"鍖呭惈"锛夛細
+     *   褰撳墠鏌ョ湅鐨勫伐浣� 鈭� 鎴戠殑宸ヤ綅鍒楄〃 鈬� 鍙搷浣滐紙鏈嶅姟绔彟鏈変竴閬撶‖鏍¢獙锛氳宸ヤ綅 doc_id 蹇呴』鏄垜锛夈��
+     * 涓�閿宸ヤ綅鍚庯紝鎴戜笉鍙兘鍚屾椂鍙湪"涓�涓�"宸ヤ綅涓婏紝鎵�浠ヤ笉鑳藉啀鐢�"鐩哥瓑"鍒ゆ柇銆�
+     * 鍏煎锛歚mySeats` 杩樻病鍙栧埌锛堟棫鎺ュ彛/鏃х紦瀛橈級鏃跺洖閫�鍒� `currentSeat` 鐩哥瓑鍒ゆ柇銆�
      */
     getCanOperate(): boolean {
-      const seat = this.currentSeat
       const view = this.room
-      if (!seat || !seat.seated || !view || view.roomId == null || !view.bedNo) {
+      if (!view || view.roomId == null || !view.bedNo) {
+        return false
+      }
+      const seats = this.mySeats || []
+      if (seats.length > 0) {
+        return seats.some(
+          (s) => String(s.roomId) === String(view.roomId) && String(s.bedNo) === String(view.bedNo)
+        )
+      }
+      const seat = this.currentSeat
+      if (!seat || !seat.seated) {
         return false
       }
       return String(seat.roomId) === String(view.roomId) && String(seat.bedNo) === String(view.bedNo)
@@ -166,6 +198,9 @@
       this.viewOwnerName = room.docName ?? null
       this.viewTargetVacant = false
 
+      // 銆愭湰闇�姹偮蜂竴浜哄宸ヤ綅銆戞妸璇ュ伐浣嶅苟鍏ャ�屾垜鐨勫伐浣嶃�嶏紙宸插瓨鍦ㄥ垯鏇存柊锛屼笉瀛樺湪鍒欐柊澧烇級
+      this.upsertMySeat(this.currentSeat)
+
       // 銆愪慨澶嶃�戝啓鍏ョ紦瀛橈紙sessionStorage锛夈��
       //
       // 鍘熷疄鐜版槸 `const bedInfo = wsCache.get(...); if (bedInfo) { ...; wsCache.set(...) }`
@@ -176,7 +211,38 @@
       //     鎵嶅惎鍔ㄥ彇鏁板畾鏃跺櫒 鈬� **椤甸潰涓�鐗囩┖鐧斤紝鐪嬭捣鏉ュ儚"娌″姞杞芥帓闃熺梾浜�"**锛�
       //   路 瑙掕壊涓� doctor 鐨勭敤鎴疯繕浼氳璺敱瀹堝崼寮瑰洖 /roomselect 閲嶆柊閫夎瘖瀹ゃ��
       // 杩欓噷鏀逛负**鏃犳潯浠跺啓鍏�**锛涙仮澶嶈鏂囦欢鏈熬鐨� setupRoomStorePersistence()銆�
-      wsCache.set(CACHE_KEY.ROOM, { isSetRoom: true, room: this.room, currentSeat: this.currentSeat })
+      wsCache.set(CACHE_KEY.ROOM, {
+        isSetRoom: true,
+        room: this.room,
+        currentSeat: this.currentSeat,
+        mySeats: this.mySeats
+      })
+    },
+    /** 銆愭湰闇�姹偮蜂竴浜哄宸ヤ綅銆戞妸涓�鏉″伐浣嶅苟鍏� mySeats锛堟寜 roomId+bedNo 鍘婚噸锛� */
+    upsertMySeat(seat: RoomSeatResp | null) {
+      if (!seat || seat.roomId == null || !seat.bedNo) return
+      const list = (this.mySeats || []).filter(
+        (s) => !(String(s.roomId) === String(seat.roomId) && String(s.bedNo) === String(seat.bedNo))
+      )
+      list.push(seat)
+      this.mySeats = list
+    },
+    /** 銆愭湰闇�姹偮蜂竴浜哄宸ヤ綅銆戠敤鍚庣杩斿洖鐨勫畬鏁村垪琛ㄦ浛鎹� mySeats锛屽苟鍚屾 currentSeat */
+    applyMySeats(seats: RoomSeatResp[]) {
+      this.mySeats = Array.isArray(seats) ? seats : []
+      if (this.mySeats.length === 0) {
+        this.currentSeat = null
+        return
+      }
+      // currentSeat锛氫紭鍏堝彇"褰撳墠鏌ョ湅鐨勫伐浣�"瀵瑰簲鐨勯偅鏉★紝鍚﹀垯绗竴鏉�
+      const view = this.room
+      const matched = this.mySeats.find(
+        (s) =>
+          null != view &&
+          String(s.roomId) === String(view.roomId) &&
+          String(s.bedNo) === String(view.bedNo)
+      )
+      this.currentSeat = matched ?? this.mySeats[0]
     },
     /**
      * 銆愪富/鍥磋銆戞妸"鎴戞鍦ㄧ湅鐨勫伐浣�"鍒囧埌鍒汉锛堟垨鍒囧洖鑷繁锛夆�斺��**涓嶆敼鎴戠殑鍏ュ骇宸ヤ綅**銆�
@@ -201,7 +267,12 @@
       this.isSetRoom = true
       this.viewOwnerName = ownerName ?? bed.docName ?? null
       this.viewTargetVacant = bed.docId == null
-      wsCache.set(CACHE_KEY.ROOM, { isSetRoom: true, room: this.room, currentSeat: this.currentSeat })
+      wsCache.set(CACHE_KEY.ROOM, {
+        isSetRoom: true,
+        room: this.room,
+        currentSeat: this.currentSeat,
+        mySeats: this.mySeats
+      })
     },
     /**
      * 銆愪富/鍥磋銆戝埛鏂�"鎴戞鍦ㄧ湅鐨勫伐浣�"鐨勬渶鏂扮姸鎬侊紙鐢ㄤ簬鍙戠幇涓讳汉宸茬搴э級銆�
@@ -232,6 +303,8 @@
       this.isSetRoom = false
       // 椤舵爮鏍囩鍚屾娓呯┖锛堢搴у悗鏄剧ず"鏈叆搴�"锛�
       this.currentSeat = null
+      // 銆愭湰闇�姹偮蜂竴浜哄宸ヤ綅銆戠搴у悗 mySeats 涓�骞舵竻绌�
+      this.mySeats = []
       this.viewOwnerName = null
       this.viewTargetVacant = false
 
@@ -253,6 +326,12 @@
         this.room = { ...this.room, ...cached.room }
         this.isSetRoom = true
         // 銆愪富/鍥磋銆戣繛"鎴戝叆搴х殑宸ヤ綅"涓�璧锋仮澶嶏細鍚﹀垯鍒锋柊鍚� getCanOperate 浼氳鍒や负鍙
+        // 銆愭湰闇�姹偮蜂竴浜哄宸ヤ綅銆戜紭鍏堟仮澶嶅畬鏁村垪琛紱鏃х紦瀛樻病鏈� mySeats 鏃剁敤 currentSeat 鍏滃簳
+        if (Array.isArray(cached?.mySeats) && cached.mySeats.length > 0) {
+          this.mySeats = cached.mySeats
+        } else if (cached?.currentSeat) {
+          this.mySeats = [cached.currentSeat]
+        }
         if (cached?.currentSeat) {
           this.currentSeat = cached.currentSeat
           this.viewOwnerName = cached.currentSeat.docName ?? null
@@ -340,15 +419,21 @@
           } as RoomVO)
           // 椤舵爮"褰撳墠宸ヤ綅"鏍囩鐢�
           this.currentSeat = resp as RoomSeatResp
+          // 銆愭湰闇�姹偮蜂竴浜哄宸ヤ綅銆戞妸璇ュ伐浣嶅苟鍏ユ垜鐨勫伐浣嶅垪琛�
+          this.upsertMySeat(this.currentSeat)
           console.info('[room] 鎸塈P鑷姩鍏ュ骇鎴愬姛', resp)
           return { seated: true, clientIp }
         }
-        console.info('[room] 鎸塈P鑷姩鍏ュ骇鏈垚鍔燂紝杞汉宸ラ�夊伐浣�', resp)
+        console.info('[room] 鎸塈P鑷姩鍏ュ骇鏈垚鍔�', resp)
         return {
           seated: false,
           clientIp,
           reason: (resp.reason || 'nomatch') as AutoSeatResult['reason'],
-          occupiedBy: resp.ownerName ?? null
+          occupiedBy: resp.ownerName ?? resp.docName ?? null,
+          // 銆愭湰闇�姹傘�戣鍗犵敤鏃跺悗绔細甯﹀洖鍊欓�夊伐浣嶄俊鎭紝渚�"鏄惁鎺ョ"纭鍚庣洿鎺ヨ皟鐢�
+          roomId: resp.roomId ?? null,
+          bedNo: resp.bedNo ?? null,
+          roomName: resp.roomName ?? null
         }
       } catch (e) {
         console.error('[tryAutoSeatByIp] 鑷姩鍏ュ骇鎺ュ彛寮傚父', e)
@@ -367,39 +452,106 @@
      */
     async fetchMySeat(): Promise<RoomSeatResp | null> {
       try {
-        const resp: any = (await RoomApi.getMySeat()) || {}
-        if (!resp.seated) {
+        // 銆愭湰闇�姹偮蜂竴浜哄宸ヤ綅銆戜紭鍏堝彇"鎴戠殑鍏ㄩ儴宸ヤ綅"锛涘悗绔湭鍗囩骇锛�404锛夋椂鍥為��鍗曞�兼帴鍙�
+        let seats: RoomSeatResp[] = []
+        let fallbackSingle: any = null
+        try {
+          const list: any = await RoomApi.getMySeats()
+          seats = Array.isArray(list) ? (list as RoomSeatResp[]) : []
+        } catch (e) {
+          console.warn('[fetchMySeat] /my-seats 涓嶅彲鐢紝鍥為�� /my-seat', e)
+          const resp: any = (await RoomApi.getMySeat()) || {}
+          if (resp.seated) {
+            fallbackSingle = resp
+            seats = [resp as RoomSeatResp]
+          }
+        }
+
+        if (seats.length === 0 && !fallbackSingle) {
+          this.mySeats = []
           this.currentSeat = null
           return null
         }
-        this.currentSeat = resp as RoomSeatResp
+
+        this.applyMySeats(seats)
+
         const noViewTarget = !this.isSetRoom || this.room.roomId == null || !this.room.bedNo
-        const viewingMyself =
-          !noViewTarget &&
-          String(this.room.roomId) === String(resp.roomId) &&
-          String(this.room.bedNo) === String(resp.bedNo)
-        if (!noViewTarget && !viewingMyself) {
-          // 姝e湪鍥磋鍒汉 鈫� 鍙洿鏂�"鎴戝叆搴х殑宸ヤ綅"锛屼笉鍔ㄦ煡鐪嬬洰鏍�
-          console.info('[room] 鏌ヨ鍒版垜鍏ュ骇鐨勫伐浣嶏紙褰撳墠姝e湪鍥磋浠栦汉锛屼笉鍒囨崲鏌ョ湅鐩爣锛�', resp)
+        const viewingMine = !noViewTarget && this.getCanOperate
+        if (!noViewTarget && !viewingMine) {
+          // 姝e湪鍥磋鍒汉 鈫� 鍙洿鏂�"鎴戠殑宸ヤ綅鍒楄〃"锛屼笉鍔ㄦ煡鐪嬬洰鏍�
+          console.info('[room] 宸插埛鏂版垜鐨勫伐浣嶅垪琛紙褰撳墠姝e湪鍥磋浠栦汉锛屼笉鍒囨崲鏌ョ湅鐩爣锛�', seats)
           return this.currentSeat
         }
-        await this.setRoomInfoAction({
-          id: resp.id ?? null,
-          roomId: resp.roomId ?? null,
-          roomName: resp.roomName ?? null,
-          bedNo: resp.bedNo ?? null,
-          ip: resp.ip ?? null,
-          status: resp.status ?? null,
-          docId: resp.docId ?? null,
-          docName: resp.docName ?? null,
-          checkTypes: resp.checkTypes ?? null,
-          opType: resp.opType ?? null
-        } as RoomVO)
-        console.info('[room] 鏌ヨ鍒板綋鍓嶅叆搴у伐浣�', resp)
+
+        // 鏈�夋煡鐪嬬洰鏍� / 鐪嬬殑灏辨槸鑷繁鐨勬煇涓伐浣� 鈫� 瀵归綈鍒拌宸ヤ綅锛堜紭鍏堝綋鍓嶆煡鐪嬬殑閭d釜锛�
+        const target = this.currentSeat ?? seats[0]
+        if (target) {
+          await this.setRoomInfoAction({
+            id: target.id ?? null,
+            roomId: target.roomId ?? null,
+            roomName: target.roomName ?? null,
+            bedNo: target.bedNo ?? null,
+            ip: target.ip ?? null,
+            status: target.status ?? null,
+            docId: target.docId ?? null,
+            docName: target.docName ?? null,
+            checkTypes: target.checkTypes ?? null,
+            opType: target.opType ?? null
+          } as RoomVO)
+        }
+        console.info('[room] 鏌ヨ鍒版垜鐨勫伐浣嶅垪琛�', seats)
         return this.currentSeat
       } catch (e) {
         console.error('[fetchMySeat] 鏌ヨ褰撳墠宸ヤ綅澶辫触', e)
         return null
+      }
+    },
+
+    /**
+     * 銆愭湰闇�姹偮锋帴鐝嚜鍔╂帴绠°�戞妸鎸囧畾宸ヤ綅浠�"鍒汉鍗犵敤"鏀瑰埌鎴戝悕涓嬶紝骞跺垏鎹㈠埌璇ュ伐浣嶃��
+     *
+     * @returns 鏄惁鎺ョ鎴愬姛
+     */
+    async takeOverBed(roomId: number | null, bedNo: string | null): Promise<boolean> {
+      if (roomId == null || !bedNo) return false
+      try {
+        await RoomApi.takeOverBed({ roomId, bedNo })
+        // 鍒锋柊"鎴戠殑宸ヤ綅"锛堟鏃跺悗绔凡鎶婅宸ヤ綅 doc_id 璁句负鎴戯級
+        await this.fetchMySeat()
+        // 鍒囨崲鍒拌宸ヤ綅锛堣嫢鏄垰鎺ョ銆佷笖涓嶅湪鍒楄〃閲岋紝鍒欐墜鍔ㄨˉ涓�鏉″苟鍒囪繃鍘伙級
+        let seat = (this.mySeats || []).find(
+          (s) => String(s.roomId) === String(roomId) && String(s.bedNo) === String(bedNo)
+        )
+        if (!seat) {
+          const userStore = useUserStore()
+          const curUser: any = userStore.getUser || {}
+          seat = {
+            seated: true,
+            roomId,
+            bedNo,
+            roomName: this.room?.roomName ?? null,
+            docId: curUser.id ?? null,
+            docName: curUser.nickname ?? null
+          } as RoomSeatResp
+          this.mySeats = [...(this.mySeats || []), seat]
+        }
+        await this.setRoomInfoAction({
+          id: seat.id ?? null,
+          roomId: seat.roomId ?? null,
+          roomName: seat.roomName ?? null,
+          bedNo: seat.bedNo ?? null,
+          ip: seat.ip ?? null,
+          status: seat.status ?? null,
+          docId: seat.docId ?? null,
+          docName: seat.docName ?? null,
+          checkTypes: seat.checkTypes ?? null,
+          opType: seat.opType ?? null
+        } as RoomVO)
+        console.info('[room] 鎺ョ宸ヤ綅鎴愬姛', roomId, bedNo)
+        return true
+      } catch (e) {
+        console.error('[takeOverBed] 鎺ョ宸ヤ綅澶辫触', e)
+        return false
       }
     },
 
@@ -428,6 +580,8 @@
         return false
       }
       await this.setRoomInfoAction(tempRoomVO)
+      // 銆愭湰闇�姹偮蜂竴浜哄宸ヤ綅銆戝叆搴у悗鍒锋柊"鎴戠殑鍏ㄩ儴宸ヤ綅"锛堝彲鑳藉凡鏈夊涓級
+      await this.fetchMySeat()
       return true
     },
 

--
Gitblit v1.9.3