demo-game.html 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. <!DOCTYPE html>
  2. <html lang="zh-CN">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
  6. <title>演示游戏内嵌页</title>
  7. <!-- Tailwind for quick styling inside iframe -->
  8. <script src="https://cdn.tailwindcss.com"></script>
  9. <!-- Import SDK -->
  10. <script src="/game-sdk.js"></script>
  11. <style>
  12. body {
  13. background-color: #f8fafc;
  14. font-family: system-ui, -apple-system, sans-serif;
  15. }
  16. </style>
  17. </head>
  18. <body class="p-4 flex flex-col min-h-screen">
  19. <div class="text-center mb-8 mt-4">
  20. <div class="inline-block p-3 rounded-full bg-indigo-100 text-indigo-600 mb-3">
  21. <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" fill="none"
  22. stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  23. <rect x="2" y="6" width="20" height="12" rx="2" />
  24. <path d="M6 12h4" />
  25. <path d="M8 10v4" />
  26. <path d="M15 13h.01" />
  27. <path d="M18 11h.01" />
  28. </svg>
  29. </div>
  30. <h1 class="text-2xl font-bold text-slate-800">异界修仙传 H5</h1>
  31. <p class="text-slate-500 text-sm mt-1">游戏客户端 (Iframe内)</p>
  32. </div>
  33. <div class="space-y-4 flex-1">
  34. <!-- 初始化模块 -->
  35. <div class="bg-white p-5 rounded-2xl shadow-sm border border-slate-100">
  36. <div class="flex justify-between items-center mb-3">
  37. <h2 class="font-semibold text-slate-700">1. 初始化模块</h2>
  38. </div>
  39. <button id="btn-init"
  40. 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">
  41. 调用 SDK 初始化
  42. </button>
  43. <div id="init-res" class="mt-3 text-xs text-slate-600 bg-slate-50 p-2 rounded hidden break-all"></div>
  44. </div>
  45. <!-- 登录模块 -->
  46. <div class="bg-white p-5 rounded-2xl shadow-sm border border-slate-100">
  47. <div class="flex justify-between items-center mb-3">
  48. <h2 class="font-semibold text-slate-700">2. 登录模块</h2>
  49. <span id="login-status" class="text-xs px-2 py-1 rounded-full bg-slate-100 text-slate-500">未登录</span>
  50. </div>
  51. <button id="btn-login"
  52. 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">
  53. 调用 SDK 登录
  54. </button>
  55. <div id="login-res" class="mt-3 text-xs text-slate-600 bg-slate-50 p-2 rounded hidden break-all"></div>
  56. </div>
  57. <!-- 支付模块 -->
  58. <div class="bg-white p-5 rounded-2xl shadow-sm border border-slate-100">
  59. <div class="flex justify-between items-center mb-3">
  60. <h2 class="font-semibold text-slate-700">3. 支付模块</h2>
  61. </div>
  62. <button id="btn-pay"
  63. 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">
  64. 购买「绝世神兵」(¥99)
  65. </button>
  66. <div id="pay-res" class="mt-3 text-xs text-slate-600 bg-slate-50 p-2 rounded hidden break-all"></div>
  67. </div>
  68. <!-- 数据上报模块 -->
  69. <div class="bg-white p-5 rounded-2xl shadow-sm border border-slate-100">
  70. <div class="flex justify-between items-center mb-3">
  71. <h2 class="font-semibold text-slate-700">4. 数据上报</h2>
  72. </div>
  73. <button id="btn-report"
  74. 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">
  75. 上报「角色升级」事件
  76. </button>
  77. <div id="report-res" class="mt-3 text-xs text-slate-600 bg-slate-50 p-2 rounded hidden break-all"></div>
  78. </div>
  79. <!-- 退出登录模块 -->
  80. <div class="bg-white p-5 rounded-2xl shadow-sm border border-slate-100">
  81. <div class="flex justify-between items-center mb-3">
  82. <h2 class="font-semibold text-slate-700">5. 退出登录</h2>
  83. </div>
  84. <button id="btn-logout"
  85. 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">
  86. 退出登录
  87. </button>
  88. <div id="logout-res" class="mt-3 text-xs text-slate-600 bg-slate-50 p-2 rounded hidden break-all"></div>
  89. </div>
  90. </div>
  91. <script>
  92. // 绑定事件到 GameSDK
  93. document.addEventListener('DOMContentLoaded', () => {
  94. const setLog = (id, result, isError = false) => {
  95. const el = document.getElementById(id);
  96. el.classList.remove('hidden');
  97. el.className = `mt-3 text-xs p-3 rounded break-all border ${isError ? 'bg-red-50 text-red-600 border-red-100' : 'bg-emerald-50 text-emerald-700 border-emerald-100'}`;
  98. el.textContent = typeof result === 'object' ? JSON.stringify(result, null, 2) : result;
  99. };
  100. // 1. 初始化
  101. document.getElementById('btn-init').addEventListener('click', async () => {
  102. const btn = document.getElementById('btn-init');
  103. btn.disabled = true;
  104. btn.innerHTML = '初始化中...';
  105. try {
  106. // 调用全局注入的 GameSDK,返回 Promise 并等待
  107. const result = await GameSDK.init({ version: '1.0.0' });
  108. setLog('init-res', result);
  109. btn.innerHTML = '初始化成功';
  110. 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. } catch (error) {
  112. setLog('init-res', error.message, true);
  113. btn.disabled = false;
  114. btn.innerHTML = '调用 SDK 初始化';
  115. }
  116. });
  117. // 2. 登录
  118. document.getElementById('btn-login').addEventListener('click', async () => {
  119. const btn = document.getElementById('btn-login');
  120. const status = document.getElementById('login-status');
  121. btn.disabled = true;
  122. btn.innerHTML = '登录中...';
  123. try {
  124. // 调用全局注入的 GameSDK,返回 Promise 并等待
  125. const result = await GameSDK.login();
  126. setLog('login-res', result);
  127. status.textContent = '已登录';
  128. status.className = 'text-xs px-2 py-1 rounded-full bg-emerald-100 text-emerald-600 font-medium';
  129. btn.innerHTML = `你好, ${result.username}`;
  130. btn.className = 'w-full py-3 bg-slate-100 text-slate-400 rounded-xl font-medium';
  131. } catch (error) {
  132. setLog('login-res', error.message, true);
  133. btn.disabled = false;
  134. btn.innerHTML = '调用 SDK 登录';
  135. }
  136. });
  137. // 2. 支付
  138. document.getElementById('btn-pay').addEventListener('click', async () => {
  139. const btn = document.getElementById('btn-pay');
  140. const originalText = btn.innerHTML;
  141. btn.disabled = true;
  142. btn.innerHTML = '支付中...';
  143. try {
  144. const result = await GameSDK.pay({
  145. cp_order_id: String(new Date().getTime() / 1000),
  146. server_id: '1',
  147. server_name: '服务器1',
  148. role_id: '1000001',
  149. role_name: '角色1',
  150. money: '1', // 元
  151. product_id: '1',
  152. product_name: '商品1',
  153. ext: '11111111'
  154. });
  155. setLog('pay-res', result);
  156. } catch (error) {
  157. setLog('pay-res', error.message, true);
  158. } finally {
  159. btn.disabled = false;
  160. btn.innerHTML = originalText;
  161. }
  162. });
  163. // 3. 上报
  164. document.getElementById('btn-report').addEventListener('click', async () => {
  165. const btn = document.getElementById('btn-report');
  166. const originalText = btn.innerHTML;
  167. btn.disabled = true;
  168. btn.innerHTML = '上报中...';
  169. try {
  170. const result = await GameSDK.report({
  171. data_type: 1,
  172. server_id: 2002,
  173. server_name: '服务器1',
  174. role_id: '1000001',
  175. role_name: '角色1',
  176. role_level: '1'
  177. });
  178. setLog('report-res', result);
  179. } catch (error) {
  180. setLog('report-res', error.message, true);
  181. } finally {
  182. btn.disabled = false;
  183. btn.innerHTML = originalText;
  184. }
  185. });
  186. // 4. 退出登录
  187. document.getElementById('btn-logout').addEventListener('click', async () => {
  188. const btn = document.getElementById('btn-logout');
  189. const originalText = btn.innerHTML;
  190. btn.disabled = true;
  191. btn.innerHTML = '退出登录中...';
  192. try {
  193. const result = await GameSDK.logout();
  194. if (result.success) {
  195. GameSDK.init({ version: '1.0.0' })
  196. GameSDK.login()
  197. }
  198. setLog('logout-res', result);
  199. } catch (error) {
  200. setLog('logout-res', error.message, true);
  201. }
  202. })
  203. // 监听来自 SDK 的消息(使用封装好的 onLogout 方法)
  204. GameSDK.onLogout().then(res => {
  205. if (res.success) {
  206. const btn = document.getElementById('btn-login');
  207. const status = document.getElementById('login-status');
  208. const resLog = document.getElementById('login-res');
  209. // 重置登录按钮和状态
  210. btn.disabled = false;
  211. btn.innerHTML = '调用 SDK 登录';
  212. 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';
  213. status.textContent = '未登录';
  214. status.className = 'text-xs px-2 py-1 rounded-full bg-slate-100 text-slate-500';
  215. // 隐藏/清除日志
  216. resLog.classList.add('hidden');
  217. resLog.textContent = '';
  218. console.log('游戏收到通知 (通过 GameSDK.onLogout):退出登录成功,已重置 UI');
  219. }
  220. })
  221. });
  222. </script>
  223. </body>
  224. </html>