zhangwencui
92 分钟以前 f08a81f01bc4a4104dd9ef04e071bb0bd0eb8afe
src/views/im/home/composables/useFriendBuckets.ts
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,99 @@
import type { FriendLite } from '../types'
import { computed, type ComputedRef, type Ref } from 'vue'
/** å­—母分桶结果:letter å– 'A'-'Z' æˆ–兜底 '#';list æ¡¶å†…按拼音 / åå­—自然序 */
export interface FriendBucket {
  letter: string
  list: FriendLite[]
}
/** å–分桶 / æŽ’序键:备注拼音优先 â†’ æ˜µç§°æ‹¼éŸ³ â†’ åå­—本身(兜底英文 / æ•°å­—) */
function getSortKey(friend: FriendLite): string {
  return (
    friend.displayNamePinyin ||
    friend.nicknamePinyin ||
    (friend.displayName || friend.nickname || '').toLowerCase()
  )
}
/** å–分桶字母:拼音首字母大写,非字母(纯符号 / æ•°å­— / ä¸­æ–‡ï¼‰å…œåº• '#' */
function getBucketLetter(friend: FriendLite): string {
  const first = getSortKey(friend).charAt(0)
  return /^[a-zA-Z]$/.test(first) ? first.toUpperCase() : '#'
}
/** æ‹¼éŸ³é¦–字母拼接:「lao zhang」→ 'lz',支持「输 lz æœè€å¼ ã€ */
function pinyinInitials(pinyin?: string): string {
  if (!pinyin) {
    return ''
  }
  return pinyin
    .split(' ')
    .map((word) => word.charAt(0))
    .join('')
}
/**
 * å¥½å‹åˆ—表的搜索 + å­—母分桶
 *
 * - æœç´¢åŒ¹é…ï¼šå¤‡æ³¨ / æ˜µç§° / å…¨æ‹¼ï¼ˆåŽ»ç©ºæ ¼ï¼‰/ é¦–字母任一命中
 * - åˆ†æ¡¶è§„则:A-Z + '#' å…œåº•,桶内按 getSortKey è‡ªç„¶åº
 *
 * é€šè®¯å½•页 FriendList ä¸Žé€‰æ‹©ç±»å¼¹çª— FriendPickerPanel å…±ç”¨ï¼Œé¿å…è§„则各自实现走偏
 */
export function useFriendBuckets(
  friends: ComputedRef<FriendLite[]> | Ref<FriendLite[]>,
  keyword: Ref<string>
): {
  buckets: ComputedRef<FriendBucket[]>
  filtered: ComputedRef<FriendLite[]>
} {
  const filtered = computed(() => {
    const keywordLower = keyword.value.trim().toLowerCase()
    if (!keywordLower) {
      return friends.value
    }
    return friends.value.filter((friend) => {
      const nicknamePinyin = friend.nicknamePinyin || ''
      const displayNamePinyin = friend.displayNamePinyin || ''
      // å…¨æ‹¼æœç´¢åŽ»æŽ‰ç©ºæ ¼ï¼Œè®©ã€Œlaozhang」也能命中「lao zhang」
      return (
        (friend.nickname || '').toLowerCase().includes(keywordLower) ||
        (friend.displayName || '').toLowerCase().includes(keywordLower) ||
        nicknamePinyin.replaceAll(/\s/g, '').includes(keywordLower) ||
        displayNamePinyin.replaceAll(/\s/g, '').includes(keywordLower) ||
        pinyinInitials(nicknamePinyin).includes(keywordLower) ||
        pinyinInitials(displayNamePinyin).includes(keywordLower)
      )
    })
  })
  const buckets = computed<FriendBucket[]>(() => {
    const map = new Map<string, FriendLite[]>()
    for (const friend of filtered.value) {
      const letter = getBucketLetter(friend)
      const bucket = map.get(letter) ?? []
      bucket.push(friend)
      map.set(letter, bucket)
    }
    const letters = [...map.keys()].toSorted((a, b) => {
      // '#' æ°¸è¿œæŽ’末尾,A-Z èµ° localeCompare
      if (a === '#') {
        return 1
      }
      if (b === '#') {
        return -1
      }
      return a.localeCompare(b)
    })
    return letters.map((letter) => ({
      letter,
      list: (map.get(letter) ?? []).toSorted((a, b) =>
        getSortKey(a).localeCompare(getSortKey(b))
      )
    }))
  })
  return { filtered, buckets }
}