Kaynağa Gözat

'微端接口'

ith5cn 1 ay önce
ebeveyn
işleme
714976961b

+ 1 - 1
public/demo-game.html

@@ -93,7 +93,7 @@
         
         try {
           // 调用全局注入的 GameSDK,返回 Promise 并等待
-          const result = await GameSDK.init({app_version:'1.0.0'});
+          const result = await GameSDK.init({version:'1.0.0'});
           
           setLog('init-res', result);
           btn.innerHTML = '初始化成功';

+ 11 - 3
public/game-sdk.js

@@ -60,12 +60,20 @@
 
   // 暴露全局对象 GameSDK
   window.GameSDK = {
+
+    /**
+     * 退出登录
+     */
+    logout: function() {
+      return sendRequest('LOGOUT_REQUEST');
+    },
+
     /**
-     * 注册退出登录回调
+     * 监听退出登录回调
      * @param {Function} callback 
      */
-    onLogout: function(callback) {
-      logoutCallback = callback;
+    onLogout: function() {
+     return sendRequest('ONLOGOUT');
     },
 
     /**

+ 52 - 0
public/native-sdk.js

@@ -0,0 +1,52 @@
+
+  /**
+   * 发送消息给 iframe
+   */
+const sendToIframe = (type, data, requestId) {
+if (!this.iframeWindow) {
+    console.warn('[Parent] Cannot send message: iframe not initialized');
+    return;
+}
+
+const message = { type, data, requestId };
+console.log('[Parent] Sending message to iframe:', message);
+this.iframeWindow.postMessage(JSON.stringify(message), this.origin);
+}
+
+
+var INDEX = {
+  init: 0, // 初始化
+  login: 1, // 登录
+  logout: 2, // 登出
+  pay: 3, // 支付
+  report: 4, // 角色上报
+  onLogout: 5, // 浮标个人/账号中心切换账号
+}
+
+
+window.jsBridge({callback:1, param:参数, token:'我给你的原样给我'})
+
+
+window.jsBridge = function (data){
+    const {callback, param, token} = data
+    switch(callback){
+        case INDEX.init:
+            sendToIframe('INIT_REQUEST', param, token)
+            break;
+        case INDEX.login:
+            sendToIframe('LOGIN_REQUEST', param, token)
+            break;
+        case INDEX.logout:
+            sendToIframe('LOGOUT_REQUEST', param, token)
+            break;
+        case INDEX.pay:
+            sendToIframe('PAY_REQUEST', param, token)
+            break;
+        case INDEX.report:
+            sendToIframe('REPORT_REQUEST', param, token)
+            break;
+        case INDEX.onLogout:
+            sendToIframe('ONLOGOUT_REQUEST', param, token)
+            break;
+    }
+}

+ 9 - 1
readme.md

@@ -23,4 +23,12 @@ npm run dev
 
 ```js
 npm run build
-```
+```
+
+## 游戏sdk,给CP调用的JS
+
+存储在`public/game-sdk.js`中
+
+## 微端,给微端调用的JS
+
+存储在`public/native-sdk.js`中

+ 45 - 6
src/App.tsx

@@ -10,10 +10,11 @@ import { report } from './components/report';
 import { getH5GameLinkApi } from './api';
 import { getURLparams } from './utils';
 import { init } from './components/init';
-import { nativeInit } from './components/init/native-init';
+import { nativeInit, nativeLogin, nativePay, nativeReport, nativeLogout, nativeOnLogout } from './native';
 import SlideBarIndex from './components/slide-bar';
 import { FloatingButton } from './components/FloatingButton';
 import { userStateAtom } from './store/user-atom';
+import { logoutApi } from './api/login';
 
 function App() {
   const iframeRef = useRef<HTMLIFrameElement>(null);
@@ -41,34 +42,72 @@ function App() {
   useEffect(() => {
     // 处理登录请求
     const handleLoginReq = (payload: any) => {
-      openModal({name:'login',item:{isOpen:true,requestId:payload.requestId,data:payload.data}})
-      console.log("登录")
+      if(getURLparams('is_native') === 'true'){
+        openModal({name:'login',item:{isOpen:false,requestId:payload.requestId,data:payload.data}})
+        nativeLogin(payload)
+      }else{
+        openModal({name:'login',item:{isOpen:true,requestId:payload.requestId,data:payload.data}})
+        console.log("登录")
+      }
+
     };
 
     // 处理支付请求
     const handlePayReq = (payload: any) => {
-      openModal({name:'payment',item:{isOpen:true,requestId:payload.requestId,data:payload.data}})
+      if(getURLparams('is_native') === 'true'){
+        openModal({name:'payment',item:{isOpen:false,requestId:payload.requestId,data:payload.data}})
+        nativePay(payload)
+      }else{
+        openModal({name:'payment',item:{isOpen:true,requestId:payload.requestId,data:payload.data}})
+      }
     };
 
     // 处理上报请求
     const handleReportReq = (payload: any) => {
-      report(payload)
+      openModal({name:'report',item:{isOpen:true,requestId:payload.requestId,data:payload.data}})
+      if(getURLparams('is_native') === 'true'){
+        nativeReport(payload)
+      }else{
+        report(payload)
+      }
     };
     
     // 处理初始化请求
     const handleInitReq = (payload: any) => {
+      openModal({name:'init',item:{isOpen:true,requestId:payload.requestId,data:payload.data}})
       // 微端是真
       if(getURLparams('is_native') === 'true'){
         nativeInit(payload)
       }else{
         init(payload)
       }
-    }    
+    } 
+
+    // 处理退出登录请求
+    const handleLogoutReq = async (payload: any) => {
+      openModal({name:'logout',item:{isOpen:true,requestId:payload.requestId,data:payload.data}})
+      if(getURLparams('is_native') === 'true'){
+        nativeLogout(payload)
+      }else{
+        await logoutApi()
+        pmBridge.sendToIframe('LOGOUT_REQUEST', {success:true, message:"退出登录成功"}, payload.requestId);
+      }
+    }
+
+    // 处理退出登录回调
+    const handleOnLogoutReq = (payload: any) => {
+      openModal({name:'onLogout',item:{isOpen:false,requestId:payload.requestId,data:payload.data}})
+      if(getURLparams('is_native') === 'true'){
+        nativeOnLogout(payload)
+      }
+    }
 
     eventBus.on('LOGIN_REQUEST', handleLoginReq);
     eventBus.on('PAY_REQUEST', handlePayReq);
     eventBus.on('REPORT_REQUEST', handleReportReq);
     eventBus.on('INIT_REQUEST', handleInitReq);
+    eventBus.on('LOGOUT_REQUEST', handleLogoutReq);
+    eventBus.on('ONLOGOUT', handleOnLogoutReq);
 
     return () => {
       eventBus.off('LOGIN_REQUEST', handleLoginReq);

+ 1 - 2
src/components/init/index.ts

@@ -2,9 +2,8 @@ import { pmBridge } from "../../lib/PostMessageBridge";
 import { initSDKApi } from "../../api";
 
 export const init = async ({data,requestId}: {data: any,requestId: string})=>{
-
     // todo 初始化接口
     await initSDKApi(data)
     // 成功
-     pmBridge.sendToIframe('INIT_SUCCESS', { success: true, message:"初始化成功" }, requestId);
+    pmBridge.sendToIframe('INIT_REQUEST', { success: true, data:"初始化成功" }, requestId);
 }

+ 0 - 11
src/components/init/native-init.ts

@@ -1,11 +0,0 @@
-import { getOS } from "../../utils/common-params"
-
-export const nativeInit = (payload: any) => {
-    if(getOS() === 2){
-        // 如果是IOS
-        let method = {'method':'gameBridge', type:'INIT_REQUEST', data:payload.data, requestId:payload.requestId}
-        window.webkit.messageHandlers.GAMESDK.postMessage(JSON.stringify(method))
-    }else{
-        
-    }
-}

+ 1 - 1
src/components/login/account-login.tsx

@@ -44,7 +44,7 @@ export const AccountLogin = ({ switchPhoneLogin, switchRegister }: AccountLoginP
 
                 // 使用 pmBridge 回传给父 iframe
                 const requestId = modalState.login.requestId
-                pmBridge.sendToIframe("LOGIN SUCCESS", res, requestId)
+                pmBridge.sendToIframe("LOGIN_REQUEST", {success:true, data: res}, requestId)
 
                 // 关闭登录弹窗
                 openModal({ name: 'login', item: { isOpen: false } })

+ 7 - 3
src/components/login/phone-login.tsx

@@ -2,6 +2,9 @@ import { useState, useEffect } from 'react';
 import { loginSendCodeApi, getAccountListByCodeApi } from '../../api/login';
 import { SelectAccount, type Account } from './select-account';
 import { Agreement } from '../agreement';
+import { pmBridge } from '../../lib/PostMessageBridge';
+import { useAtomValue } from 'jotai';
+import { modalStackAtom } from '../../store';
 
 export interface phoneLoginProps {
     switchAccountLogin: () => void;
@@ -9,6 +12,7 @@ export interface phoneLoginProps {
 }
 
 export const PhoneLogin = ({ switchAccountLogin, switchRegister }: phoneLoginProps) => {
+    const modalState = useAtomValue(modalStackAtom);
     const [mobile, setMobile] = useState('');
     const [code, setCode] = useState('');
     const [countdown, setCountdown] = useState(0);
@@ -64,12 +68,13 @@ export const PhoneLogin = ({ switchAccountLogin, switchRegister }: phoneLoginPro
         setLoading(true);
         try {
             const res = await getAccountListByCodeApi({ mobile, code });
-            console.log('验证成功1:', res);
             if (res.length > 0) {
                 setAccountList(res);
                 setShowSelectAccount(true);
             } else {
-                alert('登录成功');
+                alert('登录成功')
+                const requestId = modalState.login.requestId;
+                pmBridge.sendToIframe("LOGIN_REQUEST", {success:true, data: res}, requestId);
             }
         } catch (error: any) {
             console.error('验证失败:', error);
@@ -82,7 +87,6 @@ export const PhoneLogin = ({ switchAccountLogin, switchRegister }: phoneLoginPro
     const handleSelectConfirm = (account: Account) => {
         console.log('选择账号确认:', account);
         setShowSelectAccount(false);
-        alert(`已选择账号: ${account.user_name}`);
     };
 
     return (

+ 1 - 1
src/components/login/select-account.tsx

@@ -47,7 +47,7 @@ export const SelectAccount = ({ mobile, code, accounts, onConfirm, onClose }: Se
                     
                     // 使用 pmBridge 回传给父 iframe
                     const requestId = modalState.login.requestId
-                    pmBridge.sendToIframe("LOGIN SUCCESS", res, requestId)
+                    pmBridge.sendToIframe("LOGIN_REQUEST", {success:true, data: res}, requestId)
 
                     // 关闭登录弹窗
                     openModal({ name: 'login', item: { isOpen: false } })

+ 6 - 2
src/components/payment/index.tsx

@@ -3,6 +3,7 @@ import { useState, useEffect } from "react"
 import { useAtomValue, useSetAtom } from "jotai"
 import { modalStackAtom, openModalAction } from "../../store"
 import { createPaymentOrderApi, getPaymentLinkApi } from "../../api/payment"
+import { pmBridge } from "../../lib/PostMessageBridge"
 
 export const PaymentIndex = () => {
     const modalState = useAtomValue(modalStackAtom)
@@ -32,6 +33,8 @@ export const PaymentIndex = () => {
             }
         }
         createOrder()
+        const requestId = modalState.payment.requestId;
+        pmBridge.sendToIframe("PAY_REQUEST", {success:true, message:"支付页面已打开"}, requestId);
     }, [modalState.payment.isOpen, paymentData, orderId])
 
     const handleClose = () => {
@@ -53,6 +56,7 @@ export const PaymentIndex = () => {
                 pay_channel_id: pay_channel_id
             })
 
+
             if (res.url) {
                 window.location.href = res.url
             } else {
@@ -148,9 +152,9 @@ export const PaymentIndex = () => {
                     >
                         {loading ? '处理中...' : `立即支付 ¥${paymentData?.money || '0.00'}`}
                     </button>
-                    <p className="text-center text-xs text-slate-400 dark:text-slate-500 mt-4">
+                    {/* <p className="text-center text-xs text-slate-400 dark:text-slate-500 mt-4">
                         支付即视为同意 <a className="text-primary hover:underline" href="#">服务协议</a> 与 <a className="text-primary hover:underline" href="#">隐私政策</a>
-                    </p>
+                    </p> */}
                 </div>
             </div>
         </div>

+ 177 - 177
src/components/register/account-register.tsx

@@ -1,177 +1,177 @@
-import { CirclePlay, Send } from "lucide-react";
-import { useState } from "react";
-import { getRandomAccountApi, registerAccountApi } from "../../api/register";
-import { loginAccountApi } from "../../api/login";
-import { useAtomValue, useSetAtom } from "jotai";
-import { modalStackAtom, openModalAction } from "../../store";
-import { pmBridge } from "../../lib/PostMessageBridge";
-
-export interface AccountRegisterProps {
-    switchPhoneRegister: () => void;
-    switchLogin: () => void;
-}
-
-export const AccountRegister = ({ switchPhoneRegister, switchLogin }: AccountRegisterProps) => {
-    const [userName, setUserName] = useState('');
-    const [userPwd, setUserPwd] = useState('');
-    const [loading, setLoading] = useState(false);
-    const [agreed, setAgreed] = useState(false);
-
-    const modalState = useAtomValue(modalStackAtom);
-    const openModal = useSetAtom(openModalAction);
-
-    const handleRandomAccount = async () => {
-        setLoading(true);
-        try {
-            const res = await getRandomAccountApi({ is_activate: 1 });
-            if (res.user_name && res.user_pwd) {
-                setUserName(res.user_name);
-                setUserPwd(res.user_pwd);
-            }
-        } catch (error: any) {
-            console.error('获取随机账号失败:', error);
-            alert(error.message || '获取随机账号失败');
-        } finally {
-            setLoading(false);
-        }
-    };
-
-    const handleRegister = async () => {
-        if (!userName) {
-            alert('请输入账号');
-            return;
-        }
-        if (!userPwd) {
-            alert('请输入密码');
-            return;
-        }
-        if (!agreed) {
-            alert('请先同意服务协议与隐私权政策');
-            return;
-        }
-
-        setLoading(true);
-        try {
-            // 首先执行注册
-            await registerAccountApi({
-                user_name: userName,
-                user_pwd: userPwd
-            });
-
-            // 注册成功后立即执行登录
-            const loginRes = await loginAccountApi({
-                user_name: userName,
-                user_pwd: userPwd
-            });
-
-            if (loginRes.token) {
-                // 存储 token
-                localStorage.setItem('token', loginRes.token);
-
-                // 使用 pmBridge 回传给父 iframe
-                const requestId = modalState.login.requestId;
-                pmBridge.sendToIframe("LOGIN SUCCESS", loginRes, requestId);
-
-                // 关闭登录弹窗
-                openModal({ name: 'login', item: { isOpen: false } });
-            } else {
-                alert('登录失败:未返回 token');
-            }
-        } catch (error: any) {
-            console.error('流程失败:', error);
-            alert(error.message || '操作失败');
-        } finally {
-            setLoading(false);
-        }
-    };
-
-    return (
-        <div className="fixed inset-0 z-[100] flex items-center justify-center bg-black/60 backdrop-blur-sm">
-
-            <div className="w-full max-w-[320px] mx-5 bg-[#f5f7f8] rounded-2xl shadow-2xl overflow-hidden flex flex-col scale-100">
-
-                <div className="flex flex-col items-center pt-4 pb-6 px-6">
-
-                    <h1 className="text-xl font-bold text-slate-900 dark:text-slate-100">创建账号</h1>
-                </div>
-
-                {/* Tabs */}
-                <div className="flex border-b border-slate-200 dark:border-slate-800 px-6 gap-8">
-                    <button onClick={switchPhoneRegister} className="flex flex-col items-center justify-center border-b-[3px] border-transparent text-[#64748b] pb-3 pt-2  hover:text-primary transition-colors">
-                        <p className="text-sm font-bold leading-normal tracking-wide">手机号注册</p>
-                    </button>
-                    <button className="flex flex-col items-center justify-center border-b-[3px] border-primary text-primary pb-3 pt-2">
-                        <p className="text-sm font-bold leading-normal tracking-wide">账号注册</p>
-                    </button>
-                </div>
-
-                {/* Form Content */}
-                <div className="p-6 space-y-4">
-                    {/* Account Input */}
-                    <label className="text-xs font-semibold uppercase tracking-wider text-slate-400 ml-1">账号</label>
-                    <div className="flex gap-2">
-
-                        <div className="flex-1">
-                            <input 
-                                className="p-2 form-input input-field w-full rounded-lg border-slate-200 bg-white text-slate-900 h-12 text-sm" 
-                                placeholder="请输入账号" 
-                                type="text"
-                                value={userName}
-                                onChange={(e) => setUserName(e.target.value)}
-                            />
-                        </div>
-                    </div>
-
-                    {/* Password Input */}
-                    <label className="text-xs font-semibold uppercase tracking-wider text-slate-400 ml-1">密码</label>
-                    <div className="flex gap-2">
-                        <div className="flex-1">
-                            <input 
-                                className="p-2 form-input input-field w-full rounded-lg border-slate-200 bg-white text-slate-900 h-12 text-sm" 
-                                placeholder="请输入密码" 
-                                type="text" 
-                                value={userPwd}
-                                onChange={(e) => setUserPwd(e.target.value)}
-                            />
-                        </div>
-                    </div>
-                    <div className="flex justify-between items-center px-1">
-                        <a className="text-xs text-slate-500 dark:text-slate-400 hover:text-primary transition-colors cursor-pointer" onClick={switchLogin}>已有账号</a>
-                        <a className="text-xs text-slate-500 dark:text-slate-400 hover:text-primary transition-colors" href="#">遇到问题?</a>
-                    </div>
-
-                    {/* Action Button */}
-                    <button 
-                        onClick={handleRegister}
-                        disabled={loading}
-                        className={`w-full bg-primary hover:bg-primary/90 text-white font-bold h-12 rounded-lg shadow-lg  transition-all flex items-center justify-center gap-2 ${loading ? 'opacity-70 cursor-not-allowed' : ''}`}
-                    >
-                        {loading ? '注册中...' : '立即注册并进入游戏'} <CirclePlay size={18} />
-                    </button>
-                    <button 
-                        onClick={handleRandomAccount}
-                        disabled={loading}
-                        className="w-full text-primary font-bold h-12 rounded-lg shadow-lg transition-all flex items-center justify-center gap-2 border border-primary/20 hover:bg-primary/5"
-                    >
-                        <Send size={18} />一键生成账号密码
-                    </button>
-                    {/* Secondary Links */}
-                  
-                    <div className="flex items-center gap-2 px-1 pt-2">
-                        <input 
-                            className="h-4 w-4 rounded border-slate-300 text-primary focus:ring-primary cursor-pointer" 
-                            id="tos" 
-                            type="checkbox" 
-                            checked={agreed}
-                            onChange={(e) => setAgreed(e.target.checked)}
-                        />
-                        <label htmlFor="tos" className="text-xs leading-relaxed text-slate-500 cursor-pointer select-none">
-                            我已阅读并同意 <a className="text-primary hover:underline" href="#">服务协议</a> 与 <a className="text-primary hover:underline" href="#">隐私权政策</a>
-                        </label>
-                    </div>
-                </div>
-
-            </div>
-        </div>
-    );
-}
+import { CirclePlay, Send } from "lucide-react";
+import { useState } from "react";
+import { getRandomAccountApi, registerAccountApi } from "../../api/register";
+import { loginAccountApi } from "../../api/login";
+import { useAtomValue, useSetAtom } from "jotai";
+import { modalStackAtom, openModalAction } from "../../store";
+import { pmBridge } from "../../lib/PostMessageBridge";
+
+export interface AccountRegisterProps {
+    switchPhoneRegister: () => void;
+    switchLogin: () => void;
+}
+
+export const AccountRegister = ({ switchPhoneRegister, switchLogin }: AccountRegisterProps) => {
+    const [userName, setUserName] = useState('');
+    const [userPwd, setUserPwd] = useState('');
+    const [loading, setLoading] = useState(false);
+    const [agreed, setAgreed] = useState(false);
+
+    const modalState = useAtomValue(modalStackAtom);
+    const openModal = useSetAtom(openModalAction);
+
+    const handleRandomAccount = async () => {
+        setLoading(true);
+        try {
+            const res = await getRandomAccountApi({ is_activate: 1 });
+            if (res.user_name && res.user_pwd) {
+                setUserName(res.user_name);
+                setUserPwd(res.user_pwd);
+            }
+        } catch (error: any) {
+            console.error('获取随机账号失败:', error);
+            alert(error.message || '获取随机账号失败');
+        } finally {
+            setLoading(false);
+        }
+    };
+
+    const handleRegister = async () => {
+        if (!userName) {
+            alert('请输入账号');
+            return;
+        }
+        if (!userPwd) {
+            alert('请输入密码');
+            return;
+        }
+        if (!agreed) {
+            alert('请先同意服务协议与隐私权政策');
+            return;
+        }
+
+        setLoading(true);
+        try {
+            // 首先执行注册
+            await registerAccountApi({
+                user_name: userName,
+                user_pwd: userPwd
+            });
+
+            // 注册成功后立即执行登录
+            const loginRes = await loginAccountApi({
+                user_name: userName,
+                user_pwd: userPwd
+            });
+
+            if (loginRes.token) {
+                // 存储 token
+                localStorage.setItem('token', loginRes.token);
+
+                // 使用 pmBridge 回传给父 iframe
+                const requestId = modalState.login.requestId;
+                pmBridge.sendToIframe("LOGIN_REQUEST", {success:true, data: loginRes}, requestId);
+
+                // 关闭登录弹窗
+                openModal({ name: 'login', item: { isOpen: false } });
+            } else {
+                alert('登录失败:未返回 token');
+            }
+        } catch (error: any) {
+            console.error('流程失败:', error);
+            alert(error.message || '操作失败');
+        } finally {
+            setLoading(false);
+        }
+    };
+
+    return (
+        <div className="fixed inset-0 z-[100] flex items-center justify-center bg-black/60 backdrop-blur-sm">
+
+            <div className="w-full max-w-[320px] mx-5 bg-[#f5f7f8] rounded-2xl shadow-2xl overflow-hidden flex flex-col scale-100">
+
+                <div className="flex flex-col items-center pt-4 pb-6 px-6">
+
+                    <h1 className="text-xl font-bold text-slate-900 dark:text-slate-100">创建账号</h1>
+                </div>
+
+                {/* Tabs */}
+                <div className="flex border-b border-slate-200 dark:border-slate-800 px-6 gap-8">
+                    <button onClick={switchPhoneRegister} className="flex flex-col items-center justify-center border-b-[3px] border-transparent text-[#64748b] pb-3 pt-2  hover:text-primary transition-colors">
+                        <p className="text-sm font-bold leading-normal tracking-wide">手机号注册</p>
+                    </button>
+                    <button className="flex flex-col items-center justify-center border-b-[3px] border-primary text-primary pb-3 pt-2">
+                        <p className="text-sm font-bold leading-normal tracking-wide">账号注册</p>
+                    </button>
+                </div>
+
+                {/* Form Content */}
+                <div className="p-6 space-y-4">
+                    {/* Account Input */}
+                    <label className="text-xs font-semibold uppercase tracking-wider text-slate-400 ml-1">账号</label>
+                    <div className="flex gap-2">
+
+                        <div className="flex-1">
+                            <input 
+                                className="p-2 form-input input-field w-full rounded-lg border-slate-200 bg-white text-slate-900 h-12 text-sm" 
+                                placeholder="请输入账号" 
+                                type="text"
+                                value={userName}
+                                onChange={(e) => setUserName(e.target.value)}
+                            />
+                        </div>
+                    </div>
+
+                    {/* Password Input */}
+                    <label className="text-xs font-semibold uppercase tracking-wider text-slate-400 ml-1">密码</label>
+                    <div className="flex gap-2">
+                        <div className="flex-1">
+                            <input 
+                                className="p-2 form-input input-field w-full rounded-lg border-slate-200 bg-white text-slate-900 h-12 text-sm" 
+                                placeholder="请输入密码" 
+                                type="text" 
+                                value={userPwd}
+                                onChange={(e) => setUserPwd(e.target.value)}
+                            />
+                        </div>
+                    </div>
+                    <div className="flex justify-between items-center px-1">
+                        <a className="text-xs text-slate-500 dark:text-slate-400 hover:text-primary transition-colors cursor-pointer" onClick={switchLogin}>已有账号</a>
+                        <a className="text-xs text-slate-500 dark:text-slate-400 hover:text-primary transition-colors" href="#">遇到问题?</a>
+                    </div>
+
+                    {/* Action Button */}
+                    <button 
+                        onClick={handleRegister}
+                        disabled={loading}
+                        className={`w-full bg-primary hover:bg-primary/90 text-white font-bold h-12 rounded-lg shadow-lg  transition-all flex items-center justify-center gap-2 ${loading ? 'opacity-70 cursor-not-allowed' : ''}`}
+                    >
+                        {loading ? '注册中...' : '立即注册并进入游戏'} <CirclePlay size={18} />
+                    </button>
+                    <button 
+                        onClick={handleRandomAccount}
+                        disabled={loading}
+                        className="w-full text-primary font-bold h-12 rounded-lg shadow-lg transition-all flex items-center justify-center gap-2 border border-primary/20 hover:bg-primary/5"
+                    >
+                        <Send size={18} />一键生成账号密码
+                    </button>
+                    {/* Secondary Links */}
+                  
+                    <div className="flex items-center gap-2 px-1 pt-2">
+                        <input 
+                            className="h-4 w-4 rounded border-slate-300 text-primary focus:ring-primary cursor-pointer" 
+                            id="tos" 
+                            type="checkbox" 
+                            checked={agreed}
+                            onChange={(e) => setAgreed(e.target.checked)}
+                        />
+                        <label htmlFor="tos" className="text-xs leading-relaxed text-slate-500 cursor-pointer select-none">
+                            我已阅读并同意 <a className="text-primary hover:underline" href="#">服务协议</a> 与 <a className="text-primary hover:underline" href="#">隐私权政策</a>
+                        </label>
+                    </div>
+                </div>
+
+            </div>
+        </div>
+    );
+}

+ 1 - 1
src/components/register/phone-register.tsx

@@ -51,7 +51,7 @@ export const PhoneRegister = ({ switchAccountRegister, switchLogin }: RegisterPr
         if (res.token) {
             localStorage.setItem('token', res.token);
             const requestId = modalState.login.requestId;
-            pmBridge.sendToIframe("LOGIN SUCCESS", res, requestId);
+            pmBridge.sendToIframe("LOGIN_REQUEST", {success:true, data: res}, requestId);
             openModal({ name: 'login', item: { isOpen: false } });
         } else {
             alert('登录失败:未返回 token');

+ 1 - 1
src/components/report/index.ts

@@ -6,5 +6,5 @@ export const report = async ({data,requestId}: {data: any,requestId: string})=>{
     // todo 上报接口
     await reportRoleApi(data)
     // 成功
-     pmBridge.sendToIframe('REPORT_SUCCESS', { success: true, message:"上报成功" }, requestId);
+     pmBridge.sendToIframe('REPORT_REQUEST', { success: true, message:"上报成功" }, requestId);
 }

+ 7 - 8
src/components/slide-bar/slide-bar.tsx

@@ -2,6 +2,8 @@ import { ChevronRight, IdCard, Key, Smartphone, SquareArrowRightExit } from "luc
 import { logout } from "../../store/user-atom";
 import { pmBridge } from "../../lib/PostMessageBridge";
 import { logoutApi } from "../../api/login";
+import { useAtomValue } from "jotai";
+import { modalStackAtom } from "../../store";
 
 export default function SlideBar({ 
     onChangePassword, 
@@ -23,20 +25,17 @@ export default function SlideBar({
         try {
             // 1. 调用退出登录接口
             await logoutApi();
-        } catch (error) {
-            console.error('Logout API failed:', error);
-        } finally {
-            // 无论接口是否成功,都执行本地清理逻辑
-            
             // 2. 清除本地存储和状态
             logout();
-            
             // 3. 通知父页面(游戏)
-            pmBridge.sendToIframe('LOGOUT SUCCESS');
+            const payload = useAtomValue(modalStackAtom).onLogout;
+            pmBridge.sendToIframe('ONLOGOUT', {success:true, message:"退出登录成功"}, payload.requestId);
 
             // 4. 关闭侧边栏
             onClose();
-        }
+        } catch (error) {
+            console.error('Logout API failed:', error);
+        } 
     };
 
     return (

+ 63 - 0
src/native.ts

@@ -0,0 +1,63 @@
+import { getOS } from "./utils/common-params"
+
+export const nativeInit = (payload: any) => {
+    if(getOS() === 2){
+        // 如果是IOS
+        let method = {'method':'gameBridge', code:0, args:payload.data?JSON.stringify(payload.data):"", token:payload.requestId}
+        window.webkit.messageHandlers.GAMESDK.postMessage(JSON.stringify(method))
+    }else{
+        
+    }
+}
+
+export const nativeLogin = (payload: any) => {
+    if(getOS() === 2){
+        // 如果是IOS
+        let method = {'method':'gameBridge', code:1, args:payload.data?JSON.stringify(payload.data):"", token:payload.requestId}
+        window.webkit.messageHandlers.GAMESDK.postMessage(JSON.stringify(method))
+    }else{
+        
+    }
+}
+
+export const nativePay = (payload: any) => {
+    if(getOS() === 2){
+        // 如果是IOS
+        let method = {'method':'gameBridge', code:3, args:payload.data?JSON.stringify(payload.data):"", token:payload.requestId}
+        window.webkit.messageHandlers.GAMESDK.postMessage(JSON.stringify(method))
+    }else{
+        
+    }
+}
+
+export const nativeReport = (payload: any) => {
+    if(getOS() === 2){
+        // 如果是IOS
+        let method = {'method':'gameBridge', code:4, args:payload.data?JSON.stringify(payload.data):"", token:payload.requestId}
+        window.webkit.messageHandlers.GAMESDK.postMessage(JSON.stringify(method))
+    }else{
+        
+    }
+}
+
+export const nativeLogout = (payload: any) => {
+    if(getOS() === 2){
+        // 如果是IOS
+        let method = {'method':'gameBridge', code:2, args:payload.data?JSON.stringify(payload.data):"", token:payload.requestId}
+        window.webkit.messageHandlers.GAMESDK.postMessage(JSON.stringify(method))
+    }else{
+        
+    }
+}
+
+
+export const nativeOnLogout = (payload: any) => {
+    if(getOS() === 2){
+        // 如果是IOS
+        let method = {'method':'gameBridge', code:5, args:payload.data?JSON.stringify(payload.data):"", token:payload.requestId}
+        window.webkit.messageHandlers.GAMESDK.postMessage(JSON.stringify(method))
+    }else{
+        
+    }
+}
+

+ 4 - 0
src/store/modal-atom.ts

@@ -14,6 +14,8 @@ interface ModalState {
     report: ModalItem;
     realName: ModalItem;
     init: ModalItem;
+    onLogout: ModalItem;
+    logout: ModalItem;
 }
 
 // 原始原子:弹窗状态
@@ -23,6 +25,8 @@ export const modalStackAtom = atom<ModalState>({
     report: { isOpen: false, requestId: '', data: null },
     realName: { isOpen: false, requestId: '', data: null },
     init: { isOpen: true, requestId: '', data: null },
+    onLogout: { isOpen: false, requestId: '', data: null },
+    logout: { isOpen: false, requestId: '', data: null },
     
 });