feat(staffchat): 入口改造(StaffList/CustomerList微信行切新页)+useStaffProfile缓存+StatsPane固定列/金额格式+vitest依赖化
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
import { ref, watch, type Ref } from 'vue'
|
||||
import { getAccounts } from '@/api'
|
||||
import type { Account } from '@/api/types'
|
||||
|
||||
/**
|
||||
* 员工资料(模块级缓存,全 app 一份请求)。avatar/nickname/phone 等。
|
||||
*
|
||||
* StaffChat(资料卡)与 StatsPane(员工微信列)原先各持一份相同的
|
||||
* getAccounts(wechat, 100) + find 实现——提取为 composable 并加模块级缓存。
|
||||
* 一次响应的 100 条整页入缓存,同页其它员工切换 owner 直接命中不再请求;
|
||||
* 未命中/失败写 null(负缓存),避免重复打失败请求。
|
||||
*/
|
||||
const cache = new Map<string, Account | null>()
|
||||
|
||||
/** 命中缓存直接回调;否则请求一页 wechat 账号,整页回写缓存后回调。 */
|
||||
async function fetchProfile(ownerId: string, apply: (a: Account | null) => void): Promise<void> {
|
||||
if (cache.has(ownerId)) {
|
||||
apply(cache.get(ownerId) ?? null)
|
||||
return
|
||||
}
|
||||
try {
|
||||
const res = await getAccounts({ channel: 'wechat', page: 1, page_size: 100 })
|
||||
for (const a of res.items) cache.set(a.account_id, a)
|
||||
// find 不到也写 null(负缓存)
|
||||
const hit = cache.get(ownerId) ?? null
|
||||
cache.set(ownerId, hit)
|
||||
apply(hit)
|
||||
} catch {
|
||||
cache.set(ownerId, null)
|
||||
apply(null)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ownerId 员工 account_id(wxid);响应式传入时自动随变更重载
|
||||
* @returns profile 资料卡(null=未命中/失败,调用方自行兜底显示 ownerId);
|
||||
* load 手动重载入口(watch immediate 已覆盖常规场景,一般无需调用)
|
||||
*/
|
||||
export function useStaffProfile(ownerId: string | Ref<string>): {
|
||||
profile: Ref<Account | null>
|
||||
load: () => void
|
||||
} {
|
||||
const idRef = typeof ownerId === 'string' ? ref(ownerId) : ownerId
|
||||
const profile = ref<Account | null>(cache.get(idRef.value) ?? null)
|
||||
// token 守卫: ownerId 快速切换时,旧 in-flight 响应不回写新 profile
|
||||
let token = 0
|
||||
|
||||
function load(): void {
|
||||
const my = ++token
|
||||
const id = idRef.value
|
||||
void fetchProfile(id, (a) => {
|
||||
if (my === token) profile.value = a
|
||||
})
|
||||
}
|
||||
|
||||
watch(idRef, load, { immediate: true })
|
||||
return { profile, load }
|
||||
}
|
||||
Reference in New Issue
Block a user