瀏覽代碼

添加切换账号

ith5 2 周之前
父節點
當前提交
4bb7b5c525
共有 4 個文件被更改,包括 138 次插入85 次删除
  1. 99 47
      public/demo-game.html
  2. 9 9
      public/game-sdk.js
  3. 5 0
      src/App.tsx
  4. 25 29
      src/components/payment/index.tsx

+ 99 - 47
public/demo-game.html

@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <html lang="zh-CN">
+
 <head>
   <meta charset="UTF-8">
   <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
@@ -15,24 +16,33 @@
     }
   </style>
 </head>
+
 <body class="p-4 flex flex-col min-h-screen">
-  
+
   <div class="text-center mb-8 mt-4">
     <div class="inline-block p-3 rounded-full bg-indigo-100 text-indigo-600 mb-3">
-      <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="6" width="20" height="12" rx="2"/><path d="M6 12h4"/><path d="M8 10v4"/><path d="M15 13h.01"/><path d="M18 11h.01"/></svg>
+      <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" fill="none"
+        stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+        <rect x="2" y="6" width="20" height="12" rx="2" />
+        <path d="M6 12h4" />
+        <path d="M8 10v4" />
+        <path d="M15 13h.01" />
+        <path d="M18 11h.01" />
+      </svg>
     </div>
     <h1 class="text-2xl font-bold text-slate-800">异界修仙传 H5</h1>
     <p class="text-slate-500 text-sm mt-1">游戏客户端 (Iframe内)</p>
   </div>
 
   <div class="space-y-4 flex-1">
-    
+
     <!-- 初始化模块 -->
     <div class="bg-white p-5 rounded-2xl shadow-sm border border-slate-100">
       <div class="flex justify-between items-center mb-3">
         <h2 class="font-semibold text-slate-700">1. 初始化模块</h2>
       </div>
-      <button id="btn-init" class="w-full py-3 bg-blue-600 hover:bg-blue-700 text-white rounded-xl font-medium transition-colors shadow-sm shadow-blue-200 active:scale-95 duration-150">
+      <button id="btn-init"
+        class="w-full py-3 bg-blue-600 hover:bg-blue-700 text-white rounded-xl font-medium transition-colors shadow-sm shadow-blue-200 active:scale-95 duration-150">
         调用 SDK 初始化
       </button>
       <div id="init-res" class="mt-3 text-xs text-slate-600 bg-slate-50 p-2 rounded hidden break-all"></div>
@@ -44,7 +54,8 @@
         <h2 class="font-semibold text-slate-700">2. 登录模块</h2>
         <span id="login-status" class="text-xs px-2 py-1 rounded-full bg-slate-100 text-slate-500">未登录</span>
       </div>
-      <button id="btn-login" class="w-full py-3 bg-blue-600 hover:bg-blue-700 text-white rounded-xl font-medium transition-colors shadow-sm shadow-blue-200 active:scale-95 duration-150">
+      <button id="btn-login"
+        class="w-full py-3 bg-blue-600 hover:bg-blue-700 text-white rounded-xl font-medium transition-colors shadow-sm shadow-blue-200 active:scale-95 duration-150">
         调用 SDK 登录
       </button>
       <div id="login-res" class="mt-3 text-xs text-slate-600 bg-slate-50 p-2 rounded hidden break-all"></div>
@@ -55,7 +66,8 @@
       <div class="flex justify-between items-center mb-3">
         <h2 class="font-semibold text-slate-700">3. 支付模块</h2>
       </div>
-      <button id="btn-pay" class="w-full py-3 bg-emerald-500 hover:bg-emerald-600 text-white rounded-xl font-medium transition-colors shadow-sm shadow-emerald-200 active:scale-95 duration-150">
+      <button id="btn-pay"
+        class="w-full py-3 bg-emerald-500 hover:bg-emerald-600 text-white rounded-xl font-medium transition-colors shadow-sm shadow-emerald-200 active:scale-95 duration-150">
         购买「绝世神兵」(¥99)
       </button>
       <div id="pay-res" class="mt-3 text-xs text-slate-600 bg-slate-50 p-2 rounded hidden break-all"></div>
@@ -66,18 +78,31 @@
       <div class="flex justify-between items-center mb-3">
         <h2 class="font-semibold text-slate-700">4. 数据上报</h2>
       </div>
-      <button id="btn-report" class="w-full py-3 bg-purple-500 hover:bg-purple-600 text-white rounded-xl font-medium transition-colors shadow-sm shadow-purple-200 active:scale-95 duration-150">
+      <button id="btn-report"
+        class="w-full py-3 bg-purple-500 hover:bg-purple-600 text-white rounded-xl font-medium transition-colors shadow-sm shadow-purple-200 active:scale-95 duration-150">
         上报「角色升级」事件
       </button>
       <div id="report-res" class="mt-3 text-xs text-slate-600 bg-slate-50 p-2 rounded hidden break-all"></div>
     </div>
 
+    <!-- 退出登录模块 -->
+    <div class="bg-white p-5 rounded-2xl shadow-sm border border-slate-100">
+      <div class="flex justify-between items-center mb-3">
+        <h2 class="font-semibold text-slate-700">5. 退出登录</h2>
+      </div>
+      <button id="btn-logout"
+        class="w-full py-3 bg-red-500 hover:bg-red-600 text-white rounded-xl font-medium transition-colors shadow-sm shadow-red-200 active:scale-95 duration-150">
+        退出登录
+      </button>
+      <div id="logout-res" class="mt-3 text-xs text-slate-600 bg-slate-50 p-2 rounded hidden break-all"></div>
+    </div>
+
   </div>
 
   <script>
     // 绑定事件到 GameSDK
     document.addEventListener('DOMContentLoaded', () => {
-      
+
       const setLog = (id, result, isError = false) => {
         const el = document.getElementById(id);
         el.classList.remove('hidden');
@@ -90,11 +115,11 @@
         const btn = document.getElementById('btn-init');
         btn.disabled = true;
         btn.innerHTML = '初始化中...';
-        
+
         try {
           // 调用全局注入的 GameSDK,返回 Promise 并等待
-          const result = await GameSDK.init({version:'1.0.0'});
-          
+          const result = await GameSDK.init({ version: '1.0.0' });
+
           setLog('init-res', result);
           btn.innerHTML = '初始化成功';
           btn.className = 'w-full py-3 bg-emerald-600 hover:bg-emerald-700 text-white rounded-xl font-medium transition-colors shadow-sm shadow-emerald-200 active:scale-95 duration-150';
@@ -111,11 +136,11 @@
         const status = document.getElementById('login-status');
         btn.disabled = true;
         btn.innerHTML = '登录中...';
-        
+
         try {
           // 调用全局注入的 GameSDK,返回 Promise 并等待
           const result = await GameSDK.login();
-          
+
           setLog('login-res', result);
           status.textContent = '已登录';
           status.className = 'text-xs px-2 py-1 rounded-full bg-emerald-100 text-emerald-600 font-medium';
@@ -134,21 +159,21 @@
         const originalText = btn.innerHTML;
         btn.disabled = true;
         btn.innerHTML = '支付中...';
-        
+
         try {
           const result = await GameSDK.pay({
-            cp_order_id:String(new Date().getTime()/1000),
-            server_id:'1',
+            cp_order_id: String(new Date().getTime() / 1000),
+            server_id: '1',
             server_name: '服务器1',
-            role_id:'1000001',
-            role_name:'角色1',
-            money:'1', // 元
-            product_id:'1',
-            product_name:'商品1',
-            ext:'11111111'
+            role_id: '1000001',
+            role_name: '角色1',
+            money: '1', // 元
+            product_id: '1',
+            product_name: '商品1',
+            ext: '11111111'
 
           });
-          
+
           setLog('pay-res', result);
         } catch (error) {
           setLog('pay-res', error.message, true);
@@ -164,17 +189,17 @@
         const originalText = btn.innerHTML;
         btn.disabled = true;
         btn.innerHTML = '上报中...';
-        
+
         try {
           const result = await GameSDK.report({
-            data_type: '1',
-            server_id: '1',
+            data_type: 1,
+            server_id: 2002,
             server_name: '服务器1',
             role_id: '1000001',
             role_name: '角色1',
             role_level: '1'
           });
-          
+
           setLog('report-res', result);
         } catch (error) {
           setLog('report-res', error.message, true);
@@ -183,29 +208,56 @@
           btn.innerHTML = originalText;
         }
       });
+      // 4. 退出登录
+      document.getElementById('btn-logout').addEventListener('click', async () => {
+        const btn = document.getElementById('btn-logout');
+        const originalText = btn.innerHTML;
+        btn.disabled = true;
+        btn.innerHTML = '退出登录中...';
+
+        try {
+          const result = await GameSDK.logout();
+          if (result.success) {
+            GameSDK.init({ version: '1.0.0' })
+            GameSDK.login()
+          }
+          setLog('logout-res', result);
+        } catch (error) {
+          setLog('logout-res', error.message, true);
+        }
+      })
+
 
       // 监听来自 SDK 的消息(使用封装好的 onLogout 方法)
-      GameSDK.onLogout(() => {
-        const btn = document.getElementById('btn-login');
-        const status = document.getElementById('login-status');
-        const resLog = document.getElementById('login-res');
-        
-        // 重置登录按钮和状态
-        btn.disabled = false;
-        btn.innerHTML = '调用 SDK 登录';
-        btn.className = 'w-full py-3 bg-blue-600 hover:bg-blue-700 text-white rounded-xl font-medium transition-colors shadow-sm shadow-blue-200 active:scale-95 duration-150';
-        
-        status.textContent = '未登录';
-        status.className = 'text-xs px-2 py-1 rounded-full bg-slate-100 text-slate-500';
-        
-        // 隐藏/清除日志
-        resLog.classList.add('hidden');
-        resLog.textContent = '';
-        
-        console.log('游戏收到通知 (通过 GameSDK.onLogout):退出登录成功,已重置 UI');
-      });
+      GameSDK.onLogout().then(res => {
+        if (res.success) {
+
+          const btn = document.getElementById('btn-login');
+          const status = document.getElementById('login-status');
+          const resLog = document.getElementById('login-res');
+
+          // 重置登录按钮和状态
+          btn.disabled = false;
+          btn.innerHTML = '调用 SDK 登录';
+          btn.className = 'w-full py-3 bg-blue-600 hover:bg-blue-700 text-white rounded-xl font-medium transition-colors shadow-sm shadow-blue-200 active:scale-95 duration-150';
+
+          status.textContent = '未登录';
+          status.className = 'text-xs px-2 py-1 rounded-full bg-slate-100 text-slate-500';
+
+          // 隐藏/清除日志
+          resLog.classList.add('hidden');
+          resLog.textContent = '';
+
+          console.log('游戏收到通知 (通过 GameSDK.onLogout):退出登录成功,已重置 UI');
+
+        }
+      })
+
 
     });
+
+
   </script>
 </body>
-</html>
+
+</html>

+ 9 - 9
public/game-sdk.js

@@ -2,7 +2,7 @@
  * 游戏端 SDK
  * 注入到游戏 iframe 内,封装常用业务 API
  */
-(function() {
+(function () {
   const pendingRequests = new Map();
   let logoutCallback = null;
 
@@ -19,7 +19,7 @@
       if (message && message.requestId) {
         console.log('[SDK] Received message from parent:', message);
         const request = pendingRequests.get(message.requestId);
-        
+
         if (request) {
           if (message.type.endsWith('_SUCCESS')) {
             request.resolve(message.data);
@@ -55,7 +55,7 @@
     /**
      * 退出登录
      */
-    logout: function() {
+    logout: function () {
       return sendRequest('LOGOUT_REQUEST');
     },
 
@@ -63,15 +63,15 @@
      * 监听退出登录回调
      * @param {Function} callback 
      */
-    onLogout: function() {
-     return sendRequest('ONLOGOUT');
+    onLogout: function () {
+      return sendRequest('ONLOGOUT');
     },
 
     /**
      * 调用登录
      * @returns {Promise<{token: string, userId: string, username: string}>}
      */
-    login: function() {
+    login: function () {
       return sendRequest('LOGIN_REQUEST');
     },
 
@@ -83,7 +83,7 @@
      * @param {number} orderInfo.amount 支付金额
      * @returns {Promise<{orderId: string, status: string}>}
      */
-    pay: function(orderInfo) {
+    pay: function (orderInfo) {
       return sendRequest('PAY_REQUEST', orderInfo);
     },
 
@@ -94,7 +94,7 @@
      * @param {string} reportData.payload 上报内容
      * @returns {Promise<{success: boolean}>}
      */
-    report: function(reportData) {
+    report: function (reportData) {
       return sendRequest('REPORT_REQUEST', reportData);
     },
 
@@ -102,7 +102,7 @@
      * 初始化
      * @returns {Promise<{success: boolean}>}
      */
-    init: function(initData) {
+    init: function (initData) {
       return sendRequest('INIT_REQUEST', initData);
     }
   };

+ 5 - 0
src/App.tsx

@@ -90,12 +90,14 @@ function App() {
         nativeLogout(payload)
       } else {
         await logoutApi()
+
         pmBridge.sendToIframe('LOGOUT_REQUEST', { success: true, message: "退出登录成功" }, payload.requestId);
       }
     }
 
     // 处理退出登录回调
     const handleOnLogoutReq = (payload: any) => {
+      console.log("handleOnLogoutReq", payload)
       openModal({ name: 'onLogout', item: { isOpen: false, requestId: payload.requestId, data: payload.data } })
       if (getURLparams('is_native') === 'true') {
         nativeOnLogout(payload)
@@ -114,6 +116,9 @@ function App() {
       eventBus.off('PAY_REQUEST', handlePayReq);
       eventBus.off('REPORT_REQUEST', handleReportReq);
       eventBus.off('INIT_REQUEST', handleInitReq);
+      eventBus.off('LOGOUT_REQUEST', handleLogoutReq);
+      eventBus.off('ONLOGOUT', handleOnLogoutReq);
+
     };
   }, []);
 

+ 25 - 29
src/components/payment/index.tsx

@@ -11,7 +11,7 @@ export const PaymentIndex = () => {
     const [method, setMethod] = useState<'alipay' | 'wechat'>('alipay')
     const [loading, setLoading] = useState(false)
     const [orderId, setOrderId] = useState('')
-    const [payChannel, setPayChannel] = useState<any[]>([])
+    const [payChannel, setPayChannel] = useState<Record<string, any>>({})
 
     const paymentData = modalState.payment.data
 
@@ -23,7 +23,7 @@ export const PaymentIndex = () => {
                     const res: any = await createPaymentOrderApi(paymentData)
                     if (res.order_id) {
                         setOrderId(res.order_id)
-                        setPayChannel(res.pay_channel || [])
+                        setPayChannel(res.pay_channel || {})
                     }
                 } catch (error) {
                     console.error('创建订单失败:', error)
@@ -34,12 +34,12 @@ export const PaymentIndex = () => {
         }
         createOrder()
         const requestId = modalState.payment.requestId;
-        pmBridge.sendToIframe("PAY_SUCCESS", {success:true, message:"支付页面已打开"}, requestId);
+        pmBridge.sendToIframe("PAY_SUCCESS", { success: true, message: "支付页面已打开" }, requestId);
     }, [modalState.payment.isOpen, paymentData, orderId])
 
     const handleClose = () => {
         setOrderId('')
-        setPayChannel([])
+        setPayChannel({})
         openModal({ name: 'payment', item: { isOpen: false } })
     }
 
@@ -48,17 +48,15 @@ export const PaymentIndex = () => {
         setLoading(true)
         try {
             // 根据 method 找到对应的 channel_id
-            const selectedChannel = payChannel.find(c => c.name.includes(method === 'alipay' ? '支付宝' : '微信'))
-            const pay_channel_id = selectedChannel ? selectedChannel.id : (method === 'alipay' ? 'alipay' : 'wechat')
-
+            const pay_channel_method = method === 'alipay' ? 'alipay_wap' : 'wechat_wap'
+            const pay_channel_id = payChannel[pay_channel_method]
             const res: any = await getPaymentLinkApi({
                 order_id: orderId,
-                pay_channel_id: pay_channel_id
+                pay_channel_id: String(pay_channel_id)
             })
 
-
-            if (res.url) {
-                window.location.href = res.url
+            if (res.pay_url) {
+                window.location.href = res.pay_url
             } else {
                 alert('获取支付链接失败')
             }
@@ -77,7 +75,7 @@ export const PaymentIndex = () => {
             <div className="w-full max-w-[350px] mx-5 bg-white dark:bg-slate-900 rounded-xl shadow-2xl overflow-hidden border border-slate-200 dark:border-slate-800">
 
                 <div className="flex items-center bg-white dark:bg-slate-900 p-2 border-b border-slate-100 dark:border-slate-800 justify-between">
-                    <button 
+                    <button
                         onClick={handleClose}
                         className="text-slate-600 dark:text-slate-400 hover:bg-slate-100 dark:hover:bg-slate-800 p-2 rounded-full transition-colors"
                     >
@@ -100,16 +98,15 @@ export const PaymentIndex = () => {
                     <h3 className="text-slate-900 dark:text-slate-100 text-sm font-bold uppercase tracking-wider mb-4">选择支付方式</h3>
                     <div className="flex flex-col gap-3">
 
-                        <label 
+                        <label
                             onClick={() => setMethod('alipay')}
-                            className={`group relative flex items-center gap-4 rounded-xl border-2 p-4 cursor-pointer transition-all ${
-                                method === 'alipay' ? 'border-primary bg-primary/5' : 'border-slate-200 dark:border-slate-800 hover:border-primary/50'
-                            }`}
+                            className={`group relative flex items-center gap-4 rounded-xl border-2 p-4 cursor-pointer transition-all ${method === 'alipay' ? 'border-primary bg-primary/5' : 'border-slate-200 dark:border-slate-800 hover:border-primary/50'
+                                }`}
                         >
-                            <input 
-                                className="h-5 w-5 border-2 border-slate-300 dark:border-slate-600 text-primary focus:ring-primary focus:ring-offset-0" 
-                                name="payment_method" 
-                                type="radio" 
+                            <input
+                                className="h-5 w-5 border-2 border-slate-300 dark:border-slate-600 text-primary focus:ring-primary focus:ring-offset-0"
+                                name="payment_method"
+                                type="radio"
                                 checked={method === 'alipay'}
                                 onChange={() => setMethod('alipay')}
                             />
@@ -121,16 +118,15 @@ export const PaymentIndex = () => {
                             </div>
                         </label>
 
-                        <label 
+                        <label
                             onClick={() => setMethod('wechat')}
-                            className={`group relative flex items-center gap-4 rounded-xl border-2 p-4 cursor-pointer transition-all ${
-                                method === 'wechat' ? 'border-primary bg-primary/5' : 'border-slate-200 dark:border-slate-800 hover:border-primary/50'
-                            }`}
+                            className={`group relative flex items-center gap-4 rounded-xl border-2 p-4 cursor-pointer transition-all ${method === 'wechat' ? 'border-primary bg-primary/5' : 'border-slate-200 dark:border-slate-800 hover:border-primary/50'
+                                }`}
                         >
-                            <input 
-                                className="h-5 w-5 border-2 border-slate-300 dark:border-slate-600 text-primary focus:ring-primary focus:ring-offset-0" 
-                                name="payment_method" 
-                                type="radio" 
+                            <input
+                                className="h-5 w-5 border-2 border-slate-300 dark:border-slate-600 text-primary focus:ring-primary focus:ring-offset-0"
+                                name="payment_method"
+                                type="radio"
                                 checked={method === 'wechat'}
                                 onChange={() => setMethod('wechat')}
                             />
@@ -145,7 +141,7 @@ export const PaymentIndex = () => {
                 </div>
 
                 <div className="p-6 pt-0">
-                    <button 
+                    <button
                         onClick={handlePay}
                         disabled={loading || !orderId}
                         className={`w-full bg-primary hover:bg-primary/90 text-white font-bold py-4 rounded-xl shadow-lg shadow-primary/20 transition-all active:scale-[0.98] ${(loading || !orderId) ? 'opacity-50 cursor-not-allowed' : ''}`}