合伙人端开店选照片
This commit is contained in:
@@ -7,6 +7,7 @@ import {
|
||||
needsWechatAuth,
|
||||
type PartnerProfile,
|
||||
} from '../lib/wechat-auth';
|
||||
import { formatChooseImageFailMessage } from '@dukang/weixin-sdk';
|
||||
import { isWechatEnv, weixinSdk } from '../lib/weixin';
|
||||
import type { ClientRuntimeConfig } from '@dukang/shared-types';
|
||||
|
||||
@@ -28,12 +29,11 @@ const DEFAULT_MAX_MB = 10;
|
||||
|
||||
function formatWechatUploadError(e: unknown): string {
|
||||
const msg = e instanceof Error ? e.message : '无法打开相册';
|
||||
const formatted = formatChooseImageFailMessage(msg);
|
||||
if (formatted) return formatted;
|
||||
if (/invalid signature/i.test(msg)) {
|
||||
return '微信 JSSDK 签名校验失败:请确认公众号已配置 JS 接口安全域名为 user.runxian.top,并刷新页面后重试';
|
||||
}
|
||||
if (/permission|denied|拒绝/i.test(msg)) {
|
||||
return '微信选图权限被拒绝,请在微信设置中允许相册/相机访问后重试';
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
@@ -116,9 +116,10 @@ export default function OssUploadField({
|
||||
}
|
||||
|
||||
async function pickWechatImage() {
|
||||
await weixinSdk.init();
|
||||
const files = await weixinSdk.chooseImages({
|
||||
count: 1,
|
||||
sourceType: ['album', 'camera'],
|
||||
sourceType: ['album'],
|
||||
});
|
||||
if (files?.[0]) {
|
||||
await uploadSelectedFile(files[0]);
|
||||
@@ -143,7 +144,6 @@ export default function OssUploadField({
|
||||
const msg = e instanceof Error ? e.message : '无法打开相册';
|
||||
if (/cancel/i.test(msg)) return;
|
||||
setError(formatWechatUploadError(e));
|
||||
openNativeFilePicker();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { getRuntimePlatform } from './env';
|
||||
import { ensureJssdkReady, normalizeJssdkPageUrl, getJssdkSignUrl } from './jssdk';
|
||||
import { getRuntimePlatform, isIosDevice, isWechatDevTools } from './env';
|
||||
import { ensureJssdkReady, normalizeJssdkPageUrl } from './jssdk';
|
||||
import type { WeixinSdkConfig } from './types';
|
||||
|
||||
export type ChooseWechatImageOptions = {
|
||||
@@ -7,6 +7,38 @@ export type ChooseWechatImageOptions = {
|
||||
sourceType?: Array<'album' | 'camera'>;
|
||||
};
|
||||
|
||||
function delay(ms: number): Promise<void> {
|
||||
return new Promise((resolve) => window.setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
/** 将微信 chooseImage / getLocalImgData fail 的 errMsg 转为用户可读文案 */
|
||||
export function formatChooseImageFailMessage(errMsg: string): string {
|
||||
const msg = errMsg.trim() || '无法打开相册';
|
||||
if (/cancel/i.test(msg)) return '';
|
||||
|
||||
if (/offline verifying|permission value is offline/i.test(msg)) {
|
||||
return '微信权限验证中,请稍候再试或刷新页面后重新选择图片';
|
||||
}
|
||||
|
||||
if (/invalid signature|config:fail|signature/i.test(msg)) {
|
||||
return '微信 JSSDK 签名校验失败,请刷新页面后重试';
|
||||
}
|
||||
|
||||
if (/photo.*denied|photos.*denied|相册.*权限|无法访问相册|无相册权限/i.test(msg)) {
|
||||
return '相册权限未开启,请在 iPhone「设置 → 隐私与安全性 → 照片」中允许微信访问相册';
|
||||
}
|
||||
|
||||
if (/system.*camera|camera.*not.*allowed|无法访问相机|无相机权限/i.test(msg)) {
|
||||
return '相机权限未开启,请在 iPhone「设置 → 隐私与安全性 → 相机」中允许微信使用摄像头';
|
||||
}
|
||||
|
||||
if (/permission|auth|denied|授权|拒绝/i.test(msg)) {
|
||||
return `微信选图接口未就绪(${msg}),请刷新页面后重试`;
|
||||
}
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
async function reportChooseImageEvent(
|
||||
config: WeixinSdkConfig,
|
||||
payload: {
|
||||
@@ -67,7 +99,34 @@ function localIdToFile(localId: string): Promise<File> {
|
||||
reject(e instanceof Error ? e : new Error('图片解析失败'));
|
||||
}
|
||||
},
|
||||
fail: (err) => reject(new Error(err.errMsg || '读取图片失败')),
|
||||
fail: (err) => {
|
||||
const raw = err.errMsg || '读取图片失败';
|
||||
const formatted = formatChooseImageFailMessage(raw);
|
||||
reject(new Error(formatted || raw));
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function invokeChooseImage(
|
||||
count: number,
|
||||
sourceType: Array<'album' | 'camera'>,
|
||||
): Promise<string[]> {
|
||||
return new Promise((resolve, reject) => {
|
||||
window.wx!.chooseImage!({
|
||||
count,
|
||||
sizeType: ['compressed'],
|
||||
sourceType,
|
||||
success: (res) => resolve(res.localIds ?? []),
|
||||
fail: (err) => {
|
||||
const raw = err.errMsg || '无法打开相册';
|
||||
if (/cancel/i.test(raw)) {
|
||||
resolve([]);
|
||||
return;
|
||||
}
|
||||
const formatted = formatChooseImageFailMessage(raw);
|
||||
reject(new Error(formatted || raw));
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -84,7 +143,6 @@ export async function chooseWechatImages(
|
||||
const sourceType = options.sourceType ?? ['album', 'camera'];
|
||||
|
||||
if (platform === 'wechat-h5') {
|
||||
const pageUrl = typeof window !== 'undefined' ? getJssdkSignUrl() : '';
|
||||
const sourceTypeKey = sourceType.join(',');
|
||||
try {
|
||||
await ensureJssdkReady({
|
||||
@@ -104,26 +162,38 @@ export async function chooseWechatImages(
|
||||
throw new Error(errMsg);
|
||||
}
|
||||
|
||||
let localIds: string[];
|
||||
try {
|
||||
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 || '无法打开相册')),
|
||||
});
|
||||
});
|
||||
} catch (e) {
|
||||
const errMsg = e instanceof Error ? e.message : '无法打开相册';
|
||||
void reportChooseImageEvent(config, { status: 'fail', errMsg, sourceType: sourceTypeKey, stage: 'choose' });
|
||||
throw e;
|
||||
if (isIosDevice() && !isWechatDevTools()) {
|
||||
await delay(500);
|
||||
}
|
||||
|
||||
let localIds: string[] = [];
|
||||
const maxAttempts = 2;
|
||||
let lastError: Error | null = null;
|
||||
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
||||
if (attempt > 0) {
|
||||
await delay(800);
|
||||
}
|
||||
try {
|
||||
localIds = await invokeChooseImage(count, sourceType);
|
||||
lastError = null;
|
||||
break;
|
||||
} catch (e) {
|
||||
lastError = e instanceof Error ? e : new Error('无法打开相册');
|
||||
const raw = lastError.message;
|
||||
const retryable = /offline verifying|权限验证中|接口未就绪/i.test(raw);
|
||||
if (attempt < maxAttempts - 1 && retryable) continue;
|
||||
void reportChooseImageEvent(config, {
|
||||
status: 'fail',
|
||||
errMsg: raw,
|
||||
sourceType: sourceTypeKey,
|
||||
stage: 'choose',
|
||||
});
|
||||
throw lastError;
|
||||
}
|
||||
}
|
||||
if (lastError) throw lastError;
|
||||
|
||||
if (!localIds.length) {
|
||||
const errMsg = '未选择图片';
|
||||
void reportChooseImageEvent(config, { status: 'fail', errMsg, sourceType: sourceTypeKey, stage: 'empty' });
|
||||
return [];
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ export {
|
||||
export type { WechatLocationOutcome } from './location';
|
||||
export { scanQrCode } from './scan';
|
||||
export { invokeWechatPay } from './pay';
|
||||
export { chooseWechatImages, canUseWechatChooseImage } from './chooseImage';
|
||||
export { chooseWechatImages, canUseWechatChooseImage, formatChooseImageFailMessage } from './chooseImage';
|
||||
export type { ChooseWechatImageOptions } from './chooseImage';
|
||||
export {
|
||||
setWechatShareData,
|
||||
|
||||
Reference in New Issue
Block a user