import Taro from '@tarojs/taro'; import type { UserProfile } from './api'; export type MiniWechatProfile = { nickname?: string; avatarUrl?: string; }; export type MiniWechatProfileUpdate = MiniWechatProfile & { avatarResourceId?: string; }; export type UploadedAvatarResource = { resourceId: string; url: string; bucket: string; ossKey: string; }; const WX_PROFILE_CACHE_KEY = 'wx_mini_profile_cache'; export function cacheWxProfile(info: MiniWechatProfile) { if (!info.nickname && !info.avatarUrl) return; try { Taro.setStorageSync(WX_PROFILE_CACHE_KEY, JSON.stringify(info)); } catch { /* ignore */ } } export function getCachedWxProfile(): MiniWechatProfile | null { try { const raw = Taro.getStorageSync(WX_PROFILE_CACHE_KEY); if (!raw) return null; const parsed = JSON.parse(String(raw)) as MiniWechatProfile; if (!parsed?.nickname && !parsed?.avatarUrl) return null; return parsed; } catch { return null; } } export function isDefaultMiniNickname(nickname?: string | null): boolean { if (!nickname || nickname === '访客' || nickname === '微信用户' || nickname === '用户') return true; return /^用户\d{4}$/.test(nickname); } /** 是否缺少可展示的微信头像/昵称(需走 chooseAvatar + nickname 填写) */ export function needsWxProfileFill(profile: UserProfile | null | undefined): boolean { if (!profile) return true; return !profile.avatarUrl || isDefaultMiniNickname(profile.nickname); } export function mergeWxDisplayProfile(profile: UserProfile): UserProfile { const cached = getCachedWxProfile(); if (!cached && !profile.hasWechat) return profile; const nickname = (!isDefaultMiniNickname(profile.nickname) ? profile.nickname : undefined) || cached?.nickname || profile.nickname || '微信用户'; return { ...profile, nickname, avatarUrl: profile.avatarUrl || cached?.avatarUrl || null, }; } /** 上传 chooseAvatar 临时文件到 OSS,并返回已登记到当前用户的真实资源。 */ export async function uploadAvatarTempFile(tempFilePath: string): Promise { const { API_BASE, CLIENT_APP, getToken } = await import('./api'); const { compressWeappImageIfNeeded } = await import('./compress-image'); const token = getToken(); if (!token) throw new Error('请先登录'); const filePath = await compressWeappImageIfNeeded(tempFilePath); const res = await Taro.uploadFile({ url: `${API_BASE}/common/resources/upload`, filePath, name: 'file', formData: { bizType: 'AVATAR', mediaType: 'IMAGE', }, header: { Authorization: `Bearer ${token}`, 'X-Client-App': CLIENT_APP, }, }); let body: { code?: number; message?: string; data?: { resourceId?: string; url?: string; bucket?: string; ossKey?: string }; } = {}; try { body = JSON.parse(String(res.data || '{}')) as typeof body; } catch { throw new Error('头像上传响应异常'); } if (res.statusCode === 401 || body.code === 401) { throw new Error(body.message || '登录已过期,请重新登录'); } if ( res.statusCode >= 400 || body.code !== 0 || !body.data?.resourceId || !body.data.url || !body.data.bucket || !body.data.ossKey ) { throw new Error(body.message || '头像上传失败'); } return { resourceId: body.data.resourceId, url: body.data.url, bucket: body.data.bucket, ossKey: body.data.ossKey, }; } export async function uploadMiniWechatProfile(info: MiniWechatProfileUpdate): Promise { if (!info.nickname && !info.avatarUrl && !info.avatarResourceId) return null; const { request } = await import('./api'); const updated = await request('/auth/wechat/mini-profile', { method: 'POST', data: info, }); cacheWxProfile({ nickname: updated?.nickname ?? info.nickname, avatarUrl: updated?.avatarUrl ?? info.avatarUrl, }); return updated; } /** * 兼容旧调用:getUserProfile 已无法拿到真实头像昵称。 * 始终导出为函数,避免循环依赖/旧包出现 “is not a function”。 */ export async function fetchMiniWechatUserInfo(): Promise { const cached = getCachedWxProfile(); if (cached?.nickname || cached?.avatarUrl) { return cached; } // 不再弹 getUserProfile;引导走「我的」页 chooseAvatar / nickname throw new Error('请在「我的」页点击头像完善微信头像和昵称'); } /** 绑定后上报微信资料(优先使用已拉取的信息) */ export async function syncMiniWechatProfile( prefetched?: MiniWechatProfile | null, ): Promise { if (process.env.TARO_ENV !== 'weapp') return null; const info = prefetched?.nickname || prefetched?.avatarUrl ? prefetched : getCachedWxProfile(); if (!info?.nickname && !info?.avatarUrl) return null; // 缓存头像 URL 可能来自历史微信资料,未经过当前 OSS 上传登记;这里只同步昵称。 if (info.nickname) await uploadMiniWechatProfile({ nickname: info.nickname }); return info; }