index.tsx 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. import { App, Empty } from "antd"
  2. import React, { useContext, useEffect, useState } from "react"
  3. import { getGameId, getToken, removeToken } from "../../utils/auth"
  4. import AuthPop from "../authPop"
  5. import BindPhone from "../bindPhone"
  6. import FloatingWindow from "../../components/floatingWindow"
  7. import { DispatchContext } from "../../App"
  8. import UserManage from "./userManage"
  9. import Modify from "../modify"
  10. import { useAjax } from "../../hooks/useAjax"
  11. import { gameRoleEscalationApi, getJsApiPayInfoApi, payPostResultApi, userLogoutApi } from "../../api"
  12. import PayPop from "../payPop"
  13. import { isOs, isWx } from "../../utils"
  14. import WxpcQrCode from "../payPop/wxpcQrCode"
  15. import LoadingPop from "../../components/loadingPop"
  16. import showMessage from "../../components/showMessage"
  17. import showModal from "../../components/showModal"
  18. /**
  19. * 登录成功
  20. * @param param0
  21. * @returns
  22. */
  23. const LoginSucc: React.FC = () => {
  24. /*************************************/
  25. const { dispatch, state: { initData: { h5GameUrl, h5SignShow }, userData, isBind, isAuth, orientation }, getDetails } = useContext(DispatchContext)!;
  26. const { userId, authentication, checkSwitch, bindPhone } = userData
  27. const [open, setOpen] = useState<boolean>(false)
  28. const [openPhone, setOpenPhone] = useState<boolean>(false)
  29. const [openAuth, setOpenAuth] = useState<boolean>(false)
  30. const [openModify, setOpenModify] = useState<boolean>(false)
  31. const [payConfig, setPayConfig] = useState<{ open: boolean, data: any }>({ open: false, data: {} })
  32. const [isClick, setIsClick] = useState<boolean>(false)
  33. const [timerInfo, setTimerInfo] = useState<any>({})
  34. const { message, modal } = App.useApp()
  35. const [htmlpay, setHtmlPay] = useState<string>('')
  36. const [wxPayInfo, setWxPayInfo] = useState<{ qrcode: string, amount: string, open: boolean, orderId: string }>({ qrcode: '', amount: '0.00', open: false, orderId: '' })
  37. const [isLoading, setIsLoading] = useState<boolean>(false)
  38. const [isVer, setIsVer] = useState<boolean>(false)
  39. const gameRoleEscalation = useAjax((params) => gameRoleEscalationApi(params))
  40. const payPostResult = useAjax((params) => payPostResultApi(params))
  41. const getJsApiPayInfo = useAjax((params) => getJsApiPayInfoApi(params))
  42. const userLogout = useAjax(() => userLogoutApi())
  43. /*************************************/
  44. useEffect(() => {
  45. let os = isOs()
  46. if (['ios', 'android'].includes(os) && orientation === 'VERTICAL') {
  47. setIsVer(true)
  48. } else {
  49. setIsVer(false)
  50. }
  51. }, [orientation])
  52. // 上报
  53. const escalation = (data: any) => {
  54. gameRoleEscalation.run(data).then(res => {
  55. if (+res.code === 200) {
  56. console.log('上报成功')
  57. } else {
  58. showMessage.error(res.msg || '上报失败', message)
  59. }
  60. })
  61. }
  62. // 登出
  63. const loginOut = () => {
  64. userLogout.run().then(res => {
  65. if (+res.code === 200) {
  66. removeToken();
  67. window.location.reload()
  68. } else {
  69. showMessage.error(res.msg, message)
  70. }
  71. })
  72. }
  73. useEffect(() => {
  74. const handleMessage = (event: MessageEvent) => {
  75. // 处理收到的消息
  76. let data = event.data
  77. switch (data.type) {
  78. case 'member.init':
  79. (window.frames as any).gameFrame.postMessage({
  80. type: "callback.init",
  81. value: userData
  82. }, "*")
  83. break
  84. case 'member.tips'://弹窗提示
  85. showModal.info({
  86. title: '提示信息',
  87. content: data.data,
  88. modal
  89. })
  90. break
  91. case 'member.pay'://支付
  92. setPayConfig({ open: true, data: data.data })
  93. break
  94. case 'member.uprole': // 上报
  95. escalation(data.data)
  96. break
  97. case 'member.logout': // 登出
  98. loginOut()
  99. break
  100. }
  101. };
  102. window.addEventListener('message', handleMessage);
  103. return () => {
  104. window.removeEventListener('message', handleMessage);
  105. };
  106. }, [userData])
  107. useEffect(() => {
  108. if (authentication === 0 && !isAuth) {
  109. setOpenAuth(true)
  110. setIsClick(false)
  111. } else {
  112. // 是否首次进入弹绑定手机
  113. // if (bindPhone === 0 && !isBind) {
  114. // setOpenPhone(true)
  115. // }
  116. }
  117. }, [bindPhone, authentication, isBind, isAuth])
  118. const setIsBind = () => {
  119. if (!isBind) {
  120. dispatch({ type: 'setIsBind', params: { isBind: true } })
  121. }
  122. }
  123. const setIsAuth = () => {
  124. if (!isAuth) {
  125. dispatch({ type: 'setIsAuth', params: { isAuth: true } })
  126. }
  127. }
  128. const handle = (type: 'BIND' | 'AUTH' | 'MODIFY' | 'LOGOUT') => {
  129. switch (type) {
  130. case 'AUTH':
  131. setIsClick(true)
  132. setOpenAuth(true)
  133. break
  134. case 'BIND':
  135. setOpenPhone(true)
  136. break
  137. case 'MODIFY':
  138. setOpenModify(true)
  139. break
  140. case 'LOGOUT':
  141. loginOut()
  142. break
  143. }
  144. }
  145. /**
  146. * 预下单成功
  147. * @param data
  148. * @param payWay
  149. */
  150. const preOrderSucc = (data: any, payWay: string, payInfo: any) => {
  151. setIsLoading(true)
  152. let orderId = data.orderId
  153. let os = isOs()
  154. payResult(orderId)
  155. if (os === 'windows' || os === 'mac') { // pc
  156. setIsLoading(false)
  157. if (payWay === '1') { // 支付宝
  158. document.querySelector('[name="punchout_form"]')?.remove();
  159. setHtmlPay(data.data.replace('<script>document.forms[0].submit();</script>'))
  160. setTimeout(() => {
  161. document.querySelector('[name="punchout_form"]')?.setAttribute("target", "__blank");
  162. (document.querySelector('[name="punchout_form"]') as any).submit();
  163. }, 100)
  164. } else { // 微信
  165. setWxPayInfo({ open: true, qrcode: data.data, orderId: data.orderId, amount: payInfo.amount })
  166. }
  167. } else if (isWx()) { // 微信jsApi支付
  168. setPayConfig({ open: false, data: {} })
  169. weChatPay(data.openId, data.orderId)
  170. } else { //
  171. setTimeout(() => { setIsLoading(false) }, 2000)
  172. setPayConfig({ open: false, data: {} })
  173. window.location.href = data.data
  174. }
  175. }
  176. // JSAPI支付
  177. const onBridgeReady = (payParam: any) => {
  178. if (payParam) {
  179. let { package: pack, nonceStr, paySign, signType, timeStamp, appId } = JSON.parse(payParam)
  180. // @ts-ignore
  181. WeixinJSBridge.invoke('getBrandWCPayRequest', {
  182. "appId": appId, //公众号ID,由商户传入 -
  183. "timeStamp": timeStamp, //时间戳,自1970年以来的秒数
  184. "nonceStr": nonceStr, //随机串
  185. // @ts-ignore
  186. "package": `prepay_id=${pack.prepay_id}`,
  187. "signType": signType, //微信签名方式:
  188. "paySign": paySign //微信签名
  189. }, (res: any) => {
  190. if (res.err_msg == "get_brand_wcpay_request:ok") {
  191. showModal.success({
  192. title: '支付结果',
  193. content: '支付成功',
  194. modal
  195. })
  196. } else if (res.err_msg == "get_brand_wcpay_request:fail") {
  197. showModal.error({ title: '提示信息', content: '该订单已失效,请回复“2”或游戏内重新下单获取最新支付订单', modal });
  198. }
  199. });
  200. } else {
  201. showModal.error({ title: '提示信息', content: '订单异常,请联系客服重新下单', modal });
  202. }
  203. }
  204. // 客服支付
  205. const weChatPay = (openId: string, orderId: string) => {
  206. getJsApiPayInfo.run({ openId, orderId }).then(res => {
  207. setIsLoading(false)
  208. if (+res.code === 200 && res.data) {
  209. let { payParam } = res.data
  210. // @ts-ignore
  211. if (typeof WeixinJSBridge == "undefined") {
  212. if (document.addEventListener) {
  213. document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
  214. } else if ((document as any).attachEvent) {
  215. (document as any).attachEvent('WeixinJSBridgeReady', onBridgeReady);
  216. (document as any).attachEvent('onWeixinJSBridgeReady', onBridgeReady);
  217. }
  218. } else {
  219. onBridgeReady(payParam)
  220. }
  221. } else {
  222. showMessage.error(res.msg || '该订单已失效,请回复“2”或游戏内重新下单获取最新支付订单', message)
  223. }
  224. })
  225. }
  226. // 支付回调结果
  227. const payResult = (orderId: string) => {
  228. payPostResult.run({ orderId }).then(res => {
  229. if (+res.code === 200) {
  230. if (res.data) {
  231. setPayConfig({ open: false, data: {} })
  232. setWxPayInfo({ qrcode: '', amount: '0.00', open: false, orderId: '' })
  233. showModal.success({
  234. title: '支付结果',
  235. content: '支付成功',
  236. modal
  237. });
  238. } else {
  239. let newtimerInfo = timerInfo
  240. if (newtimerInfo?.[orderId]) {
  241. newtimerInfo[orderId] += 1
  242. } else {
  243. newtimerInfo[orderId] = 1
  244. }
  245. if (newtimerInfo?.[orderId] && newtimerInfo[orderId] < 200) { // 5分钟关闭
  246. setTimeout(() => {
  247. payResult(orderId)
  248. }, 1500)
  249. } else {
  250. delete newtimerInfo[orderId]
  251. }
  252. setTimerInfo(newtimerInfo)
  253. }
  254. } else {
  255. showModal.error({ title: '支付结果', content: res.msg, modal });
  256. }
  257. })
  258. }
  259. if (h5GameUrl) {
  260. let gameUrl = h5GameUrl
  261. if (gameUrl?.indexOf('?') !== -1) {
  262. gameUrl = gameUrl + '&game_id=' + getGameId() + '&user_id=' + userId + '&token=' + getToken()
  263. } else {
  264. gameUrl = gameUrl + '?game_id=' + getGameId() + '&user_id=' + userId + '&token=' + getToken()
  265. }
  266. return <>
  267. {isLoading && <LoadingPop />}
  268. <iframe id="gameFrame" name="gameFrame" className='fullscreen' src={gameUrl}></iframe>
  269. {/* 抽屉侧边窗 */}
  270. {open && <UserManage isVer={isVer} open={open} onClose={() => setOpen(false)} handle={handle} />}
  271. {/* 实名认证 */}
  272. {openAuth && <AuthPop open={openAuth} isClick={isClick} onClose={() => { setOpenAuth(false); setIsAuth() }} checkSwitch={checkSwitch} onChange={() => { getDetails(); setIsAuth() }} />}
  273. {/* 绑定手机 */}
  274. {openPhone && <BindPhone onChange={() => { getDetails(); setIsBind() }} open={openPhone} onClose={() => { setOpenPhone(false); setIsBind() }} />}
  275. {/* 修改密码 */}
  276. {openModify && <Modify open={openModify} onClose={() => setOpenModify(false)} onChange={() => { getDetails(); setOpenModify(false) }} />}
  277. {/* 悬浮球 */}
  278. {h5SignShow !== 'SIGN_SHOW_NONE' && <>
  279. {(h5SignShow === 'SIGN_SHOW_ALL' || ((h5SignShow === 'SIGN_SHOW_WX_NONE' && !isWx()) || (isOs() === 'windows' || isOs() === 'mac')) || (h5SignShow === 'SIGN_SHOW_H5_NONE' && (isOs() === 'windows' || isOs() === 'mac'))) && <FloatingWindow isVer={isVer} onClick={() => setOpen(true)} />}
  280. </>}
  281. {/* 支付选择组件 */}
  282. {payConfig.open && <PayPop isVer={isVer} {...payConfig} onClose={() => setPayConfig({ open: false, data: {} })} onChange={preOrderSucc} />}
  283. {/* 微信PC二维码弹窗 */}
  284. {wxPayInfo.open && <WxpcQrCode open={wxPayInfo.open} data={{ ...wxPayInfo }} onClose={() => setWxPayInfo({ qrcode: '', amount: '0.00', open: false, orderId: '' })} />}
  285. <div dangerouslySetInnerHTML={{ __html: htmlpay }}></div>
  286. </>
  287. } else {
  288. return <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} description="请先配置H5游戏地址" />
  289. }
  290. }
  291. export default React.memo(LoginSucc)