/**
* 微信开放标签封装组件
* 用于在微信内 H5 跳转小程序
*/
import React, { useState, useEffect, useCallback, useRef } from 'react';
import { Box, Spinner, Text, Button as ChakraButton } from '@chakra-ui/react';
import { getJsSdkConfig } from '@services/miniprogramService';
// 小程序原始 ID
const MINIPROGRAM_ORIGINAL_ID = 'gh_fd2fd8dd2fb5';
/**
* 微信开放标签组件
* @param {Object} props
* @param {string} [props.path] - 小程序页面路径
* @param {string} [props.query] - 页面参数
* @param {React.ReactNode} props.children - 按钮内容
* @param {Function} [props.onLaunch] - 跳转成功回调
* @param {Function} [props.onError] - 跳转失败回调
* @param {Object} [props.buttonStyle] - 按钮样式
*/
const WxOpenLaunchWeapp = ({
path = '',
query = '',
children,
onLaunch,
onError,
buttonStyle = {},
}) => {
const [ready, setReady] = useState(false);
const [error, setError] = useState(null);
const [loading, setLoading] = useState(true);
const launchBtnRef = useRef(null);
// 初始化微信 JS-SDK
const initWxSdk = useCallback(async () => {
try {
setLoading(true);
setError(null);
// 获取当前页面 URL(不含 hash)
const currentUrl = window.location.href.split('#')[0];
// 获取签名配置
const config = await getJsSdkConfig(currentUrl);
if (!config) {
throw new Error('获取签名配置失败');
}
// 检查 wx 对象是否存在
if (typeof wx === 'undefined') {
throw new Error('微信 JS-SDK 未加载');
}
// 配置 wx
wx.config({
debug: false,
appId: config.appId,
timestamp: config.timestamp,
nonceStr: config.nonceStr,
signature: config.signature,
jsApiList: config.jsApiList || [],
openTagList: config.openTagList || ['wx-open-launch-weapp'],
});
// 监听 ready 事件
wx.ready(() => {
console.log('[WxOpenLaunchWeapp] wx.ready');
setReady(true);
setLoading(false);
});
// 监听 error 事件
wx.error((err) => {
console.error('[WxOpenLaunchWeapp] wx.error:', err);
setError(err.errMsg || '初始化失败');
setLoading(false);
});
} catch (err) {
console.error('[WxOpenLaunchWeapp] initWxSdk error:', err);
setError(err.message || '初始化失败');
setLoading(false);
}
}, []);
useEffect(() => {
initWxSdk();
}, [initWxSdk]);
// 监听开放标签事件
useEffect(() => {
const btn = launchBtnRef.current;
if (!btn) return;
const handleLaunch = (e) => {
console.log('[WxOpenLaunchWeapp] launch success:', e.detail);
onLaunch?.(e.detail);
};
const handleError = (e) => {
console.error('[WxOpenLaunchWeapp] launch error:', e.detail);
onError?.(e.detail);
};
btn.addEventListener('launch', handleLaunch);
btn.addEventListener('error', handleError);
return () => {
btn.removeEventListener('launch', handleLaunch);
btn.removeEventListener('error', handleError);
};
}, [ready, onLaunch, onError]);
// 构建小程序路径
const mpPath = query ? `${path}?${query}` : path;
// 默认按钮样式
const defaultButtonStyle = {
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
padding: '12px 24px',
backgroundColor: '#07c160',
color: '#ffffff',
fontSize: '16px',
fontWeight: '500',
borderRadius: '8px',
border: 'none',
cursor: 'pointer',
width: '100%',
...buttonStyle,
};
// 加载中状态
if (loading) {
return (
正在初始化...
);
}
// 错误状态
if (error) {
return (
{error}
);
}
// 渲染开放标签
if (ready) {
// 微信开放标签需要使用纯 HTML 字符串,不支持 JSX
const buttonText = typeof children === 'string' ? children : '打开小程序';
const htmlContent = `
`;
return (
);
}
return null;
};
export default WxOpenLaunchWeapp;