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