/** * 微信开放标签封装组件 * 用于在微信内 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 (