9a3ccabcc9
CI / verify (pull_request) Has been cancelled
Co-authored-by: Cursor <cursoragent@cursor.com>
173 lines
4.6 KiB
TypeScript
173 lines
4.6 KiB
TypeScript
import { ensureJssdkReady, normalizeJssdkPageUrl } from './jssdk';
|
|
import { getRuntimePlatform, isWechatBrowser } from './env';
|
|
import type { WeixinSdkConfig } from './types';
|
|
|
|
export type WechatShareData = {
|
|
title: string;
|
|
desc: string;
|
|
link: string;
|
|
imgUrl: string;
|
|
};
|
|
|
|
export function canUseWechatShare(): boolean {
|
|
return isWechatBrowser() || getRuntimePlatform() === 'mini';
|
|
}
|
|
|
|
function applyShareData(data: WechatShareData): Promise<void> {
|
|
return new Promise((resolve, reject) => {
|
|
const wx = window.wx as
|
|
| (NonNullable<typeof window.wx> & {
|
|
onMenuShareAppMessage?: (opts: Record<string, unknown>) => void;
|
|
onMenuShareTimeline?: (opts: Record<string, unknown>) => void;
|
|
invoke?: (
|
|
api: string,
|
|
params: Record<string, unknown>,
|
|
cb?: (res: { err_msg?: string; errMsg?: string }) => void,
|
|
) => void;
|
|
})
|
|
| undefined;
|
|
|
|
if (!wx) {
|
|
reject(new Error('微信 JSSDK 不可用'));
|
|
return;
|
|
}
|
|
|
|
let pending = 0;
|
|
let failed = false;
|
|
const done = (err?: Error) => {
|
|
if (err && !failed) {
|
|
failed = true;
|
|
reject(err);
|
|
return;
|
|
}
|
|
pending -= 1;
|
|
if (pending === 0 && !failed) resolve();
|
|
};
|
|
|
|
const payload = {
|
|
title: data.title,
|
|
desc: data.desc,
|
|
link: data.link,
|
|
imgUrl: data.imgUrl,
|
|
};
|
|
|
|
if (wx.updateAppMessageShareData) {
|
|
pending += 1;
|
|
wx.updateAppMessageShareData({
|
|
...payload,
|
|
success: () => done(),
|
|
fail: (res) => done(new Error(res.errMsg || '设置分享给朋友失败')),
|
|
});
|
|
}
|
|
|
|
if (wx.updateTimelineShareData) {
|
|
pending += 1;
|
|
wx.updateTimelineShareData({
|
|
title: data.title,
|
|
link: data.link,
|
|
imgUrl: data.imgUrl,
|
|
success: () => done(),
|
|
fail: (res) => done(new Error(res.errMsg || '设置分享到朋友圈失败')),
|
|
});
|
|
}
|
|
|
|
// 兼容旧微信:同时挂旧版菜单分享(设置即生效,无 success 回调也可继续)
|
|
if (wx.onMenuShareAppMessage) {
|
|
wx.onMenuShareAppMessage({
|
|
...payload,
|
|
success: () => {},
|
|
cancel: () => {},
|
|
});
|
|
}
|
|
if (wx.onMenuShareTimeline) {
|
|
wx.onMenuShareTimeline({
|
|
title: data.title,
|
|
link: data.link,
|
|
imgUrl: data.imgUrl,
|
|
success: () => {},
|
|
cancel: () => {},
|
|
});
|
|
}
|
|
|
|
if (pending === 0) {
|
|
if (wx.onMenuShareAppMessage || wx.onMenuShareTimeline) {
|
|
resolve();
|
|
return;
|
|
}
|
|
reject(new Error('当前微信版本不支持分享,请升级微信后重试'));
|
|
}
|
|
});
|
|
}
|
|
|
|
/** 尽量调起系统分享面板(部分微信版本支持;失败则仅完成卡片配置) */
|
|
export function tryInvokeSharePanel(data: WechatShareData): Promise<boolean> {
|
|
return new Promise((resolve) => {
|
|
const wx = window.wx as
|
|
| {
|
|
invoke?: (
|
|
api: string,
|
|
params: Record<string, unknown>,
|
|
cb?: (res: { err_msg?: string; errMsg?: string }) => void,
|
|
) => void;
|
|
}
|
|
| undefined;
|
|
if (!wx?.invoke) {
|
|
resolve(false);
|
|
return;
|
|
}
|
|
try {
|
|
wx.invoke(
|
|
'shareAppMessage',
|
|
{
|
|
title: data.title,
|
|
desc: data.desc,
|
|
link: data.link,
|
|
img_url: data.imgUrl,
|
|
imgUrl: data.imgUrl,
|
|
},
|
|
(res) => {
|
|
const msg = `${res?.err_msg || res?.errMsg || ''}`;
|
|
resolve(/:ok\b/i.test(msg));
|
|
},
|
|
);
|
|
} catch {
|
|
resolve(false);
|
|
}
|
|
});
|
|
}
|
|
|
|
/** 配置微信内分享卡片(好友 / 朋友圈) */
|
|
export async function setWechatShareData(
|
|
config: WeixinSdkConfig,
|
|
data: WechatShareData,
|
|
): Promise<void> {
|
|
if (!canUseWechatShare()) return;
|
|
|
|
await ensureJssdkReady({
|
|
apiBase: config.apiBase ?? '/api/v1',
|
|
clientApp: config.clientApp,
|
|
getAccessToken: config.getAccessToken,
|
|
});
|
|
|
|
await applyShareData(data);
|
|
}
|
|
|
|
/**
|
|
* 配置分享并尝试调起分享面板。
|
|
* @returns invoked=true 表示已弹出系统分享;否则需引导用户点右上角
|
|
*/
|
|
export async function shareViaWechatSdk(
|
|
config: WeixinSdkConfig,
|
|
data: WechatShareData,
|
|
): Promise<{ invoked: boolean }> {
|
|
await setWechatShareData(config, data);
|
|
const invoked = await tryInvokeSharePanel(data);
|
|
return { invoked };
|
|
}
|
|
|
|
/** 获取当前页分享链接(去掉 hash、OAuth 回跳参数) */
|
|
export function getWechatShareLink(rawUrl?: string): string {
|
|
if (typeof window === 'undefined') return rawUrl ?? '';
|
|
return normalizeJssdkPageUrl(rawUrl ?? window.location.href);
|
|
}
|