From 27cd042df9aca0383a49f3514bc21958dd890912 Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期一, 29 六月 2026 15:42:23 +0800
Subject: [PATCH] 银川 1.联调产品维护页面 2.添加IM即时通讯模块

---
 src/views/im/home/store/groupRequestStore.ts |  242 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 242 insertions(+), 0 deletions(-)

diff --git a/src/views/im/home/store/groupRequestStore.ts b/src/views/im/home/store/groupRequestStore.ts
new file mode 100644
index 0000000..24ea5da
--- /dev/null
+++ b/src/views/im/home/store/groupRequestStore.ts
@@ -0,0 +1,242 @@
+import type { ImGroupRequestApi } from '#/api/im/group/request'
+
+import { acceptHMRUpdate, defineStore } from 'pinia'
+
+import { agreeGroupRequest as apiAgreeGroupRequest, getMyGroupRequest as apiGetMyGroupRequest, getUnhandledRequestList as apiGetUnhandledRequestList, pullMyGroupRequestList as apiPullMyGroupRequestList, refuseGroupRequest as apiRefuseGroupRequest } from '#/api/im/group/request'
+import { getCurrentUserId } from '#/views/im/utils/auth'
+import { ImGroupRequestHandleResult } from '#/views/im/utils/constants'
+
+import { getDb, StorageKeys } from '../../utils/db'
+import { runIncrementalPull } from '../../utils/pull'
+
+type PendingRequest = { epoch: number; promise: Promise<void>; userId: number; }
+
+/** clear() 鏃堕�掑锛涙棫璐﹀彿 in-flight 鐨� pullGroupRequests 缁撴灉 resolve 鍚庢瘮瀵逛竴鑷存墠鍐� store锛岄槻璺ㄨ处鍙风孩鐐规薄鏌擄紙涓� friendStore 鍚屽彛寰勶級 */
+let storeEpoch = 0
+let pendingUnhandledFetch: null | PendingRequest = null
+
+/**
+ * IM 鍔犵兢鐢宠 Store
+ *
+ * 浠呯淮鎶ゃ�屾垜绠$悊鐨勬墍鏈夌兢銆嶄笅鏈鐞嗙殑鐢宠鍒楄〃锛坲nhandledList锛夛紱
+ * 妯箙 / Drawer 閮戒粠杩欓噷娲剧敓 count 鍜屽垎缁勫垪琛紝閬垮厤缁� ImGroupApi.GroupRespVO 鎸� pendingRequestCount 瀛楁
+ *
+ * 鏁版嵁鐢熷懡鍛ㄦ湡锛�
+ * - 杩� IM 鍚庤皟涓�娆� fetchUnhandledGroupRequestList 鎷夐椤靛叏閲�
+ * - WebSocket 1503 鈫� 璋� addGroupRequestById(requestId) 鎷夊崟鏉� + push 鍒� unhandledList 澶撮儴
+ * - WebSocket 1505 / 1506 鈫� 鎸� requestId 浠� unhandledList 绉婚櫎
+ * - WebSocket 1517 GROUP_ADMIN_ADD锛堣嚜宸辫鍔犱负 admin锛夆啋 閲嶆柊璋� fetchUnhandledGroupRequestList
+ * - 鏈 agree / refuse 澶勭悊鍚� 鈫� 鏈湴鎸� requestId 绉婚櫎
+ */
+export const useGroupRequestStore = defineStore('imGroupRequestStore', {
+  state: () => ({
+    /** 鎴戠鐞嗙殑鎵�鏈夌兢涓嬫湭澶勭悊鐢宠鍒楄〃锛堟寜 id 鍊掑簭锛� */
+    unhandledList: [] as ImGroupRequestApi.GroupRequestRespVO[],
+    /** fetchUnhandledGroupRequestList 鏄惁鎴愬姛鎵ц杩囷紱閬垮厤妯箙鏄剧ず 0 鐒跺悗璺虫暟瀛楃殑闂儊 */
+    loaded: false
+  }),
+
+  getters: {
+    /**
+     * 鍚勭兢涓嬫湭澶勭悊鐢宠鏁扮殑 Map锛汷(N) 鎵竴娆$紦瀛樹緵 ConversationItem 绛� N 澶勫鐢紝閬垮厤 N脳M 閲嶅 filter
+     */
+    getUnhandledGroupRequestCountMap(state): Map<number, number> {
+      const map = new Map<number, number>()
+      for (const request of state.unhandledList) {
+        map.set(request.groupId, (map.get(request.groupId) ?? 0) + 1)
+      }
+      return map
+    },
+    /** 鎸囧畾缇や笅鐨勬湭澶勭悊鐢宠鏁� */
+    getUnhandledGroupRequestCount(): (groupId: number) => number {
+      return (groupId: number) => this.getUnhandledGroupRequestCountMap.get(groupId) ?? 0
+    },
+    /** 鎸囧畾缇や笅鐨勬湭澶勭悊鐢宠鍒楄〃 */
+    getUnhandledGroupRequestListByGroupId:
+      (state) =>
+      (groupId: number): ImGroupRequestApi.GroupRequestRespVO[] =>
+        state.unhandledList.filter((r) => r.groupId === groupId)
+  },
+
+  actions: {
+    /** 浠� IndexedDB 鎭㈠鍔犵兢鐢宠 */
+    async loadGroupRequestList(): Promise<boolean> {
+      try {
+        const cached = await getDb().getAll<ImGroupRequestApi.GroupRequestRespVO>('groupRequests')
+        if (!cached || cached.length === 0) {
+          return false
+        }
+        this.unhandledList = cached
+          .filter((request) => request.handleResult === ImGroupRequestHandleResult.UNHANDLED)
+          .toSorted((requestA, requestB) => requestB.id - requestA.id)
+        return true
+      } catch (error) {
+        console.warn('[IM groupRequestStore] 鏈湴鍔犵兢鐢宠缂撳瓨璇诲彇澶辫触', error)
+        return false
+      }
+    },
+
+    /** 淇濆瓨鍔犵兢鐢宠鍒楄〃 */
+    saveGroupRequestList(): void {
+      void getDb()
+        .transaction(['groupRequests'], 'readwrite', async (tx) => {
+          const db = getDb()
+          await db.clearStore('groupRequests', tx)
+          for (const request of this.unhandledList) {
+            await db.put('groupRequests', request, tx)
+          }
+        })
+        .catch((error) => console.warn('[IM groupRequestStore] 鏈湴鍔犵兢鐢宠缂撳瓨鍐欏叆澶辫触', error))
+    },
+
+    /** 淇濆瓨鍗曟潯鍔犵兢鐢宠 */
+    async saveGroupRequestRecord(request: ImGroupRequestApi.GroupRequestRespVO): Promise<void> {
+      await getDb().put('groupRequests', request)
+    },
+
+    /** 淇濆瓨鍗曟潯鍔犵兢鐢宠 */
+    saveGroupRequest(request: ImGroupRequestApi.GroupRequestRespVO): void {
+      void this.saveGroupRequestRecord(request).catch((error) =>
+        console.warn('[IM groupRequestStore] 鏈湴鍔犵兢鐢宠鍐欏叆澶辫触', error)
+      )
+    },
+
+    /** 鎷夊彇鎴戠鐞嗙殑鎵�鏈夌兢涓嬫湭澶勭悊鐢宠锛涜繘 IM 鍚� / 鍗囩骇 admin 鍚� / WS 鎺ㄩ�佹湁鍐茬獊鏃惰皟鐢� */
+    async fetchUnhandledGroupRequestList() {
+      const requestEpoch = storeEpoch
+      const requestUserId = getCurrentUserId()
+      if (
+        pendingUnhandledFetch?.epoch === requestEpoch &&
+        pendingUnhandledFetch.userId === requestUserId
+      ) {
+        return pendingUnhandledFetch.promise
+      }
+      const promise = (async () => {
+        const list = await apiGetUnhandledRequestList()
+        if (requestEpoch !== storeEpoch || getCurrentUserId() !== requestUserId) {
+          return
+        }
+        this.unhandledList = list || []
+        this.loaded = true
+        this.saveGroupRequestList()
+      })().finally(() => {
+        if (
+          pendingUnhandledFetch?.epoch === requestEpoch &&
+          pendingUnhandledFetch.userId === requestUserId
+        ) {
+          pendingUnhandledFetch = null
+        }
+      })
+      pendingUnhandledFetch = { epoch: requestEpoch, userId: requestUserId, promise }
+      return promise
+    },
+
+    /**
+     * WS 鏀跺埌 1503锛氭媺鏈�鏂板唴瀹瑰苟缃《
+     *
+     * 鍚屼竴瀵� group_id, user_id 澶嶇敤璁板綍鏃� requestId 涓嶅彉浣� applyContent / inviterUserId 浼氬埛鏂帮紝鎵�浠ユ棤鏉′欢 fetch + 鎺掑埌澶撮儴
+     */
+    async addGroupRequestById(requestId: number) {
+      const requestEpoch = storeEpoch
+      const requestUserId = getCurrentUserId()
+      const request = await apiGetMyGroupRequest(requestId)
+      if (!request) {
+        return
+      }
+      if (requestEpoch !== storeEpoch || getCurrentUserId() !== requestUserId) {
+        return
+      }
+      this.upsertGroupRequest(request)
+    },
+
+    /**
+     * 鏈湴鍚堝苟 / 鏂板鍗曟潯鍔犵兢鐢宠锛圵S 鎺ㄩ�� & 澧為噺鎷夊彇鍏辩敤锛�
+     *
+     * 鏈鐞嗙殑鎸� id 鍘婚噸鍚庣疆椤讹紱宸插鐞嗙殑浠庢湭澶勭悊鍒楄〃绉婚櫎锛岄伩鍏嶈ˉ鍋挎椂鎶婂凡鍚屾剰 / 鎷掔粷鐨勮褰曞鍥炵孩鐐�
+     */
+    upsertGroupRequest(request: ImGroupRequestApi.GroupRequestRespVO) {
+      void this.upsertGroupRequestForPull(request).catch((error) =>
+        console.warn('[IM groupRequestStore] 鏈湴鍔犵兢鐢宠鍐欏叆澶辫触', error)
+      )
+    },
+
+    /** 鏈湴鍚堝苟 / 鏂板鍗曟潯鍔犵兢鐢宠 */
+    async upsertGroupRequestForPull(request: ImGroupRequestApi.GroupRequestRespVO): Promise<void> {
+      if (request.handleResult !== ImGroupRequestHandleResult.UNHANDLED) {
+        await this.removeGroupRequestByIdForPull(request.id)
+        return
+      }
+      this.unhandledList = [request, ...this.unhandledList.filter((r) => r.id !== request.id)]
+      await this.saveGroupRequestRecord(request)
+    },
+
+    /**
+     * 澧為噺鎷夊彇鍔犵兢鐢宠鍙樻洿骞跺悎骞讹紱鍚凡澶勭悊鐨勬寜 handleResult 璧扮Щ闄わ紙宸插鐞� 鈫� 浠庣孩鐐瑰垪琛ㄥ墧闄わ級
+     *
+     * 鍙仛閲嶈繛 / 鍚庣画绂荤嚎琛ュ伩锛屼笉璐熻矗棣栫櫥锛氶鐧荤孩鐐硅蛋 fetchUnhandledGroupRequestList锛堟湇鍔$鐩存帴杩囨护鏈鐞嗭紝璇箟鏇寸簿鍑嗐�佸惎鍔ㄦ洿杞伙級銆�
+     * 鏁呴娆¢噸杩炴椂娓告爣涓虹┖ = 涓�娆℃�у叏閲忚蛋涓�閬嶏紙宸插鐞嗚褰曞懡涓� removeGroupRequestById 涓� no-op锛岀孩鐐逛笉鍙楀奖鍝嶏級锛屼箣鍚庡閲忋��
+     */
+    async pullGroupRequests() {
+      // 蹇収 epoch锛涜处鍙峰湪鎷夊彇閫斾腑鍒囨崲锛坈lear() 鈫� epoch++锛夋椂涓㈠純鏃ц处鍙烽偅鍑犻〉缁撴灉锛岄槻璺ㄨ处鍙风孩鐐规薄鏌�
+      const requestEpoch = storeEpoch
+      const requestUserId = getCurrentUserId()
+      const isActive = () => requestEpoch === storeEpoch && getCurrentUserId() === requestUserId
+      await runIncrementalPull(
+        StorageKeys.settings.groupRequestPullCursor,
+        apiPullMyGroupRequestList,
+        async (records) => {
+          if (!isActive()) {
+            return false
+          }
+          await Promise.all(records.map((vo) => this.upsertGroupRequestForPull(vo)))
+          return true
+        },
+        isActive
+      )
+      if (isActive()) {
+        this.loaded = true
+      }
+    },
+
+    /** WS 鏀跺埌 1505 / 1506 鎴栨湰绔鐞嗗畬涓�鏉★細鎸� requestId 浠庡垪琛ㄧЩ闄� */
+    removeGroupRequestById(requestId: number) {
+      this.unhandledList = this.unhandledList.filter((r) => r.id !== requestId)
+      void getDb()
+        .delete('groupRequests', requestId)
+        .catch((error) => console.warn('[IM groupRequestStore] 鏈湴鍔犵兢鐢宠鍒犻櫎澶辫触', error))
+    },
+
+    /** 鍒犻櫎鍗曟潯鍔犵兢鐢宠 */
+    async removeGroupRequestByIdForPull(requestId: number): Promise<void> {
+      this.unhandledList = this.unhandledList.filter((r) => r.id !== requestId)
+      await getDb().delete('groupRequests', requestId)
+    },
+
+    /** 鍚屾剰鐢宠锛涙湰绔鐞嗗悗绔嬪嵆浠庡垪琛ㄧЩ闄わ紝閬垮厤琚弽澶嶇偣鍑� */
+    async agreeGroupRequest(requestId: number) {
+      await apiAgreeGroupRequest(requestId)
+      this.removeGroupRequestById(requestId)
+    },
+
+    /** 鎷掔粷鐢宠 */
+    async refuseGroupRequest(requestId: number, handleContent?: string) {
+      await apiRefuseGroupRequest(requestId, handleContent)
+      this.removeGroupRequestById(requestId)
+    },
+
+    /** 娓呯┖鍔犵兢鐢宠鍐呭瓨 */
+    clear() {
+      this.unhandledList = []
+      this.loaded = false
+      // 璐﹀彿鍒囨崲锛氶�掑 epoch 搴熷純鏃ц处鍙� in-flight 鐨� pullGroupRequests 缁撴灉锛岄伩鍏嶅啓杩涙柊璐﹀彿绾㈢偣鍒楄〃
+      storeEpoch++
+      pendingUnhandledFetch = null
+    }
+  }
+})
+
+export const useGroupRequestStoreWithOut = () => useGroupRequestStore()
+
+if (import.meta.hot) {
+  import.meta.hot.accept(acceptHMRUpdate(useGroupRequestStore, import.meta.hot))
+}

--
Gitblit v1.9.3