Files
dukang/apps/mini-user/src/lib/mini-wechat-profile.ts
T

161 lines
5.0 KiB
TypeScript

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<UploadedAvatarResource> {
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<UserProfile | null> {
if (!info.nickname && !info.avatarUrl && !info.avatarResourceId) return null;
const { request } = await import('./api');
const updated = await request<UserProfile>('/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<MiniWechatProfile> {
const cached = getCachedWxProfile();
if (cached?.nickname || cached?.avatarUrl) {
return cached;
}
// 不再弹 getUserProfile;引导走「我的」页 chooseAvatar / nickname
throw new Error('请在「我的」页点击头像完善微信头像和昵称');
}
/** 绑定后上报微信资料(优先使用已拉取的信息) */
export async function syncMiniWechatProfile(
prefetched?: MiniWechatProfile | null,
): Promise<MiniWechatProfile | null> {
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;
}