81413e4d08
Co-authored-by: Cursor <cursoragent@cursor.com>
89 lines
2.8 KiB
TypeScript
89 lines
2.8 KiB
TypeScript
import { getRuntimePlatform } from './env';
|
|
import { ensureJssdkReady } from './jssdk';
|
|
import type { WeixinSdkConfig } from './types';
|
|
|
|
export type ChooseWechatImageOptions = {
|
|
count?: number;
|
|
sourceType?: Array<'album' | 'camera'>;
|
|
};
|
|
|
|
function base64ToFile(base64: string, fileName: string): File {
|
|
const normalized = base64.startsWith('data:')
|
|
? base64
|
|
: `data:image/jpeg;base64,${base64.replace(/\s/g, '')}`;
|
|
const [header, body] = normalized.split(',');
|
|
const mime = header.match(/:(.*?);/)?.[1] ?? 'image/jpeg';
|
|
const binary = atob(body);
|
|
const bytes = new Uint8Array(binary.length);
|
|
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
|
|
return new File([bytes], fileName, { type: mime });
|
|
}
|
|
|
|
function localIdToFile(localId: string): Promise<File> {
|
|
return new Promise((resolve, reject) => {
|
|
if (!window.wx?.getLocalImgData) {
|
|
reject(new Error('微信 getLocalImgData 不可用'));
|
|
return;
|
|
}
|
|
window.wx.getLocalImgData({
|
|
localId,
|
|
success: (res) => {
|
|
try {
|
|
resolve(base64ToFile(res.localData, `wx-${Date.now()}.jpg`));
|
|
} catch (e) {
|
|
reject(e instanceof Error ? e : new Error('图片解析失败'));
|
|
}
|
|
},
|
|
fail: (err) => reject(new Error(err.errMsg || '读取图片失败')),
|
|
});
|
|
});
|
|
}
|
|
|
|
/** 微信内选图(相册/拍照),返回 File 列表;非微信环境返回 null */
|
|
export async function chooseWechatImages(
|
|
config: WeixinSdkConfig,
|
|
options: ChooseWechatImageOptions = {},
|
|
): Promise<File[] | null> {
|
|
const platform = getRuntimePlatform();
|
|
if (platform === 'browser') return null;
|
|
|
|
const count = options.count ?? 1;
|
|
const sourceType = options.sourceType ?? ['album', 'camera'];
|
|
|
|
if (platform === 'wechat-h5') {
|
|
const pageUrl = typeof window !== 'undefined' ? window.location.href.split('#')[0] : '';
|
|
await ensureJssdkReady({
|
|
apiBase: config.apiBase ?? '/api/v1',
|
|
clientApp: config.clientApp,
|
|
getAccessToken: config.getAccessToken,
|
|
url: pageUrl,
|
|
jsApiList: ['chooseImage', 'getLocalImgData'],
|
|
});
|
|
if (!window.wx?.chooseImage) {
|
|
throw new Error('微信选图接口不可用,请刷新页面后重试');
|
|
}
|
|
|
|
const localIds = await new Promise<string[]>((resolve, reject) => {
|
|
window.wx!.chooseImage!({
|
|
count,
|
|
sizeType: ['compressed'],
|
|
sourceType,
|
|
success: (res) => resolve(res.localIds ?? []),
|
|
fail: (err) => reject(new Error(err.errMsg || '无法打开相册')),
|
|
});
|
|
});
|
|
|
|
const files: File[] = [];
|
|
for (const localId of localIds) {
|
|
files.push(await localIdToFile(localId));
|
|
}
|
|
return files;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
export function canUseWechatChooseImage(): boolean {
|
|
return getRuntimePlatform() !== 'browser';
|
|
}
|