gaoluyang
32 分钟以前 cb9cd49627b65a4c0e137e08063271a8cefe1826
src/views/im/home/store/faceStore.ts
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,151 @@
import type { ImFacePackApi } from '#/api/im/face/pack'
import type { ImFaceUserItemApi } from '#/api/im/face/userItem'
import { ref } from 'vue'
import { acceptHMRUpdate, defineStore } from 'pinia'
import { getFacePackList as apiGetFacePackList } from '#/api/im/face/pack'
import { createFaceUserItem as apiCreateFaceUserItem, deleteFaceUserItem as apiDeleteFaceUserItem, getFaceUserItemList as apiGetFaceUserItemList } from '#/api/im/face/userItem'
/**
 * IM è¡¨æƒ…面板数据 store(系统表情包 + ä¸ªäººè¡¨æƒ…)
 *
 * ä¸æŒä¹…化:数据小、低频;每次进 IM ç¬¬ä¸€æ¬¡æ‰“开表情面板时按需拉,关 tab å³ä¸¢å¼ƒ
 * - ç³»ç»ŸåŒ…:IM ä¸»é¡µ onMounted åŽå°é¢„拉(不阻塞首屏),消除面板首次展开的白屏
 * - ä¸ªäººè¡¨æƒ…:切到「收藏」tab / é•¿æŒ‰æ¶ˆæ¯ã€Œæ·»åŠ åˆ°è¡¨æƒ…ã€æ—¶æŒ‰éœ€æ‹‰
 */
export const useFaceStore = defineStore('imFace', () => {
  /** ç³»ç»Ÿè¡¨æƒ…包列表(含每个包的 items);运营管理后台维护 */
  const facePacks = ref<ImFacePackApi.FacePackUser[]>([])
  /** ä¸ªäººè¡¨æƒ…包列表(用户长按「添加到表情」/ ä¸Šä¼ äº§ç”Ÿï¼‰ */
  const faceUserItems = ref<ImFaceUserItemApi.FaceUserItem[]>([])
  /** clear() æ—¶é€’增;旧账号请求返回后不写入新账号内存 */
  let storeEpoch = 0
  /**
   * ç³»ç»Ÿè¡¨æƒ…包拉取 promise;ensureFacePackList å†… cache:
   * - null = è¿˜æ²¡æ‹‰è¿‡ï¼Œä¸‹æ¬¡è°ƒç”¨çœŸå‘请求
   * - resolve åŽä¿ç•™å¯¹è±¡ = åŽç»­è°ƒç”¨ await ç«‹å³è¿”回,不再发请求
   * - reject åŽç½®å›ž null,让调用方下次重试
   */
  let facePacksPromise: null | Promise<void> = null
  /** æŒ‰éœ€æ‹‰å–系统表情包(已拉过则直接复用 cached promise) */
  async function ensureFacePackList(): Promise<void> {
    if (!facePacksPromise) {
      const requestEpoch = storeEpoch
      facePacksPromise = apiGetFacePackList()
        .then((data) => {
          if (requestEpoch !== storeEpoch) {
            return
          }
          facePacks.value = data || []
        })
        .catch((error) => {
          console.warn('[IM] æ‹‰å–表情包失败', error)
          if (requestEpoch === storeEpoch) {
            facePacksPromise = null
          }
          throw error
        })
    }
    return facePacksPromise
  }
  /** ä¸ªäººè¡¨æƒ…拉取 promise;语义同上 */
  let faceUserItemsPromise: null | Promise<void> = null
  /** æŒ‰éœ€æ‹‰å–个人表情(已拉过则直接复用 cached promise) */
  async function ensureFaceUserItemList(): Promise<void> {
    if (!faceUserItemsPromise) {
      const requestEpoch = storeEpoch
      faceUserItemsPromise = apiGetFaceUserItemList()
        .then((data) => {
          if (requestEpoch !== storeEpoch) {
            return
          }
          faceUserItems.value = data || []
        })
        .catch((error) => {
          console.warn('[IM] æ‹‰å–个人表情失败', error)
          if (requestEpoch === storeEpoch) {
            faceUserItemsPromise = null
          }
          throw error
        })
    }
    return faceUserItemsPromise
  }
  /**
   * æ·»åŠ ä¸ªäººè¡¨æƒ…ï¼›æœåŠ¡ç«¯å¯¹åŒ URL æŠ› FACE_USER_ITEM_DUPLICATED é”™è¯¯
   *
   * æ¥æºï¼š1. ç”¨æˆ·åœ¨è¡¨æƒ…面板「+」上传图片  2. é•¿æŒ‰æ¶ˆæ¯ã€Œæ·»åŠ åˆ°è¡¨æƒ…ã€
   */
  async function addFaceUserItem(reqVO: ImFaceUserItemApi.FaceUserItemSaveReqVO): Promise<boolean> {
    const requestEpoch = storeEpoch
    const id = await apiCreateFaceUserItem(reqVO)
    if (!id) {
      return false
    }
    // å·²åˆ‡è´¦å·æ—¶è·³è¿‡æ—§è¯·æ±‚结果
    if (requestEpoch !== storeEpoch) {
      return false
    }
    // id ä¸åœ¨ç¼“存里才插入;服务端唯一约束兜底了 race,本地理论上不会拿到重复 id
    if (!faceUserItems.value.some((item) => item.id === id)) {
      faceUserItems.value.unshift({
        id,
        url: reqVO.url,
        name: reqVO.name,
        width: reqVO.width,
        height: reqVO.height
      })
    }
    return true
  }
  /** åˆ é™¤ä¸ªäººè¡¨æƒ…;本地立即移除 */
  async function removeFaceUserItem(id: number): Promise<boolean> {
    const requestEpoch = storeEpoch
    try {
      await apiDeleteFaceUserItem(id)
      // å·²åˆ‡è´¦å·æ—¶è·³è¿‡æ—§è¯·æ±‚结果
      if (requestEpoch !== storeEpoch) {
        return false
      }
      faceUserItems.value = faceUserItems.value.filter((item) => item.id !== id)
      return true
    } catch (error) {
      console.warn('[IM] åˆ é™¤ä¸ªäººè¡¨æƒ…失败', { id }, error)
      return false
    }
  }
  /** æ¸…空表情缓存 */
  function clear(): void {
    facePacks.value = []
    faceUserItems.value = []
    facePacksPromise = null
    faceUserItemsPromise = null
    storeEpoch++
  }
  return {
    facePacks,
    faceUserItems,
    ensureFacePackList,
    ensureFaceUserItemList,
    addFaceUserItem,
    removeFaceUserItem,
    clear
  }
})
/** åœ¨ setup å¤–(路由守卫等)取 store å®žä¾‹çš„工具方法 */
export const useFaceStoreWithOut = () => useFaceStore()
if (import.meta.hot) {
  import.meta.hot.accept(acceptHMRUpdate(useFaceStore, import.meta.hot))
}