zhejiushizhuce 2 anni fa
parent
commit
329b4fd673

+ 1 - 0
package.json

@@ -30,6 +30,7 @@
     "@tanstack/react-table": "^8.7.9",
     "axios": "^1.6.7",
     "classnames": "^2.3.2",
+    "colyseus.js": "^0.15.19",
     "country-state-city": "^3.1.2",
     "craco": "^0.0.3",
     "dayjs": "^1.11.7",

+ 11 - 4
src/App.js

@@ -36,7 +36,6 @@ import {preventDefault} from '@utils/helpers';
 import rtlPlugin from 'stylis-plugin-rtl';
 import {CacheProvider} from '@emotion/react';
 import createCache from '@emotion/cache';
-
 // components
 import {BrowserRouter, HashRouter, Route, Routes, useLocation} from 'react-router-dom';
 import {ToastContainer} from 'react-toastify';
@@ -44,11 +43,10 @@ import Layout from "@layout/Layout";
 import {getFetchStatus, getUserID, getUserInfo} from '@features/mainSlice';
 import {useDispatch, useSelector} from "react-redux";
 import {REQ_STATUS} from "@api/config";
-import {reqGetRoutes} from "@features/api";
+import {reqCustomService, reqGetRoutes} from "@features/api";
 import LoadingScreen from "@components/LoadingScreen";
 import {reqPayConfig} from "@features/paySlice";
-
-
+import {connectHall, disconnectHall} from "@features/actions/hallClient";
 const App = () => {
     const dispatch = useDispatch();
     const fetchStatus=useSelector(getFetchStatus);
@@ -83,7 +81,16 @@ const App = () => {
     useEffect(()=>{
         if (userID!=0){
             reqPayConfig(dispatch,userInfo);
+            dispatch(connectHall());
+        }
+        else
+        {
+            dispatch(disconnectHall());
         }
+        //customer
+        dispatch(reqCustomService());
+        // var client = new Colyseus.Client('wss://wstest.ouro777.com:10000');
+        // console.log(client.joinOrCreate)
     },[userID])
     const renderLayout=()=>{
         return (

+ 7 - 0
src/Global.js

@@ -6,3 +6,10 @@ global.i18n=i18n;
 // global.symbol_m=symbol_m;
 global.DOLLAR="R$";
 global.dispatch=null;
+global.msgBox=null;
+global.msgBoxShow=(params)=>{
+    if (global.msgBox)global.msgBox.show(params);
+}
+global.msgBoxHide=()=>{
+    if (global.msgBox)global.msgBox.hide();
+}

+ 9 - 2
src/api/config.js

@@ -36,6 +36,13 @@ export const APP_RECHARGE_CONFIG=BASE_PREFIX+"recharge/gear";
 export const APP_FIRSTPAY_CONFIG=BASE_PREFIX+"recharge/firstPayConfig";
 export const APP_ACCOUNTS_PAY_INFO=BASE_PREFIX+"api/get_accounts_pay_info";
 export const APP_PAYMENT_ORDER=BASE_PREFIX+"payment_entry/pay";
-export const APP_GAME_INFO=BASE_PREFIX+"info";
 //pay
-
+//withdraw
+export const APP_WITHDRAW_TAX="api/api/withDrawTax";
+export const APP_WITHDRAW_BASE_INFO=BASE_PREFIX+"withdraw/baseInfo";
+export const APP_WITHDRAW_INFO=BASE_PREFIX+"withDraw/getWithDrawInfo";
+//withdraw
+//userinfo
+export const APP_GAME_INFO=BASE_PREFIX+"info";
+//custom customer_service
+export const APP_CUSTOMER_SERVICE="api/api/customer_service";

+ 12 - 5
src/api/request.js

@@ -62,14 +62,15 @@ service.interceptors.response.use(
 
 const get=(params={})=>{
     let sign=getSign();
+    if (params.params==null)params.params={};
     if (sign!=null&&sign!=""){
         // let url=params.url;
         // if (url.indexOf("?")===-1)url=url+"?sign="+getSign();
         // else url=url+"&sign="+getSign();
         // params.url=url;
-        if (params.params==null)params.params={};
-        params.params["sign"]=getSign();
+        params.params["sign"]=sign;
     }
+    params.params["t"]=Date.now();
     return service({
         method: 'get',
         ...params
@@ -77,9 +78,11 @@ const get=(params={})=>{
 }
 const post=(params={})=>{
     let sign=getSign();
+    if (params.data==null)params.data={};
     if (sign!=null&&sign!=""){
-        if (params.data)params.data.sign=getSign();
+        params.data.sign=sign;
     }
+    params.data.t=Date.now();
     return service({
         method: 'post',
         ...params
@@ -87,9 +90,11 @@ const post=(params={})=>{
 }
 const put=(params={})=>{
     let sign=getSign();
+    if (params.data==null)params.data={};
     if (sign!=null&&sign!=""){
-        params.sign=getSign();
+        params.data.sign=sign;
     }
+    params.data.t=Date.now();
     return service({
         method: 'put',
         ...params
@@ -97,9 +102,11 @@ const put=(params={})=>{
 }
 const adelete=(params={})=>{
     let sign=getSign();
+    if (params.data==null)params.data={};
     if (sign!=null&&sign!=""){
-        params.sign=getSign();
+        params.data.sign=sign;
     }
+    params.data.t=Date.now();
     return service({
         method: 'delete',
         ...params

+ 9 - 4
src/app/store.js

@@ -4,13 +4,18 @@ import MainReducer from '@features/mainSlice';
 import PageReducer from '@features/pageSlice';
 import GameListReducer from '@features/gameListSlice';
 import PayReducer from '@features/paySlice';
-
+import SocketReducer from '@features/socketSlice';
 export default configureStore({
     reducer: {
-        todos: TodosReducer,
+        // todos: TodosReducer,
         main:MainReducer,
         page:PageReducer,
         gamelist:GameListReducer,
-        pay:PayReducer
-    }
+        pay:PayReducer,
+        socket:SocketReducer
+    },
+    middleware:(getDefaultMiddleware => {
+        let middlewares=getDefaultMiddleware();
+        return middlewares;
+    })
 });

+ 19 - 0
src/assets/singlesvg/edit.svg

@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
+<svg width="800px" height="800px" viewBox="0 -0.5 21 21" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    
+    <title>edit_cover [#1481]</title>
+    <desc>Created with Sketch.</desc>
+    <defs>
+
+</defs>
+    <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="Dribbble-Light-Preview" transform="translate(-419.000000, -359.000000)" fill="#000000">
+            <g id="icons" transform="translate(56.000000, 160.000000)">
+                <path d="M384,209.210475 L384,219 L363,219 L363,199.42095 L373.5,199.42095 L373.5,201.378855 L365.1,201.378855 L365.1,217.042095 L381.9,217.042095 L381.9,209.210475 L384,209.210475 Z M370.35,209.51395 L378.7731,201.64513 L380.4048,203.643172 L371.88195,212.147332 L370.35,212.147332 L370.35,209.51395 Z M368.25,214.105237 L372.7818,214.105237 L383.18415,203.64513 L378.8298,199 L368.25,208.687714 L368.25,214.105237 Z" id="edit_cover-[#1481]">
+
+</path>
+            </g>
+        </g>
+    </g>
+</svg>

+ 85 - 0
src/components/MsgBox/index.jsx

@@ -0,0 +1,85 @@
+import {Component} from "react";
+import Modal from "@mui/material/Modal";
+import Fade from "@mui/material/Fade";
+import {ClickAwayListener} from "@mui/base/ClickAwayListener";
+import Grow from "@mui/material/Grow";
+import styles from "./styles.module.scss";
+const i18n=global.i18n;
+class MsgBox extends Component{
+    constructor(props) {
+        super(props);
+        this.init();
+    }
+    init(){
+        this.state=({
+             isShow:false,
+             title:"",
+             content:'',
+             sureLabel:'',
+             cancelLabel:''
+            })
+    }
+    show({title='',content='',sureCB=null,cancelCB=null,sureLabel='',cancelLabel=''}){
+        if (title==='')title=i18n.t('msgbox.title');
+        if (sureLabel==='')sureLabel=i18n.t('msgbox.sure_label');
+        if (cancelLabel==='')cancelLabel=i18n.t('msgbox.cancel_label');
+        this.sureCB=sureCB;
+        this.cancelCB=cancelCB;
+        this.setState({
+            isShow:true,
+            title:title,
+            content:content,
+            sureLabel:sureLabel,
+            cancelLabel:cancelLabel
+        })
+    }
+    hide(){
+        this.setState({
+            isShow:false,
+        })
+    }
+    onClickBtn(type){
+        if (type==0){
+            if (this.cancelCB!=null)this.cancelCB();
+        }
+        else if (type==1){
+            if (this.sureCB!=null)this.sureCB();
+        }
+        this.hide();
+    }
+    closeMsgBox(){
+        this.onClickBtn(0);
+    }
+    onClickSure(){
+        this.onClickBtn(1);
+    }
+    render() {
+        return (
+            <Modal open={this.state.isShow} onClose={this.closeMsgBox.bind(this)} closeAfterTransition>
+                <Fade in={this.state.isShow} timeout={500}>
+                    <div className="popup-container">
+                        <ClickAwayListener onClickAway={this.closeMsgBox.bind(this)}>
+                            <Grow in={this.state.isShow} timeout={500}>
+                                <div className={`popup card card-padded ${styles.msg_box}`}>
+                                    <div className={styles.msg_content}>
+                                        <div className={styles.title}>{this.state.title}</div>
+                                        <div className={styles.content}>{this.state.content}</div>
+                                        <div className={styles.msg_btn}>
+                                            <button className={"button-gray"} onClick={this.closeMsgBox.bind(this)}>
+                                                {this.state.cancelLabel}
+                                            </button>
+                                            <button className={"button-green"} onClick={this.onClickSure.bind(this)}>
+                                                {this.state.sureLabel}
+                                            </button>
+                                        </div>
+                                    </div>
+                                </div>
+                            </Grow>
+                        </ClickAwayListener>
+                    </div>
+                </Fade>
+            </Modal>
+        )
+    }
+}
+export default MsgBox;

+ 32 - 0
src/components/MsgBox/styles.module.scss

@@ -0,0 +1,32 @@
+.msg_box{
+  width: 90%;
+  & .msg_content{
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    color: var(--header);
+    gap: 0.5rem;
+    & .title{
+      font-size: 1.2rem;
+    }
+    & .content{
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      font-size: 1rem;
+      width: 100%;
+      height: 5rem;
+      text-align: center;
+      word-wrap: break-word;
+      word-break: break-all;
+      text-align: center;
+    }
+    & .msg_btn{
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+      width: 100%;
+      gap: 2rem;
+    }
+  }
+}

+ 6 - 1
src/constants/app.js

@@ -11,8 +11,13 @@ const APP_CHANNEL={
     Channel:"com.ouro777.j15",
     ChannelNumber:271
 }
+const APP_SERVER={
+    SERVER_URL:"wss://wstest.ouro777.com:10000",
+    ROOM_HALL:"hall",
+}
 export {
     APP_THEME,
     APP_GENDER,
-    APP_CHANNEL
+    APP_CHANNEL,
+    APP_SERVER
 };

+ 2 - 1
src/constants/routes.js

@@ -19,7 +19,8 @@ const ROUTE_PATH={
     GAME:"/game",
     PAY:"#/pay",
     SAQUE:"#/saque",
-    PAY_ORDER:"#/payorder"
+    PAY_ORDER:"#/payorder",
+    ACCOUNT_INFO:"#/accountInfo"
 }
 
 export {

+ 13 - 0
src/db/routes.js

@@ -204,4 +204,17 @@ export const routes=[
         lpath:"#/signin",//登录path
         subs:[]
     },
+    {
+        path: "#/accountInfo",
+        type: 1,
+        side: 0,
+        block:1,//块排序
+        title: "Account Information",
+        icon:"",
+        fill:";;",//icon 颜色 默认 选中 本身颜色
+        component:"accountInfo",
+        login:1,//0,1 检不检查登录
+        lpath:"#/signin",//登录path
+        subs:[]
+    },
 ]

+ 65 - 0
src/features/actions/hallClient.js

@@ -0,0 +1,65 @@
+import {APP_SERVER} from "@constants/app";
+import {connectServer, disconnectServer, onDisconnect, sendToServer} from "@features/socketSlice";
+const roomName=APP_SERVER.ROOM_HALL;
+const serverUrl=APP_SERVER.SERVER_URL;
+//信息处理
+const __playground_message_types=(message,dispatch)=>{
+
+}
+const roger=(message,dispatch)=>{
+    console.log(message);
+}
+const chat=(message,dispatch)=>{
+    console.log(message);
+}
+//信息处理
+const messageHandler={
+    __playground_message_types,
+    roger,
+    chat
+}
+const onHallConnect=()=>{
+    return (dispatch, getState) => {
+        dispatch(hallSendReg());
+        // dispatch(hallSendChat("123456"));
+    }
+}
+const send=(type,message,dispatch)=>{
+    dispatch(sendToServer({
+        roomName,
+        type,
+        message
+    }));
+}
+export const onHallMessage=(type,message)=>{
+    return (dispatch, getState) => {
+        let handler=messageHandler[type];
+        if (handler!=null){
+            handler(message,dispatch);
+        }
+    }
+}
+export const connectHall=()=>{
+    return connectServer({
+        roomName:roomName,
+        serverUrl:serverUrl,
+        messageCB:onHallMessage,
+        onRoomConnect:onHallConnect
+    });
+}
+export const disconnectHall=()=>{
+    return disconnectServer(roomName);
+}
+export const hallSendReg=()=>{
+    return (dispatch, getState) => {
+        let main=getState().main;
+        let userInfo=main.userInfo;
+        let {UserID,GlobalUID,FaceID,NickName}=userInfo;
+        send("id",{UserID,GlobalUID,FaceID,NickName},dispatch);
+    }
+}
+export const hallSendChat=(message)=>{
+    return (dispatch, getState) => {
+        send("chat",message,dispatch);
+    }
+}

+ 45 - 2
src/features/api.js

@@ -2,13 +2,13 @@ import {createAsyncThunk} from "@reduxjs/toolkit";
 import {
     APP_ACCOUNTS_PAY_INFO,
     APP_CHANGE_EMAIL,
-    APP_CHANGE_INFO, APP_CHANGE_PASS, APP_CHANGE_PHONE, APP_FIRSTPAY_CONFIG, APP_GAME_INFO,
+    APP_CHANGE_INFO, APP_CHANGE_PASS, APP_CHANGE_PHONE, APP_CUSTOMER_SERVICE, APP_FIRSTPAY_CONFIG, APP_GAME_INFO,
     APP_GAME_LIST,
     APP_LOGIN,
     APP_LOGOUT,
     APP_PAGE_MODULES, APP_PAYMENT_ORDER, APP_RECHARGE_CONFIG,
     APP_REGISTER,
-    APP_ROUTES,
+    APP_ROUTES, APP_WITHDRAW_BASE_INFO, APP_WITHDRAW_INFO, APP_WITHDRAW_TAX,
     REQ_STATUS
 } from "@api/config";
 import Http from "@api/request";
@@ -244,6 +244,38 @@ export const reqPaymentOrder=createAsyncThunk(
     }
 )
 //pay
+//withdraw
+export const reqWithdrawTax=createAsyncThunk(
+    APP_WITHDRAW_TAX,
+    async (arg, thunkAPI) => {
+        let params={
+            url:APP_WITHDRAW_TAX
+        }
+        const response=await Http.get(params);
+        return response;
+    }
+)
+export const reqWithdrawBaseInfo=createAsyncThunk(
+    APP_WITHDRAW_BASE_INFO,
+    async (arg, thunkAPI) => {
+        let params={
+            url:APP_WITHDRAW_BASE_INFO
+        }
+        const response=await Http.get(params);
+        return response;
+    }
+)
+export const reqWithdrawInfo=createAsyncThunk(
+    APP_WITHDRAW_INFO,
+    async (arg, thunkAPI) => {
+        let params={
+            url:APP_WITHDRAW_INFO
+        }
+        const response=await Http.get(params);
+        return response;
+    }
+)
+//withdraw
 //用户信息
 export const reqGameInfo=createAsyncThunk(
     APP_GAME_INFO,
@@ -255,4 +287,15 @@ export const reqGameInfo=createAsyncThunk(
         return response;
     }
 )
+//custom
+export const reqCustomService=createAsyncThunk(
+    APP_CUSTOMER_SERVICE,
+    async (arg,thunkAPI)=>{
+        let params={
+            url:APP_CUSTOMER_SERVICE
+        }
+        const response=await Http.get(params);
+        return response;
+    }
+)
 //api

+ 73 - 0
src/features/colyseus/CSClient.js

@@ -0,0 +1,73 @@
+import { Client as ColyseusClient, Room } from "colyseus.js";
+class CSClient {
+    constructor(roomName, serverUrl,messageCB) {
+        this.roomName=roomName;
+        this.serverUrl=serverUrl;
+        this.messageCB=messageCB;
+        this.client=new ColyseusClient(serverUrl);
+        this.callbacks=[];
+        this.unsetRoom();
+    }
+    unsetRoom(){
+        console.log("unsetRoomunsetRoom");
+        if(this.currentRoom){
+            this.currentRoom.removeAllListeners();
+            this.currentRoom=null;
+        }
+    }
+    setRoom(room){
+        this.currentRoom=room;
+        let self=this;
+        // room.connection.ws.addEventListener("close",()=>{
+        //     self.unsetRoom();
+        // });
+        room.onStateChange((newState) => {
+            console.log(self.roomName, "has new state:", newState.mySynchronizedProperty);
+            // skip unregistered (null) callbacks
+            self.callbacks.filter((_) => _).forEach((callback) => callback(newState));
+        });
+        room.onMessage("*",(type,message)=>{
+            console.log("Room:"+self.roomName+" onMessage:"+" type:"+type+" message:"+JSON.stringify(message))
+            if (self.messageCB)self.messageCB(type,message);
+        })
+
+        // when leaving, reset the connection state indicator
+        room.onLeave(self.unsetRoom);
+    }
+    async connect(options={}){
+        let self=this;
+        if(this.isConnected())await this.disconnect();
+        return new Promise((resolve, reject)=>{
+            self.client.joinOrCreate(this.roomName,options).then((room)=>{
+                self.setRoom(room);
+                resolve(true);
+            }).catch((e)=>{
+                resolve(false);
+            })
+        });
+    }
+    async disconnect(){
+        let self=this;
+        return new Promise((resolve, reject)=>{
+            if (self.currentRoom!=null){
+                self.currentRoom.onLeave(()=>{
+                    self.unsetRoom();
+                    resolve(true);
+                });
+                self.currentRoom.leave();
+            }
+            else{
+                resolve(true);
+            }
+        })
+    }
+    send(type,message){
+        if (this.currentRoom){
+            this.currentRoom.send(type,message);
+        }
+    }
+    isConnected(){
+        return this.currentRoom!=null;
+    }
+}
+export default CSClient;

+ 40 - 0
src/features/colyseus/CSClientWrap.js

@@ -0,0 +1,40 @@
+import CSClient from "@features/colyseus/CSClient";
+
+class CSClientWrap{
+    constructor() {
+        this.clients={};
+    }
+    async connect(roomName, serverUrl,messageCB=null,options={}){
+        this.disconnect(roomName);
+        let client=new CSClient(roomName,serverUrl,messageCB);
+        this.clients[roomName]=client;
+        let isConnected=await client.connect(options);
+        return isConnected;
+    }
+    async disconnect(roomName){
+        let client=this.clients[roomName];
+        if (client!=null){
+            client.disconnect();
+            delete this.clients[roomName];
+        }
+        return true;
+    }
+    isConnected(roomName){
+        let client=this.clients[roomName];
+        if (client)return client.isConnected();
+        return false;
+    }
+    send(roomName,type,message){
+        if (!this.isConnected(roomName))return;
+        let client=this.clients[roomName];
+        client.send(type,message);
+    }
+}
+let instance=null;
+CSClientWrap.getInstance=()=>{
+    if (instance==null){
+        instance=new CSClientWrap();
+    }
+    return instance;
+}
+export default CSClientWrap.getInstance();

+ 18 - 12
src/features/mainSlice.js

@@ -11,7 +11,7 @@ import {REQ_STATUS} from "@api/config";
 import {
     buildReqReducer, reqChangeEmail,
     reqChangeInfo,
-    reqChangePass, reqChangePhone, reqGameInfo,
+    reqChangePass, reqChangePhone, reqCustomService, reqGameInfo,
     reqGetRoutes,
     reqLogin,
     reqLogout,
@@ -60,6 +60,9 @@ const generateRoutes=(routes,asyncRoutes=[])=>{
                     if (route.path==="#/pay"){
                         route.component="deposit";
                     }
+                    if (route.path==="#/saque"){
+                        route.component="withdraw";
+                    }
                     allMap[route.path]=route;
                     let type=route.type;
                     if (type===ROUTE_TYPE_IN||type===ROUTE_TYPE_FULL)inRoutes.push(route);
@@ -162,16 +165,6 @@ const getLocalIsLogin=()=>{
     return islogin;
 }
 const getMsg=(payload)=>{
-    // let result=payload.result;
-    // if (result==null)result=payload.msg;
-    // let msg="";
-    // if (result!=null){
-    //     let key=result[0];
-    //     let def=result[1];
-    //     if (i18n.exists(key))msg=i18n.t(key);
-    //     else msg=def;
-    // }
-    // return msg;
     return getHttpMsg(payload);
 }
 const parseLogin=(state,action,arg,isShowMsg=true)=>{
@@ -289,6 +282,14 @@ const gameInfoStatus=(state,status,arg)=>{
     state.gameInfoStatus=status;
 }
 //gameinfo
+//custom
+const reducerCustom=(state,action,arg)=>{
+    let payload=action.payload;
+    if (payload&&payload.code==200){
+        state.customerInfo=payload.data;
+    }
+}
+//custom
 export const Main=createSlice({
     name: 'main',
     initialState: {
@@ -311,7 +312,8 @@ export const Main=createSlice({
             phone:REQ_STATUS.NONE,
             email:REQ_STATUS.NONE
         },
-        gameInfoStatus:REQ_STATUS.NONE
+        gameInfoStatus:REQ_STATUS.NONE,
+        customerInfo:[]
     },
     reducers: {
         logout:(state, action)=>{
@@ -333,6 +335,7 @@ export const Main=createSlice({
         buildReqReducer(builder,reqChangePhone,reducerChangePhone,changePhoneStatus);
         buildReqReducer(builder,reqChangeEmail,reducerChangeEmail,changeEmailStatus);
         buildReqReducer(builder,reqGameInfo,reducerGameInfo,gameInfoStatus);
+        buildReqReducer(builder,reqCustomService,reducerCustom,null);
     },
 })
 export const {logout} = Main.actions;
@@ -463,6 +466,9 @@ export const getUserID=(state)=>{
     }
     return uid;
 }
+export const getCustomInfo=(state)=>{
+    return state.main.customerInfo;
+}
 //数据获取
 export default Main.reducer;
 

+ 62 - 3
src/features/paySlice.js

@@ -5,7 +5,7 @@ import {
     reqFirstPayConfig,
     reqGetAccountsPayInfo,
     reqPaymentOrder,
-    reqRechargeConfig
+    reqRechargeConfig, reqWithdrawBaseInfo, reqWithdrawInfo, reqWithdrawTax
 } from "@features/api";
 const reducerRechargeConfig=(state,action,arg)=>{
     let payload=action.payload;
@@ -84,6 +84,33 @@ const reducerPaymentOrder=(state,action,arg)=>{
 const paymentOrderStatus=(state,status,arg)=>{
     state.status.PaymentOrder=status;
 }
+const reducerWithdrawTax=(state,action,arg)=>{
+    let payload=action.payload;
+    if (payload&&payload.code===200){
+        let data=payload.data;
+        if (data){
+            state.WithDrawTax=data.WithDrawTax;
+        }
+    }
+}
+const reducerWithdrawBaseInfo=(state,action,arg)=>{
+    let payload=action.payload;
+    if (payload&&payload.code===200){
+        let data=payload.data;
+        if (data){
+            state.withdrawBaseInfo=data;
+        }
+    }
+}
+const reducerWithdrawInfo=(state,action,arg)=>{
+    let payload=action.payload;
+    if (payload&&payload.code===200){
+        let data=payload.data;
+        if (data){
+            state.withdrawInfo=data;
+        }
+    }
+}
 export const Pay=createSlice({
     name: 'pay',
     initialState: {
@@ -97,8 +124,29 @@ export const Pay=createSlice({
         payconfig:null,
         firstconfig:null,
         payType:null,
-        currPayOrder:null
-
+        currPayOrder:null,
+        WithDrawTax:4,
+        withdrawBaseInfo:null,
+        withdrawInfo:null,
+        // withdrawBaseInfo:{
+        //     // "Achieves": null,
+        //     // "SumCanExchange": "3482",
+        //     // "AccountsBank": "",
+        //     // "BranchBank": "",
+        //     // "BankNO": "",
+        //     // "MinExchange": "6000",
+        //     // "MaxExchange": "3000000",
+        //     // "OrderLimit": "3",
+        //     // "OrderCount": "0",
+        //     // "BankUserName": "",
+        //     // "PhoneNumber": "",
+        //     // "IFSCNumber": "",
+        //     // "EmailAddress": "",
+        //     // "PANNumber": "",
+        //     // "AdhaarNumber": "",
+        //     // "PixNum": "",
+        //     // "PixType": "0"
+        // }
     },
     reducers: {
 
@@ -108,6 +156,9 @@ export const Pay=createSlice({
         buildReqReducer(builder,reqFirstPayConfig,reducerFirstPayConfig,firstPayConfigStatus);
         buildReqReducer(builder,reqGetAccountsPayInfo,reducerGetAccountsPayInfo,getAccountsPayInfoStatus);
         buildReqReducer(builder,reqPaymentOrder,reducerPaymentOrder,paymentOrderStatus);
+        buildReqReducer(builder,reqWithdrawTax,reducerWithdrawTax,null);
+        buildReqReducer(builder,reqWithdrawBaseInfo,reducerWithdrawBaseInfo,null);
+        buildReqReducer(builder,reqWithdrawInfo,reducerWithdrawInfo,null);
     },
 })
 export const {} = Pay.actions;
@@ -157,10 +208,18 @@ export const getPaymentOrderStatus=(state)=>{
 export const getCurrPayOrder=(state)=>{
     return state.pay.currPayOrder;
 }
+export const getWithdrawBaseInfo=(state)=>{
+    return state.pay.withdrawBaseInfo;
+}
+export const getWithdrawInfo=(state)=>{
+    return state.pay.withdrawInfo;
+}
 export default Pay.reducer;
 
 export const reqPayConfig=(dispatch,userInfo)=>{
     dispatch(reqRechargeConfig());
     dispatch(reqFirstPayConfig(userInfo.UserID));
     dispatch(reqGetAccountsPayInfo(userInfo.UserID));
+    dispatch(reqWithdrawBaseInfo());
+    // dispatch(reqWithdrawTax());
 }

+ 75 - 0
src/features/socketSlice.js

@@ -0,0 +1,75 @@
+import {createSlice} from "@reduxjs/toolkit";
+import {APP_SERVER} from "@constants/app";
+import CSClientWrap from "@features/colyseus/CSClientWrap";
+
+export const Socket=createSlice({
+    name: 'socket',
+    initialState: {
+        clients:{}
+    },
+    reducers: {
+        onConnect:(state, action) => {
+            let roomName=action.payload;
+            if (roomName!=null){
+                state.clients[roomName]={
+                    isConnected:true,
+                    message:{}//最后一条消息
+                }
+            }
+        },
+        onDisconnect:(state, action) =>{
+            let roomName=action.payload;
+            let client=state.clients[roomName];
+            if (client!=null){
+                client.isConnected=false;
+            }
+        },
+        onSend:(state, action) =>{
+
+        },
+        onMessage:(state, action) => {
+            let {roomName,type,message}=action.payload;
+            let client=state.clients[roomName];
+            if (client!=null){
+                client.message={type,message};
+            }
+        }
+    },
+    extraReducers: (builder) => {
+    },
+})
+export const {onConnect,onDisconnect,onSend,onMessage} = Socket.actions;
+
+export default Socket.reducer;
+
+export const connectServer=({roomName, serverUrl,messageCB=null,onRoomConnect=null,options={}})=>{
+    return async (dispatch, getState) => {
+        if (CSClientWrap.isConnected())return ;
+        let isConnected=await CSClientWrap.connect(roomName,serverUrl,(type,message)=>{
+            dispatch(onMessage({roomName,type,message}));
+            if (messageCB!=null)dispatch(messageCB(type,message));
+        });
+        if(isConnected){
+            dispatch(onConnect(roomName));
+            if (onRoomConnect!=null)dispatch(onRoomConnect());
+        }
+    }
+}
+export const disconnectServer=(roomName)=>{
+    return async (dispatch, getState) => {
+        await CSClientWrap.disconnect(roomName);
+        dispatch(onDisconnect(roomName));
+    }
+}
+export const sendToServer=({roomName,type,message=""})=>{
+    return (dispatch)=>{
+        CSClientWrap.send(roomName,type,message);
+        dispatch(onSend({roomName,type,message}));
+    }
+}
+// export const connectHall=()=>{
+//     return connectServer({
+//         roomName:APP_SERVER.ROOM_HALL,
+//         serverUrl:APP_SERVER.SERVER_URL
+//     });
+// }

+ 6 - 0
src/layout/Layout.jsx

@@ -19,10 +19,12 @@ import SubScreen from "@components/SubScreen";
 import CSSTransition from "react-transition-group/CSSTransition";
 import Transition from "react-transition-group/Transition";
 import WLangSelect from "@widgets/WLangSelect";
+import MsgBox from "@components/MsgBox";
 const PageNotFound = lazy(() => import('@pages/PageNotFound'));
 
 const Layout=()=>{
     const appRef = useRef(null);
+    const msgBoxRef=useRef(null);
     const {isMobile} = useThemeProvider();
     const {pathname, search, hash} = useLocation();
     const isFull = useSelector(isFullRoute(pathname));
@@ -34,6 +36,9 @@ const Layout=()=>{
         appRef.current && appRef.current.scrollTo(0, 0);
         preventDefault();
     }, []);
+    useEffect(()=>{
+        global.msgBox=msgBoxRef.current;
+    },[msgBoxRef])
     const renderIn=()=>{
         return (
             <div className={`app`} ref={appRef}>
@@ -89,6 +94,7 @@ const Layout=()=>{
         return (
             <>
                 <WLangSelect/>
+                <MsgBox ref={msgBoxRef}/>
             </>
         )
     }

+ 75 - 0
src/locales/languages/en_US.json

@@ -169,5 +169,80 @@
     "msg_title": "Leave the game",
     "msg_content": "Are you sure you want to leave?",
     "cancel": "Cancel"
+  },
+  "msgbox": {
+    "title": "Prompt",
+    "sure_label": "Sure",
+    "cancel_label": "Cancel"
+  },
+  "withdraw": {
+    "main": {
+      "total_balance": "My total chip",
+      "withdrawable": "Extractable chip",
+      "editBox": "Chips",
+      "editPlaceholder": "Enter the amount to withdraw",
+      "btn_reset": "Remove",
+      "btn_all": "ALL",
+      "bank_info_isNull": "No bank information bound",
+      "bank_No_isNull": "No bank card account",
+      "via": "Withdraw Via",
+      "account": "My Account",
+      "btn_account": "+ Bank Account",
+      "btn_account_change": "Change Account",
+      "btn_withdraw": "Withdraw",
+      "tip": "Tips: The expected time of receipt is within 12 hours, please refer to the bank.The minimum/maximum amount which you can withdraw every time is {0}/{1}"
+    },
+    "account": {
+      "title": "Account Information",
+      "btn_save": "Save and activate",
+      "help": "Please make sure your Account Number is correct,we do not take any responsi-bilty caused by incorrect input",
+      "userName": "Name",
+      "name_holder": "Enter name",
+      "phone": "Telephone[+55]",
+      "phone_holder": "Enter 11 digits",
+      "email": "Email",
+      "email_holder": "input Email-ID",
+      "cpf": "CPF",
+      "cpf_holder": "***.***.***-**",
+      "phone_type": "Telephone(+55)",
+      "tedCon": "Bank accounts:",
+      "tedCon_holder": "exemple:123456",
+      "tedCon2_holder": "exemple:1",
+      "tedBan": "Bank Code:",
+      "tedBan_holder": "exemple:123456",
+      "tedSub": "Sub branch Code:",
+      "tedSub_holder": "exemple:123456",
+      "cpf_dict": "PIX DICT",
+      "e_mail": "E-mail",
+      "tip": {
+        "select_null": "please select PIX DICT",
+        "account_error": "Incorrect bank card format",
+        "account_null": "The bank card content is empty",
+        "name_error": "The User Name information is wrong",
+        "name_null": "user name is empty",
+        "bank_error": "The Bank Name information is wrong",
+        "bank_null": "Bank name is empty",
+        "phone_error": "Malformed phone number",
+        "phone_null": "Phone Number is empty",
+        "IFSC_error": "IFSC Code error",
+        "IFSC_null": "IFSC Code is empty",
+        "PAN_error": "PAN Number error",
+        "PAN_null": "PAN Number is empty",
+
+        "BAN_error": "[Bank Code] incorrect format",
+        "BAN_null": "[Bank Code] is empty",
+        "email_error": "[Email] incorrect format",
+        "email_null": "[Email] is empty",
+        "cpf_error": "[CPF] incorrect format",
+        "cpf_null": "[CPF] is empty",
+        "success": "PIX bank account saved and activated",
+        "success2": "TED bank account saved and activated",
+        "error": "Bank account information failed to save",
+        "bind_too_more": "Application failed\nYour account may be used by multiple users, please check your bank account security.",
+        "is_null": "is empty",
+        "is_error": "incorrect format"
+
+      }
+    }
   }
 }

+ 10 - 0
src/pages/Withdraw.jsx

@@ -0,0 +1,10 @@
+import WWithdraw from "@widgets/WWithdraw";
+
+const Withdraw=({...props})=>{
+    return (
+        <>
+            <WWithdraw {...props}></WWithdraw>
+        </>
+    )
+}
+export default Withdraw;

+ 10 - 0
src/pages/WithdrawAccountEdit.jsx

@@ -0,0 +1,10 @@
+import AccountEdit from "@widgets/WWithdraw/AccountEdit";
+
+const WithdrawAccountEdit=({...props})=>{
+    return (
+        <>
+            <AccountEdit {...props}/>
+        </>
+    )
+}
+export default WithdrawAccountEdit;

+ 9 - 3
src/pages/index.jsx

@@ -1,5 +1,6 @@
 import {lazy} from "react";
 import DepositHeader from "@widgets/WDeposit/DepositHeader";
+import WithdrawHeader from "@widgets/WWithdraw/WithdrawHeader";
 const ModulePage=lazy(()=>import('@pages/ModulePage'));
 const Home=lazy(()=>import('@pages/Home'));
 const Login=lazy(()=>import("@pages/Login"));
@@ -8,7 +9,9 @@ const EditProfile=lazy(()=>import("@pages/EditProfile"));
 const EditPassword=lazy(()=>import("@pages/EditPassword"));
 const Game=lazy(()=>import("@pages/Game"));
 const Deposit=lazy(()=>import("@pages/Deposit"));
-const PaymentOrder=lazy(()=>import("@pages/PaymentOrder"))
+const PaymentOrder=lazy(()=>import("@pages/PaymentOrder"));
+const Withdraw=lazy(()=>import("@pages/Withdraw"));
+const WithdrawAccountEdit=lazy(()=>import("@pages/WithdrawAccountEdit"));
 export default {
     ModulePage:ModulePage,
     Home:Home,
@@ -18,8 +21,11 @@ export default {
     editPassword:EditPassword,
     game:Game,
     deposit:Deposit,
-    paymentOrder:PaymentOrder
+    paymentOrder:PaymentOrder,
+    withdraw:Withdraw,
+    accountInfo:WithdrawAccountEdit
 }
 export const Header={
-    deposit: DepositHeader
+    deposit: DepositHeader,
+    withdraw:WithdrawHeader
 }

+ 0 - 1
src/styles/_utils.scss

@@ -75,7 +75,6 @@
 .flex-1 {
     flex: 1;
 }
-
 .g-1 {
     gap: 1px;
 }

+ 1 - 0
src/styles/_vars.scss

@@ -68,6 +68,7 @@ $width-desktop-big-max:1564px;
     --zindex-second:1000;
     --zindex-drawer:1200;
     --zindex-popup:1300;
+    --coin-yellow:#edc349;
 }
 
 //@media screen and (min-width: 414px) {

+ 8 - 40
src/widgets/WGame/index.jsx

@@ -9,10 +9,6 @@ import {ReactComponent as Boxbg} from '@assets/singlesvg/back/boxbg.svg';
 import {ReactComponent as Boxclose} from '@assets/singlesvg/back/boxclose.svg';
 import {ReactComponent as Circlebg} from '@assets/singlesvg/back/circlebg.svg';
 import {ReactComponent as Circlearrow} from '@assets/singlesvg/back/circlearrow.svg';
-import Fade from "@mui/material/Fade";
-import {ClickAwayListener} from "@mui/base/ClickAwayListener";
-import Grow from "@mui/material/Grow";
-import Modal from "@mui/material/Modal";
 import LoadingScreen from "@components/LoadingScreen";
 import {ROUTE_PATH} from "@constants/routes";
 import {useDispatch} from "react-redux";
@@ -114,42 +110,15 @@ const WGame=()=>{
             </iframe>
         )
     }
-    const closeMsgBox=()=>{
-        setOpenPrompt(false);
-    }
     const openMsgBox=()=>{
-        setOpenPrompt(true);
-    }
-    const renderMsgBox=()=>{
-        return (
-            <Modal open={openPrompt} onClose={closeMsgBox} closeAfterTransition>
-                <Fade in={openPrompt} timeout={500}>
-                    <div className="popup-container">
-                        <ClickAwayListener onClickAway={closeMsgBox}>
-                            <Grow in={openPrompt} timeout={500}>
-                                <div className={`popup card card-padded ${styles.msg_box}`}>
-                                    <div className={styles.msg_content}>
-                                        <div className={styles.title}>{i18n.t("game.msg_title")}</div>
-                                        <div className={styles.content}>{i18n.t("game.msg_content")}</div>
-                                        <div className={styles.msg_btn}>
-                                            <button className={"button-gray"} onClick={closeMsgBox}>
-                                                {i18n.t("game.cancel")}
-                                            </button>
-                                            <button className={"button-green"} onClick={()=>{
-                                                onBack();
-                                                closeMsgBox();
-                                            }}>
-                                                {i18n.t("game.back")}
-                                            </button>
-                                        </div>
-                                    </div>
-                                </div>
-                            </Grow>
-                        </ClickAwayListener>
-                    </div>
-                </Fade>
-            </Modal>
-        )
+        let data={
+            title:i18n.t("game.msg_title"),
+            content:i18n.t("game.msg_content"),
+            sureCB:onBack,
+            sureLabel:i18n.t("game.back"),
+            cancelLabel:i18n.t("game.cancel")
+        }
+        global.msgBoxShow(data)
     }
     const renderLoading=()=>{
         if (isGameLoad)return(<></>);
@@ -163,7 +132,6 @@ const WGame=()=>{
         <div className={styles.container}>
             {renderGame()}
             {renderBackBox()}
-            {renderMsgBox()}
             {renderLoading()}
         </div>
     )

+ 0 - 32
src/widgets/WGame/styles.module.scss

@@ -88,38 +88,6 @@
     }
   }
 }
-.msg_box{
-  width: 90%;
-  & .msg_content{
-    display: flex;
-    flex-direction: column;
-    align-items: center;
-    color: var(--header);
-    gap: 0.5rem;
-    & .title{
-      font-size: 1.2rem;
-    }
-    & .content{
-      display: flex;
-      align-items: center;
-      justify-content: center;
-      font-size: 1rem;
-      width: 100%;
-      height: 5rem;
-      text-align: center;
-      word-wrap: break-word;
-      word-break: break-all;
-      text-align: center;
-    }
-    & .msg_btn{
-      display: flex;
-      align-items: center;
-      justify-content: space-between;
-      width: 100%;
-      gap: 2rem;
-    }
-  }
-}
 .loading{
   position: fixed;
   top: 0;

+ 1 - 1
src/widgets/WPaymentOrder/BR/styles.module.scss

@@ -16,7 +16,7 @@
   & .logo{
     width: 1.4rem;
     height: 1.4rem;
-    fill: #37b4aa;
+    fill: var(--primary-color);
   }
 }
 .order_info{

+ 10 - 0
src/widgets/WWithdraw/AccountEdit.jsx

@@ -0,0 +1,10 @@
+import styles from './styles.module.scss';
+import BRAccountEdit from "@widgets/WWithdraw/BR/BRAccountEdit";
+const AccountEdit=({close})=>{
+    return (
+        <div className={styles.container}>
+            <BRAccountEdit/>
+        </div>
+    )
+}
+export default AccountEdit;

+ 179 - 0
src/widgets/WWithdraw/BR/BRAccountEdit.jsx

@@ -0,0 +1,179 @@
+import styles from "./styles.module.scss";
+import Spring from "@components/Spring";
+import React, {useEffect} from "react";
+import {ReactComponent as PixLogo} from "@assets/singlesvg/pix.svg";
+import {useDispatch, useSelector} from "react-redux";
+import {getWithdrawBaseInfo, getWithdrawInfo} from "@features/paySlice";
+import SmallLoading from "@components/SmallLoading";
+import {reqWithdrawInfo} from "@features/api";
+import {Controller, useForm} from "react-hook-form";
+import PasswordInput from "@components/UInput/PasswordInput";
+import classNames from "classnames";
+import {APP_GENDER} from "@constants/app";
+const i18n=global.i18n;
+const BRAccountEdit=()=>{
+    let info=useSelector(getWithdrawBaseInfo);
+    if (info==null)info={};
+    const dispatch=useDispatch();
+    const {register, handleSubmit, formState: {errors}, control} = useForm({
+        defaultValues: {
+            account: info.AccountsBank||"",
+            userName: info.BankUserName||"",
+            bank: info.BankNO||"",
+            branceBank: info.BranchBank||"",
+            phone: info.PhoneNumber||"",
+            PAN: info.PANNumber||"",
+            IFSC:info.IFSCNumber||"",
+            email: info.EmailAddress||"",
+            PixNum: info.PixNum||"",
+            adhaar: info.AdhaarNumber||"",
+            PixType: info.PixType||"",
+        }
+    });
+    useEffect(()=>{
+        // dispatch(reqWithdrawInfo());
+    },[])
+    const handleChange=(data)=>{
+
+    }
+    const renderPixLogo=()=>{
+        return (
+            <div className={styles.pix_title}>
+                <PixLogo className={styles.logo}/>
+                {i18n.t("deposit.order_info.pay_type_pix")}
+            </div>
+        )
+    }
+    const renderAccoutForm=()=>{
+        return (
+            <form autoComplete="off" className={styles.accout_form} onSubmit={handleSubmit((data) => {
+                handleChange(data);
+            })}>
+                <Controller control={control}
+                            name="userName"
+                            rules={{required: true}}
+                            render={({field: {ref, onChange, value}, fieldState: {error}}) => (
+                                <div className={styles.form_item}>
+                                    <div className={styles.title}>{i18n.t("withdraw.account.userName")}</div>
+                                    <div className={`input-control ${error?'input-control--error':''}`}>
+                                        <input
+                                            value={value}
+                                            onChange={e => onChange(e.target.value)}
+                                            placeholder={i18n.t('withdraw.account.name_holder')}
+                                            ref={ref}
+                                        />
+                                    </div>
+                                </div>
+                            )}
+                />
+                <Controller control={control}
+                            name="phone"
+                            rules={{required: true}}
+                            render={({field: {ref, onChange, value}, fieldState: {error}}) => (
+                                <div className={styles.form_item}>
+                                    <div className={styles.title}>{i18n.t("withdraw.account.phone")}</div>
+                                    <div className={`input-control ${error?'input-control--error':''}`}>
+                                        <input
+                                            value={value}
+                                            onChange={e => onChange(e.target.value)}
+                                            placeholder={i18n.t('withdraw.account.phone_holder')}
+                                            ref={ref}
+                                        />
+                                    </div>
+                                </div>
+                            )}
+                />
+                <Controller control={control}
+                            name="email"
+                            rules={{required: true}}
+                            render={({field: {ref, onChange, value}, fieldState: {error}}) => (
+                                <div className={styles.form_item}>
+                                    <div className={styles.title}>{i18n.t("withdraw.account.email")}</div>
+                                    <div className={`input-control ${error?'input-control--error':''}`}>
+                                        <input
+                                            value={value}
+                                            onChange={e => onChange(e.target.value)}
+                                            placeholder={i18n.t('withdraw.account.email_holder')}
+                                            ref={ref}
+                                        />
+                                    </div>
+                                </div>
+                            )}
+                />
+                <Controller control={control}
+                            name="PixNum"
+                            rules={{required: true}}
+                            render={({field: {ref, onChange, value}, fieldState: {error}}) => (
+                                <div className={styles.form_item}>
+                                    <div className={styles.title}>{i18n.t("withdraw.account.cpf")}</div>
+                                    <div className={`input-control ${error?'input-control--error':''}`}>
+                                        <input
+                                            value={value}
+                                            onChange={e => onChange(e.target.value)}
+                                            placeholder={i18n.t('withdraw.account.cpf_holder')}
+                                            ref={ref}
+                                        />
+                                    </div>
+                                </div>
+                            )}
+                />
+                <Controller control={control}
+                            name="PixType"
+                            rules={{required: true}}
+                            render={({field: {ref, onChange, value}, fieldState: {error}}) => (
+                                <div className={styles.form_item}>
+                                    <div className={styles.title}>{i18n.t("withdraw.account.cpf_dict")}</div>
+                                    <div className={styles.pix_con}>
+                                        <button type={"button"} className={`${styles.radio_btn} ${value==="0"?styles.active:''}`} onClick={()=>{
+                                            onChange("0");
+                                        }}>
+                                            <div className={styles.circle}>
+                                                <div className={styles.dot}/>
+                                            </div>
+                                            <div>{i18n.t("withdraw.account.cpf")}</div>
+                                        </button>
+                                        <button type={"button"} className={`${styles.radio_btn} ${value==="1"?styles.active:''}`} onClick={()=>{
+                                            onChange("1");
+                                        }}>
+                                            <div className={styles.circle}>
+                                                <div className={styles.dot}/>
+                                            </div>
+                                            <div>{i18n.t("withdraw.account.e_mail")}</div>
+                                        </button>
+                                        <button type={"button"} className={`${styles.radio_btn} ${value==="2"?styles.active:''}`} onClick={()=>{
+                                            onChange("2");
+                                        }}>
+                                            <div className={styles.circle}>
+                                                <div className={styles.dot}/>
+                                            </div>
+                                            <div>{i18n.t("withdraw.account.phone_type")}</div>
+                                        </button>
+                                    </div>
+                                </div>
+                            )}
+                />
+                <button className={"button-green"}>
+                    {i18n.t("withdraw.account.btn_save")}
+                </button>
+                <div className={styles.tips}>{i18n.t("withdraw.account.help")}</div>
+            </form>
+        )
+    }
+    return (
+        <>
+            {
+                info==null?(
+                    <div className={styles.loading}>
+                        <SmallLoading/>
+                    </div>
+                ):(
+                    <Spring type="slideUp" className={styles.container}>
+                        {renderPixLogo()}
+                        {renderAccoutForm()}
+                    </Spring>
+                )
+            }
+        </>
+    )
+}
+export default BRAccountEdit;

+ 179 - 0
src/widgets/WWithdraw/BR/BRWithdraw.jsx

@@ -0,0 +1,179 @@
+import Spring from "@components/Spring";
+import styles from "./styles.module.scss";
+import React, {useState} from "react";
+import {useSelector} from "react-redux";
+import {getUserInfo} from "@features/mainSlice";
+import {numFormatter, stringFormat} from "@utils/helpers";
+import {getWithdrawBaseInfo} from "@features/paySlice";
+import symbol from "@assets/symbol-defs.svg";
+import {ReactComponent as Edit} from '@assets/singlesvg/edit.svg';
+import {useNavigate} from "react-router-dom";
+import {ROUTE_PATH} from "@constants/routes";
+const i18n=global.i18n;
+const BRWithdraw=()=>{
+    const user=useSelector(getUserInfo);
+    const info=useSelector(getWithdrawBaseInfo);
+    const navigate=useNavigate();
+    const addBtnParam = [200, 500, 1000, 2000, 5000, -1];
+    const [addIndex,setAddIndex]=useState(-1);
+    const [wdValue,setWdValue]=useState("");
+    const formatInput=(text)=>{
+        let inputNum = Number(text);
+        inputNum = Math.min(inputNum, info.SumCanExchange);
+        inputNum = Math.min(inputNum, user.Score);
+        return (inputNum > 0) ? (inputNum) : "";
+    }
+    const getAddIndexFromValue=(value)=>{
+        value=Number(value);
+        let index=addBtnParam.indexOf(value);
+        if (index===-1){
+            if (value===info.CanWithDraw){
+                index=addBtnParam.length-1;
+            }
+        }
+        return index;
+    }
+    const renderUser=()=>{
+        return (
+            <div className={styles.content}>
+                <div className={styles.user_con}>
+                    <div className={styles.money_con}>
+                        <div className={styles.title}>{i18n.t("withdraw.main.total_balance")}</div>
+                        <div className={styles.money}>{global.DOLLAR+numFormatter(user.Score)}</div>
+                    </div>
+                    <div className={styles.money_con}>
+                        <div className={styles.title}>{i18n.t("withdraw.main.withdrawable")}</div>
+                        <div className={styles.money}>{global.DOLLAR+numFormatter(info.SumCanExchange)}</div>
+                    </div>
+                </div>
+                <div className={styles.line}/>
+            </div>
+        )
+    }
+    const renderWithdrawValue=()=>{
+        return (
+            <div className={styles.content}>
+                <div className={styles.title}>{i18n.t("withdraw.main.editBox")}</div>
+                <div className={styles.select_con}>
+                    {
+                        addBtnParam.map((item,index)=>{
+                            let label=item===-1?i18n.t("withdraw.main.btn_all"):global.DOLLAR+" "+item;
+                            return (
+                                <button key={index}
+                                        className={`${styles.grid_btn} ${addIndex===index?styles.active:''}`}
+                                        onClick={()=>{
+                                            let value=item===-1?info.SumCanExchange+"":item+"";
+                                            let fvalue=formatInput(value);
+                                            let addIndx=value===fvalue?index:-1;
+                                            if (addIndx!==-1)setWdValue(fvalue);
+                                            setAddIndex(addIndx);
+                                        }}
+                                >
+                                    {label}
+                                </button>
+                            )
+                        })
+                    }
+                </div>
+                <div className={`input-control ${styles.input_con}`}>
+                    <div className={styles.money}>{global.DOLLAR}</div>
+                    <input
+                        value={wdValue}
+                        type={"number"}
+                        placeholder={i18n.t("withdraw.main.editPlaceholder")}
+                        onChange={(e)=>{
+                            let value=formatInput(e.target.value);
+                            setWdValue(value);
+                            setAddIndex(getAddIndexFromValue(value));
+                        }}
+                    />
+                    {
+                        wdValue===""?(<></>):(
+                            <button className={styles.clear_btn} onClick={()=>{
+                                setWdValue("");
+                            }}>
+                                <svg className={styles.icon}>
+                                    <use xlinkHref={`${symbol}#icon_Close`} />
+                                </svg>
+                            </button>
+                        )
+                    }
+                </div>
+                <div className={styles.line}/>
+            </div>
+        )
+    }
+    const renderAccount=()=>{
+        let BankUserName=info.BankUserName;
+        let AccountsBank=info.AccountsBank;
+        let cbPixType=Number(info.PixType);
+        let via="";
+        let accout="";
+        if (BankUserName!==""||AccountsBank!==""){
+            via=cbPixType >= 10 ? "TED" : "PIX";
+            accout=cbPixType >= 10 ? AccountsBank : BankUserName
+        }
+        return (
+            <div className={`${styles.content} ${styles.account_info}`}>
+                <div className={styles.title_con}>
+                    <div className={styles.title}>{i18n.t("withdraw.account.title")}</div>
+                    <button onClick={()=>{
+                        navigate(ROUTE_PATH.ACCOUNT_INFO);
+                    }}>
+                        <Edit className={styles.icon}/>
+                    </button>
+                </div>
+                <div className={styles.line}></div>
+                <div className={styles.info_item}>
+                    <div className={styles.title}>{i18n.t("withdraw.main.via")}</div>
+                    {
+                        via===""?(<div>{i18n.t("withdraw.main.bank_info_isNull")}</div>):(
+                            <div className={styles.active}>{via}</div>
+                        )
+                    }
+                    {/*<div className={styles.line}></div>*/}
+                </div>
+                <div className={styles.info_item}>
+                    <div className={styles.title}>{i18n.t("withdraw.main.account")}</div>
+                    {
+                        accout===""?(<div>{i18n.t("withdraw.main.bank_No_isNull")}</div>):(
+                            <div className={styles.active}>{accout}</div>
+                        )
+                    }
+                    {/*<div className={styles.line}></div>*/}
+                </div>
+            </div>
+        )
+    }
+    const renderSubmit=()=>{
+        let num = info.OrderLimit - info.OrderCount;
+        // data.WithDrawMin, data.WithDrawMax
+        let min=info.MinExchange;
+        let max=info.MaxExchange;
+        return (
+            <div className={styles.content}>
+                <button className="button-green">
+                    {i18n.t("withdraw.main.btn_withdraw")+"  ("+num+")"}
+                </button>
+                <div className={styles.tips}>
+                    {stringFormat(i18n.t("withdraw.main.tip"),[min,max])}
+                </div>
+            </div>
+        )
+    }
+    return (
+        <>
+            {
+                info==null?(<></>):(
+                    <Spring type="slideUp" className={styles.container}>
+                        {renderUser()}
+                        {renderWithdrawValue()}
+                        {renderAccount()}
+                        {renderSubmit()}
+                    </Spring>
+                )
+            }
+        </>
+    )
+}
+export default BRWithdraw;

+ 192 - 0
src/widgets/WWithdraw/BR/styles.module.scss

@@ -0,0 +1,192 @@
+.container{
+  display: flex;
+  flex-direction: column;
+  position: relative;
+  padding: 1rem;
+  width: 100%;
+  gap: 1rem;
+}
+.content{
+  display: flex;
+  flex-direction: column;
+  width: 100%;
+  gap: 1rem;
+  color: var(--text);
+}
+.user_con{
+  display: flex;
+  gap: 0.5rem;
+  flex-direction: column;
+  justify-content: center;
+  & .money_con{
+    display: flex;
+    flex-direction: row;
+    align-items: center;
+    justify-content: space-between;
+    gap: 0.5rem;
+  }
+}
+.title{
+  color: var(--header);
+  font-size: 1rem;
+}
+.money{
+  color: var(--coin-yellow);
+  font-size: 1rem;
+}
+.line{
+  border-top: 1px solid var(--card-line);
+}
+
+.select_con{
+  display: grid;
+  gap: 0.6rem;
+  grid-template-columns: repeat(3, minmax(0, 1fr));
+  & .grid_btn{
+    position: relative;
+    border-radius: var(--border-radius);
+    background-color: var(--pay-btn-bg);
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    gap: 0.5rem;
+    padding: 0.6rem;
+    font-size: 1rem;
+    font-weight: 500;
+    color: var(--text);
+    overflow: hidden;
+    min-height: 2rem;
+    &.active{
+      border: 1px solid var(--primary-color);
+      color: var(--header);
+      font-weight: 700;
+    }
+  }
+}
+.input_con{
+  background-color: var(--pay-btn-bg);
+  gap: 1rem;
+  font-size: 1rem;
+}
+.clear_btn{
+  width: 1rem;
+  height: 1rem;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  & .icon{
+    width: 1.4em;
+    height: 1.4em;
+    font-size: .75rem;
+    fill: var(--text);
+  }
+}
+.account_info{
+  padding: 1rem;
+  border-radius: var(--border-radius);
+  background-color: var(--card-bg);
+  & .title_con{
+    display: flex;
+    flex-direction: row;
+    align-items: center;
+    justify-content: space-between;
+    & .icon{
+      width: 1.4em;
+      height: 1.4em;
+      fill: var(--primary-color);
+      path{
+        fill: var(--primary-color);
+      }
+    }
+  }
+  & .info_item{
+    display: flex;
+    flex-direction: row;
+    align-items: center;
+    justify-content: space-between;
+    gap: 0.6rem;
+    & .title{
+      font-size: 0.9rem;
+      color: var(--header);
+    }
+    & .active
+    {
+      color: var(--header);
+    }
+  }
+}
+.tips{
+  color: var(--coin-yellow);
+  opacity: 0.9;
+  text-align: center;
+}
+.loading{
+  display: flex;
+  height: 100vh;
+}
+.pix_title{
+  display: flex;
+  width: 100%;
+  gap: 0.5rem;
+  color: var(--text);
+  font-size: 1rem;
+  font-weight: 600;
+  & .logo{
+    width: 1.4rem;
+    height: 1.4rem;
+    fill: var(--primary-color);
+  }
+}
+.accout_form{
+  display: flex;
+  flex-direction: column;
+  gap: 1rem;
+  .form_item{
+    display: flex;
+    flex-direction: column;
+    gap: 0.6rem;
+    color: var(--header);
+    & .title{
+      font-size: 0.9rem;
+      color: var(--text);
+    }
+  }
+}
+.pix_con{
+  display: flex;
+  align-items: center;
+  justify-content: space-around;
+  gap: 2rem;
+  min-height: 1.875rem;
+  & .radio_btn{
+    display: flex;
+    align-items: center;
+    color: var(--header);
+    gap: 0.5rem;
+    &.active{
+      & .circle{
+        border: solid .13rem var(--primary-color);
+        opacity: 1;
+        & .dot{
+          background-color: var(--primary-color);
+        }
+      }
+    }
+    & .circle{
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      width: 1.2rem;
+      height: 1.2rem;
+      border-radius: 50%;
+      border: solid .13rem var(--text);
+      opacity: 0.5;
+      & .dot{
+        width: 0.65rem;
+        height: 0.65rem;
+        border-radius: 50%;
+        background-color:transparent;
+      }
+    }
+  }
+}

+ 43 - 0
src/widgets/WWithdraw/WithdrawHeader.jsx

@@ -0,0 +1,43 @@
+import styles from "./styles.module.scss";
+import SvgIcon from "@components/SvgIcon";
+import {ReactComponent as Video} from "@assets/singlesvg/video.svg";
+import USD from "@assets/lvicon/USD.black.png";
+import {numFormatter} from "@utils/helpers";
+const i18n=global.i18n;
+const WithdrawHeader=({...props})=>{
+    const route=props.route;
+    const close=props.close;
+    const renderHeader=()=>{
+        let title=route?route.title:"";
+        return (
+            <div className={styles.header}>
+                <div className={styles.hcontent}>
+                    {i18n.t(title)}
+                </div>
+                <div className={styles.top}>
+                    <div className={styles.left}>
+                        <button className={styles.close} onClick={()=>{
+                            close();
+                        }}>
+                            <SvgIcon className={styles.arrow} herf={"icon_Arrow"}/>
+                        </button>
+                    </div>
+                    <div className={styles.right}>
+                        <button className={styles.right_btn}>
+                            <SvgIcon className={styles.icon} herf={"icon_Help"}/>
+                        </button>
+                        <button className={styles.right_btn}>
+                            <SvgIcon className={styles.icon} herf={"icon_History"}/>
+                        </button>
+                    </div>
+                </div>
+            </div>
+        )
+    }
+    return (
+        <div id={props.id} className={props.className}>
+            {renderHeader()}
+        </div>
+    )
+}
+export default WithdrawHeader;

+ 10 - 0
src/widgets/WWithdraw/index.jsx

@@ -0,0 +1,10 @@
+import styles from './styles.module.scss';
+import BRWithdraw from "@widgets/WWithdraw/BR/BRWithdraw";
+const WWithdraw=({close})=>{
+    return (
+        <div className={styles.container}>
+            <BRWithdraw/>
+        </div>
+    )
+}
+export default WWithdraw;

+ 67 - 0
src/widgets/WWithdraw/styles.module.scss

@@ -0,0 +1,67 @@
+.container{
+  width: 100%;
+  min-height: 100%;
+  background-color: var(--widget-bg);
+}
+.header{
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  width:100%;
+  background: var(--widget);
+  border-bottom: 1px solid var(--border);
+  box-shadow:var(--widget-shadow);
+  position:relative;
+  height:3.75rem;
+  padding: 0px 10px;
+  & .top{
+    display: flex;
+    align-items: center;
+    position:fixed;
+    justify-content: space-between;
+    left: 10px;
+    right: 10px;
+    & .left{
+      display: flex;
+      align-items: center;
+      gap: 0.25rem;
+      & .close{
+        display: flex;
+        align-items: center;
+        height: 3.75rem;
+        width: 2rem;
+        & .arrow{
+          width: 1.4rem;
+          height: 1.8em;
+          transform: rotate(-180deg);
+          fill: var(--text);
+        }
+      }
+    }
+    & .right{
+      display: flex;
+      align-items: center;
+      & .right_btn{
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        height: 2.5rem;
+        width: 2.5rem;
+        & .icon{
+          width: 1.4rem;
+          height: 1.4rem;
+          fill: var(--text);
+        }
+      }
+    }
+  }
+  & .hcontent {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    flex: 1;
+    font-size: 1rem;
+    font-weight: 600;
+    color: var(--header);
+  }
+}