Parcourir la source

Merge branch 'dev' into feature-lucky1230

xiaolin.fu il y a 6 mois
Parent
commit
8006dfc1d4

+ 6 - 4
messages/br.json

@@ -153,23 +153,25 @@
 
     "bonus":  "Bônus",
     "bonusArticle":"Bônus Article",
-    "bonusDesc1": "O saldo de ouro colorido será transferido automaticamente para sua carteira principal após a conclusão dos requisitos de volume de codificação",
+    "bonusDesc1": "O saldo de ouro colorido será transferido para sua carteira principal após a conclusão dos requisitos de volume de codificação",
     "bonusDesc2": "Se houver um saldo de ouro no momento do início do levantamento, a carteira de ouro será esvaziada",
     "bonusDesc3": "O ouro colorido não pode mais ser usado em crash, esportes ou outros jogos restritos",
     "free": "Free",
     "freeArticle": "Free Article",
     "freeDesc1": "As moedas grátis só podem ser usadas nos jogos grátis especificados",
-    "freeDesc2": "Completar a quantidade de código de moeda livre, o saldo é transferido automaticamente para a carteira de dinheiro",
+    "freeDesc2": "Completar a quantidade de código de moeda livre, o saldo é transferido para a carteira de dinheiro",
     "replay": "Replay",
     "replayArticle": "Replay Article",
     "replayDesc1": "As moedas de repetição só podem ser jogadas nos jogos de repetição especificados",
-    "replayDesc2": "Termine a quantidade de codificação de moedas de repetição, e o saldo será transferido automaticamente para a carteira de dinheiro",
+    "replayDesc2": "Termine a quantidade de codificação de moedas de repetição, e o saldo será transferido para a carteira de dinheiro",
     "modalTitle": "Proxima retirada de bonus",
     "modalBottomTips": " FALTA APOSTAR R$ ",
     "expTips": "{exp} Bet to ",
     "main": "Principais",
     "gratis": "Grátis",
-    "compensation": "Compensaçao"
+    "compensation": "Compensaçao",
+
+    "carteira": "TRANSFERIR PARA A CARTEIRA"
   },
   "DepositPage": {
     "Montante": "Montante",

+ 6 - 4
messages/en.json

@@ -153,22 +153,24 @@
     "balance": "Saldo",
     "bonus":  "Bônus",
     "bonusArticle":"Bônus Article",
-    "bonusDesc1": "O saldo de ouro colorido será transferido automaticamente para sua carteira principal após a conclusão dos requisitos de volume de codificação",
+    "bonusDesc1": "O saldo de ouro colorido será transferido para sua carteira principal após a conclusão dos requisitos de volume de codificação",
     "bonusDesc2": "Se houver um saldo de ouro no momento do início do levantamento, a carteira de ouro será esvaziada",
     "bonusDesc3": "O ouro colorido não pode mais ser usado em crash, esportes ou outros jogos restritos",
     "free": "Free",
     "freeArticle": "Free Article",
     "freeDesc1": "As moedas grátis só podem ser usadas nos jogos grátis especificados",
-    "freeDesc2": "Completar a quantidade de código de moeda livre, o saldo é transferido automaticamente para a carteira de dinheiro",
+    "freeDesc2": "Completar a quantidade de código de moeda livre, o saldo é transferido para a carteira de dinheiro",
     "replayArticle": "Replay Article",
     "replayDesc1": "As moedas de repetição só podem ser jogadas nos jogos de repetição especificados",
-    "replayDesc2": "Termine a quantidade de codificação de moedas de repetição, e o saldo será transferido automaticamente para a carteira de dinheiro",
+    "replayDesc2": "Termine a quantidade de codificação de moedas de repetição, e o saldo será transferido para a carteira de dinheiro",
     "modalBottomTips": " FALTA APOSTAR R$ ",
     "replay": "Replay",
     "modalTitle": "Proxima retirada de bonus",
     "expTips": "{exp} Bet to ",
     "main": "Main",
-    "compensation": "Compensation"
+    "compensation": "Compensation",
+
+    "carteira": "TRANSFERIR PARA A CARTEIRA"
   },
   "DepositPage": {
     "Montante": "Montante",

+ 11 - 0
src/api/home.ts

@@ -132,6 +132,10 @@ export interface GameListRep {
      * 时间
      */
     release_date: string;
+    // 自定义demo试玩
+    demo?: number,
+    // 自定义游戏类型
+    category_name? : string
 }
 
 export const getGamesApi = () => {
@@ -314,3 +318,10 @@ export const updateUserNoticeApi = (letter_id: number) => {
         data: { letter_id },
     });
 };
+
+// 获取中奖配置列表
+export const gamesNoticeWinApi = () => {
+    return server.post({
+        url: "/v1/api/front/games_notice_win",
+    });
+};

+ 20 - 0
src/api/user.ts

@@ -242,6 +242,18 @@ export interface Wallet {
     notice: {
         lose_score: number;
     };
+    /**
+     * 是否允许转移彩金
+     */
+    is_point_transfer?: boolean;
+    /**
+     * 是否允许转移免费币
+     */
+    is_free_transfer?: boolean;
+    /**
+     * 是否允许转移重玩币
+     */
+    is_lose_transfer?: boolean;
 }
 // 前台用户获取金额信息
 export const getUserMoneyApi = () => {
@@ -312,3 +324,11 @@ export interface DepositsRep {
      */
     sub_type: number;
 }
+
+// 用户钱包余额转移
+export const getUserTransferApi = (data: {wallet_type: number}) => {
+    return server.post<any>({
+        url: "/v1/api/user/user_transfer",
+        data
+    });
+};

+ 1 - 1
src/app/[locale]/(TabBar)/[[...share]]/@actionWidget/Service.tsx

@@ -125,7 +125,7 @@ const ServiceWidget: FC<Props> = (props) => {
     };
 
     const { data: slots, run: slotRun } = useRequest<any, any>(getSlots, {
-        pollingInterval: 5000,
+        pollingInterval: 2000,
         pollingErrorRetryCount: 1,
         pollingWhenHidden: false,
     });

+ 111 - 18
src/app/[locale]/(TabBar)/[[...share]]/_home/HomePrize.tsx

@@ -1,21 +1,66 @@
 "use client";
+import { gamesNoticeWinApi, GameListRep } from "@/api/home";
+import Box from "@/components/Box";
+import { Button, Popup } from "antd-mobile";
 import { useTranslations } from "next-intl";
-import { FC } from "react";
+import { FC, useState } from "react";
 import { Autoplay } from "swiper/modules";
 import { Swiper, SwiperSlide } from "swiper/react";
+import { useRouter } from "@/i18n/routing";
+import { getToken } from "@/utils/Cookies";
+import { useWalletStore } from "@/stores/useWalletStore";
+import useGame from "@/hooks/useGame";
+import { useRequest } from "ahooks";
+import styles from "@/components/Card/style.module.scss";
+
 interface Props {}
 
-const mockData = [
-    { url: "/9f/551935.jpg", name: "123", money: 11 },
-    { url: "/9f/551935.jpg", name: "123", money: 11 },
-    { url: "/9f/551935.jpg", name: "123", money: 11 },
-    { url: "/9f/551935.jpg", name: "123", money: 11 },
-    { url: "/9f/551935.jpg", name: "123", money: 11 },
-    { url: "/9f/551935.jpg", name: "123", money: 11 },
-    { url: "/9f/551935.jpg", name: "123", money: 11 },
-];
-const HomePrize: FC<Props> = (props) => {
+const HomePrize: FC<Props> = () => {
     const t = useTranslations("HomePage");
+    const tt = useTranslations("Game");
+
+    const [winImg, setWinImg] = useState<any>([{}]);
+    const { run, cancel } = useRequest(gamesNoticeWinApi, {
+        pollingInterval: 600000,
+        pollingWhenHidden: true,
+        pollingErrorRetryCount: 3,
+        staleTime: 5000,
+        onError: (error) => {},
+        onSuccess: (res) => {
+            setWinImg(res.data || []);
+        },
+    });
+
+    const [visible, setVisible] = useState(false);
+    const [gameInfo, setGameInfo] = useState<any>({});
+    const handler = (game: GameListRep) => {
+        setVisible(true);
+        setGameInfo(game)
+        console.log(game)
+    };
+    
+    const router = useRouter();
+    const token = getToken();
+    const wallet = useWalletStore((state) => state.wallet);
+    const { getGameUrl } = useGame();
+    const playGameHandler = () => {
+        setVisible(true);
+        if (!token) {
+            router.push("/login?redirect=/");
+            return;
+        }
+        let groupType = 1;
+        if (groupType === 1 && Number(wallet.score) + wallet.point <= 0) {
+            router.push("/deposit");
+            return;
+        }
+
+        const params: any = {
+            id: gameInfo.id + "",
+            mode: groupType!,
+        };
+        getGameUrl(gameInfo, params);
+    };
 
     return (
         <div className={"my-[0.0694rem]"}>
@@ -28,23 +73,71 @@ const HomePrize: FC<Props> = (props) => {
                 }}
                 loop
                 autoplay={{
-                    delay: 2000,
+                    delay: 3000,
                 }}
-                modules={[Autoplay]}
+                modules={[Autoplay]}             
                 className="mySwiper"
             >
-                {mockData.map((prize, index) => (
+                {winImg.map((prize: any, index: number) => (
                     <SwiperSlide key={index}>
-                        <div className={"w-[1.1rem] bg-[#1c1e22]"}>
-                            <img className={"h-[1.54rem]"} src={prize.url} alt="" />
+                        <div className={"w-[1.1rem] bg-[#1c1e22]"} onClick={() => handler(prize)}>
+                            <img className={"h-[1.54rem]"} src={prize.game_icon} alt="" />
                             <div className={"px-[0.13rem] pb-[0.0347rem] text-[0.13rem]"}>
-                                <p className={"text-[#98a7b5]"}>{prize.name}</p>
-                                <p className={"text-[#43c937]"}>R${prize.money}</p>
+                                <p className={"text-[#98a7b5]"}>{prize.phone ? prize.phone.slice(0,3) + '*****' + prize.phone.slice(-3): ''}</p>
+                                <p className={"text-[#43c937]"}>R${prize.amount}</p>
                             </div>
                         </div>
                     </SwiperSlide>
                 ))}
             </Swiper>
+            <Popup
+                visible={visible}
+                onMaskClick={() => {
+                    setVisible(false);
+                }}
+                onClose={() => {
+                    setVisible(false);
+                }}
+                showCloseButton={true}
+                getContainer={() => document.querySelector("#app")!}
+                bodyStyle={{ background: "#1c1c1c" }}
+            >
+                <Box className={"w-1/1 flex w-[4.02rem] flex-1"}>
+                    <div className={styles.cardWrap} style={{ width: "1.1rem" }}>
+                        <img
+                            src={gameInfo?.game_icon}
+                            alt={gameInfo?.game_name_cn}
+                            className={"h-[100%] w-[100%]"}
+                        />
+                    </div>
+                    <div className={styles.cardWrapGmeInfo}>
+                        <p className={"h-[0.6rem]"}>{gameInfo?.game_name_cn}</p>
+
+                        <div className={"flex w-[2.2rem] justify-around"}>
+                            {/*<Button*/}
+                            {/*    onClick={playGameHandler}*/}
+                            {/*    className={*/}
+                            {/*        "h-[0.39rem] w-[0.89rem] rounded-[0.05rem] text-[0.15rem]" +*/}
+                            {/*        " bg-[#3a3a3a]" +*/}
+                            {/*        " font-bold"*/}
+                            {/*    }*/}
+                            {/*>*/}
+                            {/*    {t("demo")}*/}
+                            {/*</Button>*/}
+                            <Button
+                                onClick={playGameHandler}
+                                style={{
+                                    "--background-color": "#009d80",
+                                    "--border-color": "#009d80",
+                                }}
+                                className={`h-[0.39rem] w-[0.89rem] rounded-[0.05rem] bg-[#] text-[0.15rem] font-bold`}
+                            >
+                                {tt("join")}
+                            </Button>
+                        </div>
+                    </div>
+                </Box>
+            </Popup>
         </div>
     );
 };

+ 5 - 3
src/app/[locale]/(TabBar)/[[...share]]/_home/HomeTabs.tsx

@@ -12,7 +12,7 @@ import HomeGames from "./HomeGames";
 
 const buttonGroup = [
     {
-        icon: "youxi2",
+        icon: "qianbao3",
         category_name: "sixth",
         isHot: false,
         url: "/freeGames",
@@ -20,7 +20,7 @@ const buttonGroup = [
         lock: false,
     },
     {
-        icon: "youxi1",
+        icon: "qianbao3",
         category_name: "seventh",
         isHot: false,
         url: "/replayGames",
@@ -95,6 +95,8 @@ const TabItem = ({
     };
     const cls = clsx("pro-iconfont  text-[0.14rem]", `pro-${item.icon}`);
 
+    const cls2 = clsx("iconfont  text-[0.145rem]", `icon-${item.icon}`);
+
     const rootCls = clsx(
         "relative mr-[0.06rem] flex h-[0.3rem] bg-[#3a3a3a] flex-1 cursor-pointer items-center" +
             " rounded-[0.05rem]  px-[0.08rem] py-[0.03rem] text-[0.12rem] text-[#fff]",
@@ -102,7 +104,7 @@ const TabItem = ({
     );
     return (
         <div className={rootCls} onClick={() => handler(item)}>
-            <span className={cls}></span>
+            <span className={item.icon === 'qianbao3' ? cls2 : cls}></span>
             <span className={"ml-[0.03rem] truncate"}>
                 {item.locale ? t(item.category_name) : item.category_name}
             </span>

+ 1 - 1
src/app/[locale]/(TabBar)/[[...share]]/layout.tsx

@@ -46,7 +46,7 @@ const Layout: FC<PropsWithChildren<Props>> = (props) => {
                     {/* 搜索组件 */}
                     {searchWidget}
                     {/* 搜索下面的大奖展示 */}
-                    {/*{prizeWidget}*/}
+                    {prizeWidget}
                 </Box>
                 {/* tabs 和 游戏列表 */}
                 {children}

+ 65 - 20
src/app/[locale]/(TabBar)/deposit/DepositData.tsx

@@ -1,11 +1,12 @@
 "use client";
 import { DepositsTypes, RewardsType } from "@/api/depositsApi";
-import { getUserRechargeApi } from "@/api/user";
+import { getUserRechargeApi, getUserMoneyApi } from "@/api/user";
+import TipsModal, { ModalProps } from "@/components/TipsModal";
 import Box from "@/components/Box";
 import ButtonOwn from "@/components/ButtonOwn";
 import { useUserInfoStore } from "@/stores/useUserInfoStore";
 import { neReg } from "@/utils";
-import { Form, Input, Toast } from "antd-mobile";
+import { Button, Form, Input, Toast } from "antd-mobile";
 import { FormInstance } from "antd-mobile/es/components/form";
 import { useTranslations } from "next-intl";
 import { FC, Fragment, useLayoutEffect, useRef, useState } from "react";
@@ -90,26 +91,41 @@ const DepositData: FC<Props> = (props) => {
 
     const isStrictMode = true;
 
-    const onFinish = (values: any) => {
+    const tipModelRef = useRef<ModalProps>(null); // 充值清空打码量弹窗
+    const [formData, setFormData] = useState<any>({}); // 存放表单数据
+    const onFinish = async (values: any) => {
         const params = { ...values, channel_id: activeType.id, amount: +values.amount };
-        getUserRechargeApi(params)
-            .then(async (res) => {
-                formInstanceRef.current?.resetFields();
-                Toast.show({ icon: "success", content: t("code.200"), maskClickable: false });
-                setAmount(undefined);
-
-                if (res.data.pay_url) {
-                    window.open(res.data.pay_url);
-                }
-                const data = await getDepositApi();
-                setDepositState(data);
-                setActiveType(data[0]);
-                await actions();
-            })
-            .catch((error) => {
-                Toast.show({ content: t(`code${error.data.code}`), maskClickable: false });
-            });
+        const res: any = await getUserMoneyApi()
+        if (res?.data?.tips_reset_rollover) {
+            tipModelRef.current?.onOpen();
+            setFormData(params)
+            return
+        }
+        handleUserRecharge(false, params)
     };
+
+    const handleUserRecharge = (is_reset_rollover: boolean, data?: any) => {
+        let params = data || formData 
+        getUserRechargeApi({ is_reset_rollover, ...params})
+        .then(async (res) => {
+            formInstanceRef.current?.resetFields();
+            Toast.show({ icon: "success", content: t("code.200"), maskClickable: false });
+            tipModelRef.current?.onClose();
+            setAmount(undefined);
+
+            if (res.data.pay_url) {
+                window.open(res.data.pay_url);
+            }
+            const data = await getDepositApi();
+            setDepositState(data);
+            setActiveType(data[0]);
+            await actions();
+        })
+        .catch((error) => {
+            Toast.show({ content: t(`code${error.data.code}`), maskClickable: false });
+        });
+    }
+
     const onValuesChange = (changeValues: any) => {
         if (changeValues.amount) {
             setAmount(changeValues.amount);
@@ -256,6 +272,35 @@ const DepositData: FC<Props> = (props) => {
                     {t("DepositPage.depositTips")}
                 </div>
             </Box>
+            <TipsModal title={"Tips"} ref={tipModelRef}>
+                <div className={"flex items-center justify-between"}>
+                    <h2 className={"text-[0.14rem]"}>Mantenha Bônus</h2>
+                    <Button color={"primary"} className={"mx-auto"}
+                        style={{
+                            "--background-color": "var(--primary-color)",
+                            "--border-color": "var(--primary-color)",
+                        }}
+                        onClick={() => handleUserRecharge(false)}
+                    >
+                        Depósito
+                    </Button>
+                </div>
+                <p className={"text-left text-[0.12rem] font-medium text-[#666] mt-[0.05rem]"}>Recarga direta, mantendo a carteira principal e informações de carteira de bônus;</p>
+                <b className={"mt-[0.2rem] mb-[0.2rem]"} style={{width: '100%',height: 'auto', borderTop: '1px solid #e5e5e5', display: 'block'}}></b>
+                <div className={"flex items-center justify-between"}>
+                    <h2 className={"text-[0.14rem]"}>Esvaziem Bônus</h2>
+                    <Button color={"primary"} className={"mx-auto"}
+                        style={{
+                            "--background-color": "var(--primary-color)",
+                            "--border-color": "var(--primary-color)",
+                        }}
+                        onClick={() => handleUserRecharge(true)}
+                    >
+                        Depósito
+                    </Button>
+                </div>
+                <p className={"text-left text-[0.12rem] font-medium text-[#666] mt-[0.05rem]"}>Após a recarga, o saldo principal é mantido e todo o bônus é esvaziado, a nova carteira principal e a carteira de bônus são re-gravadas a quantidade de códigos jogados;</p>
+            </TipsModal>
         </div>
     );
 };

+ 1 - 1
src/app/[locale]/(TabBar)/freeGames/page.tsx

@@ -33,7 +33,7 @@ const Header = () => {
     };
     return (
         <>
-            <HeaderBack showBack={true} title={"Free Games"}>
+            <HeaderBack showBack={true} title={"Free Wallet"}>
                 <div
                     className={"mr-[0.2083rem] flex items-center justify-end"}
                     onClick={() => modalHandler("Free")}

+ 155 - 64
src/app/[locale]/(TabBar)/profile/ProfileHeader.tsx

@@ -1,5 +1,7 @@
 "use client";
-import { UserInfoRep, UserVipInfo, Wallet } from "@/api/user";
+import { UserInfoRep, UserVipInfo, Wallet, getUserTransferApi } from "@/api/user";
+import { userInfoApi } from "@/api/login";
+import { GameListRep } from "@/api/home";
 import {
     BalanceContent,
     BonusContent,
@@ -12,10 +14,11 @@ import { useWalletStore } from "@/stores/useWalletStore";
 import { WalletEnum } from "@/types";
 import { vipImages } from "@/utils/constant";
 import { flatPoint, percentage } from "@/utils/methods";
-import { ProgressBar, Toast } from "antd-mobile";
+import { ProgressBar, Toast, Badge, Button } from "antd-mobile";
 import { useTranslations } from "next-intl";
 import Image from "next/image";
 import { Fragment, useRef, useState } from "react";
+import useGame from "@/hooks/useGame";
 
 type Props = {
     userInfo: UserInfoRep;
@@ -82,6 +85,58 @@ const WalletCard = (props: { userMoney: Wallet }) => {
         tipsRef.current?.onOpen();
     };
 
+    // 未完成游戏
+    const gameModelRef = useRef<ModalProps>(null);
+    const game = useRef<GameListRep | null>(null);
+
+    // 彩金、免费币、重玩币提现到钱包操作
+    const handleAcquire = async (wallet_type: number, transfer: boolean) => {
+        if(!transfer) return;
+
+        // 先判断是否有未完成的游戏
+        const { data }: any = await userInfoApi();
+
+        // 如果有未完成游戏 彩金游戏-2、免费游戏-3、重玩游戏-4
+        if (wallet_type === 2 && data.play_list && data.play_list.length > 0) {
+            game.current = data.play_list[0];
+            gameModelRef.current?.onOpen();
+            return;
+        }
+        
+        if (wallet_type === 3 && data.free_game_list && data.free_game_list.length > 0) {
+            game.current = data.free_game_list[0];
+            gameModelRef.current?.onOpen();
+            return;
+        }
+
+        if (wallet_type === 4 && data.lose_game_list && data.lose_game_list.length > 0) {
+            game.current = data.lose_game_list[0];
+            gameModelRef.current?.onOpen();
+            return;
+        }
+
+        getUserTransferApi({ wallet_type })
+        .then((res) => {
+            if (res.code === 200) {
+                Toast.show(t("code.200"));
+                setTimeout(() => {
+                    tipsRef.current?.onClose();
+                }, 1000)
+            }
+        })
+        .catch((error) => {
+            Toast.show(t(`code.${error.data.code}`));
+        });
+    };
+
+    const { getGameUrl } = useGame();
+    const goGame = () => {
+        const current = game.current;
+        getGameUrl(current!, { id: current?.id + "" });
+        tipsRef.current?.onClose();
+        gameModelRef.current?.onClose();
+    };
+
     return (
         <>
             <TipsModal
@@ -98,91 +153,127 @@ const WalletCard = (props: { userMoney: Wallet }) => {
                 {/*现金*/}
                 {tipsStatus === WalletEnum.Balance ? <BalanceContent wallet={userMoney} /> : null}
                 {/*  彩金*/}
-                {tipsStatus === WalletEnum.Bonus ? <BonusContent wallet={userMoney} /> : null}
+                {tipsStatus === WalletEnum.Bonus ? <BonusContent wallet={userMoney} handleAcquire={handleAcquire}/> : null}
                 {/* 免费币 */}
-                {tipsStatus === WalletEnum.Free ? <FreeContent wallet={userMoney} /> : null}
+                {tipsStatus === WalletEnum.Free ? <FreeContent wallet={userMoney} handleAcquire={handleAcquire}/> : null}
                 {/*  重玩币 */}
-                {tipsStatus === WalletEnum.Replay ? <ReplayContent wallet={userMoney} /> : null}
+                {tipsStatus === WalletEnum.Replay ? <ReplayContent wallet={userMoney} handleAcquire={handleAcquire}/> : null}
+            </TipsModal>
+            {/*   提现拦截 */}
+            <TipsModal title={"Tips"} ref={gameModelRef}>
+                <p className={"text-left text-[0.12rem] font-medium text-[#666]"}>
+                    Existem jogos de bônus pendentes que não podem iniciar a retirada.
+                </p>
+
+                <div className={"mt-[0.0694rem] flex justify-center"}>
+                    <Button
+                        color={"primary"}
+                        className={"mx-auto"}
+                        style={{
+                            "--background-color": "var(--primary-color)",
+                            "--border-color": "var(--primary-color)",
+                        }}
+                        onClick={goGame}
+                    >
+                        para jogos
+                    </Button>
+                </div>
             </TipsModal>
             <div className="coin">
-                <span className="coin_left__icon iconfont icon-icon-wallet"></span>
                 <div className={"coin_right_wallet"}>
                     <div
                         className={"wallet_left_border"}
                         onClick={() => modalHandler(WalletEnum.Balance)}
                     >
-                        <div className={"wallet_header"}>
-                            <span>{t("balance")}</span>
-                            <Image
-                                className="wallet_header__icon"
-                                src="/img/a.png"
-                                alt="question"
-                                width={15}
-                                height={15}
-                            />
-                        </div>
-
-                        <div className="num">
-                            <span className="uppercase">brl </span>
-                            <span>{userMoney.score || 0.0}</span>
-                        </div>
+                        <span className="coin_left__icon iconfont icon-qianbao3"></span>
+                        <section>
+                            <div className={"wallet_header"}>
+                                <span>{t("balance")}</span>
+                                <Image
+                                    className="wallet_header__icon"
+                                    src="/img/a.png"
+                                    alt="question"
+                                    width={15}
+                                    height={15}
+                                />
+                            </div>
+                            <div className="num">
+                                <span className="uppercase">brl </span>
+                                <span>{userMoney.score || 0.0}</span>
+                            </div>
+                        </section>
                     </div>
                     <div
                         className={"wallet_right_content"}
                         onClick={() => modalHandler(WalletEnum.Bonus)}
                     >
-                        <div className={"wallet_header"}>
-                            {t("bonus")}
-                            <Image
-                                className="wallet_header__icon"
-                                src="/img/a.png"
-                                alt="question"
-                                width={15}
-                                height={15}
-                            />
-                        </div>
-                        <div className="num">
-                            <span className="uppercase">brl </span>
-                            <span>{userMoney.point || 0.0}</span>
-                        </div>
+                        <Badge content={userMoney.is_point_transfer ? Badge.dot : null} style={{right: "10px"}}>
+                            <span className="coin_left__icon iconfont icon-qianbao3"></span>
+                        </Badge>
+                        <section>
+                            <div className={"wallet_header"}>
+                                {t("bonus")}
+                                <Image
+                                    className="wallet_header__icon"
+                                    src="/img/a.png"
+                                    alt="question"
+                                    width={15}
+                                    height={15}
+                                />
+                            </div>
+                            <div className="num">
+                                <span className="uppercase">brl </span>
+                                <span>{userMoney.point || 0.0}</span>
+                            </div>
+                        </section>
                     </div>
                     <div
                         className={"wallet_left_border"}
                         onClick={() => modalHandler(WalletEnum.Free)}
-                    >
-                        <div className={"wallet_header"}>
-                            {t("free")}
-                            <Image
-                                className="wallet_header__icon"
-                                src="/img/a.png"
-                                alt="question"
-                                width={15}
-                                height={15}
-                            />
-                        </div>
-                        <div className="num">
-                            <span className="uppercase">brl </span>
-                            <span>{userMoney.free_score || 0.0}</span>
-                        </div>
+                    >                   
+                        <Badge content={userMoney.is_free_transfer ? Badge.dot : null} style={{right: "10px"}}>
+                            <span className="coin_left__icon iconfont icon-qianbao3"></span>
+                        </Badge>
+                        <section>
+                            <div className={"wallet_header"}>
+                                {t("free")}
+                                <Image
+                                    className="wallet_header__icon"
+                                    src="/img/a.png"
+                                    alt="question"
+                                    width={15}
+                                    height={15}
+                                />
+                            </div>
+                            <div className="num">
+                                <span className="uppercase">brl </span>
+                                <span>{userMoney.free_score || 0.0}</span>
+                            </div>
+                        </section>
                     </div>
                     <div
                         className={"wallet_right_content"}
                         onClick={() => modalHandler(WalletEnum.Replay)}
                     >
-                        <div className={"wallet_header"}>
-                            {t("replay")}
-                            <Image
-                                className="wallet_header__icon"
-                                src="/img/a.png"
-                                alt="question"
-                                width={15}
-                                height={15}
-                            />
-                        </div>
-                        <div className="num">
-                            <span className="uppercase">brl </span>
-                            <span>{userMoney.lose_score || 0.0}</span>
-                        </div>
+                        <Badge content={userMoney.is_lose_transfer ? Badge.dot : null} style={{right: "10px"}}>
+                            <span className="coin_left__icon iconfont icon-qianbao3"></span>
+                        </Badge>
+                        <section>
+                            <div className={"wallet_header"}>
+                                {t("replay")}
+                                <Image
+                                    className="wallet_header__icon"
+                                    src="/img/a.png"
+                                    alt="question"
+                                    width={15}
+                                    height={15}
+                                />
+                            </div>
+                            <div className="num">
+                                <span className="uppercase">brl </span>
+                                <span>{userMoney.lose_score || 0.0}</span>
+                            </div>
+                        </section>
                     </div>
                 </div>
             </div>

+ 25 - 2
src/app/[locale]/(TabBar)/profile/page.scss

@@ -36,7 +36,6 @@
         border-bottom: .01rem dotted #d9a801;
       }
 
-
       &.active {
         margin-bottom: 0;
       }
@@ -161,7 +160,7 @@
         font-size: .12rem;
         color: #333;
         grid-template-columns: 1fr 1fr;
-        gap: 0 0.1042rem;
+        // gap: 0 0.1042rem;
         & :nth-child(3),
         & :nth-child(4){
           padding-top: 0.05rem;
@@ -190,9 +189,14 @@
 
         .wallet_left_border{
           border-right:  .01rem dotted #d9a801;
+          display: flex;
+          align-items: center;
+          
         }
         .wallet_right_content{
           margin-left: .3rem;
+          display: flex;
+          align-items: center;
         }
       }
 
@@ -254,4 +258,23 @@
       }
     }
 
+    .carteira-box {
+      display: block;
+      width: 2.2rem;
+      height: .3rem;
+      line-height: .3rem;
+      border-radius: 0.04rem;
+      color: #fff;
+      font-size: 0.13rem;
+      margin: 0 auto;
+      margin-top: .1rem;
+      text-align: center;
+      background: #ccc;
+
+      &.active {
+        background: -o-linear-gradient(top, #ff9323, #ff6a01);
+        background: linear-gradient(180deg, #ff9323, #ff6a01);
+      }
+    }
+
 }

+ 1 - 1
src/app/[locale]/(TabBar)/replayGames/page.tsx

@@ -33,7 +33,7 @@ const Header = () => {
     };
     return (
         <>
-            <HeaderBack showBack={true} title={"Replay Games"}>
+            <HeaderBack showBack={true} title={"Replay Wallet"}>
                 <div
                     className={"mr-[0.2083rem] flex items-center justify-end"}
                     onClick={() => modalHandler("Replay")}

+ 6 - 4
src/app/[locale]/(navbar)/notification/components/Notices.tsx

@@ -27,13 +27,15 @@ const SystemMessage = (props: Props) => {
                     <Collapse.Panel
                         key={`${notice.id}`}
                         arrowIcon={
-                            <div>
-                                <Badge
+                            <div className={"flex items-center"}>
+                                {/* <Badge
                                     className={`mr-[0.1rem] h-[0.06rem] w-[0.06rem]`}
                                     style={{ "--color": "#ff311b" }}
                                     content={!notice.is_read ? Badge.dot : ""}
-                                ></Badge>
-
+                                ></Badge> */}
+                                {
+                                    !notice.is_read && <div className={`mr-[0.1rem] h-[0.08rem] w-[0.08rem]`} style={{borderRadius: "0.04rem", backgroundColor: "#ff311b"}}></div>
+                                }
                                 <span className={"iconfont icon-zhankai"} />
                             </div>
                         }

+ 16 - 2
src/app/[locale]/(navbar)/recharge/page.tsx

@@ -18,9 +18,23 @@ const getActivityApi = () => {
             return [];
         });
 };
+const getUserRegTypeFreeStatusApi = () => {
+    return server
+        .request<any>({
+            url: "/v1/api/user/user_reg_type_free_status",
+            method: "post",
+        })
+        .then((res) => {
+            return res.data;
+        })
+        .catch((e) => {
+            return {};
+        });
+};
+
 const Page = async () => {
     const activities = await getActivityApi();
-    const config = await getConfigApi();
+    const config = await getUserRegTypeFreeStatusApi();
     /// 如果数组不为空, 则有活动
     const hasEndTimeActivities = activities.length > 0;
     const current = activities.find((item) => item.end_time > 0)?.end_time;
@@ -137,7 +151,7 @@ const Page = async () => {
                         </div>
 
                         {/*  3 */}
-                        {config.show_free_game === 1 && (
+                        {config.status && (
                             <div
                                 className={
                                     "mt-[10px] flex rounded-[0.0347rem] bg-[#fbe6c6]" +

+ 7 - 1
src/app/[locale]/(navbar)/transactions/Bets.tsx

@@ -25,7 +25,13 @@ const Bets = () => {
 
     const getDepositsData = async () => {
         return getWithdrawsApi(params.current).then((res) => {
-            setSourceData((value) => ({ page: res.page, list: [...value.list, ...res.data] }));
+            const newData = (res.data || []).map((item) => {
+                return {
+                    ...item,
+                    amount: -item.amount
+                };
+            });
+            setSourceData((value) => ({ page: res.page, list: [...value.list, ...newData] }));
             return res;
         });
     };

+ 9 - 1
src/app/[locale]/(navbar)/withdraw/WithdrawWidget.tsx

@@ -76,8 +76,16 @@ const MobileField: FC<MobileFieldProps> = (props) => {
         }
     };
     const onRealValueChange = (value: string) => {
+        // console.log('prefix', prefix)
+        let account_no = value
+        if (prefix.type === 1) {
+            account_no = value.replace(/[^0-9]/g, '').replace(/[\-]/g, '').slice(0,11)
+            // console.log('account_no', value.replace(/\D/g, ''))
+            // account_no = account_no.slice(0,3)
+        }
         if (onChange) {
-            onChange({ account_no: value, channel_id: prefix.id, type: prefix.type });
+            onChange({ account_no, channel_id: prefix.id, type: prefix.type });
+            // console.log('value', props.value)
         }
     };
     return (

+ 15 - 15
src/app/[locale]/affiliate/summary/page.tsx

@@ -9,8 +9,6 @@ import { useUserInfoStore } from "@/stores/useUserInfoStore";
 import { useRequest } from "ahooks";
 import { Mask, Toast } from "antd-mobile";
 import { useLocale, useTranslations } from "next-intl";
-
-import { CashbackTypes, Rule } from "@/api/cashback";
 import { CommissionModel } from "@/app/[locale]/affiliate/component/TabsCom";
 import Table, { TableHeaderItem } from "@/components/Table";
 import TipsModal, { ModalProps } from "@/components/TipsModal";
@@ -25,31 +23,31 @@ interface Props {}
 
 const RulesClient = () => {
     const t = useTranslations("cashback");
-    const [rules, setRules] = useState<any[]>([]);
+    const [rules, setRules] = useState<any>([]);
     const [visible, setVisible] = useState(false);
     const columns: TableHeaderItem[] = [
         {
             title: <div className={"text-center text-[#98a7b5]"}>Nivel Agente</div>,
-            dataIndex: "level",
+            dataIndex: "agent_level",
             align: "center",
-            render: (item: Rule) => (
-                <div className={"text-[0.12rem] text-[#98a7b5]"}>{item.level}</div>
+            render: (item: any) => (
+                <div className={"text-[0.12rem] text-[#98a7b5]"}>{item?.agent_level}</div>
             ),
         },
         {
             title: <div className={"text-center text-[#98a7b5]"}>Apostas Validas</div>,
-            dataIndex: "aposta",
+            dataIndex: "bet",
             align: "center",
-            render: (item: Rule) => (
-                <div className={"text-[0.12rem] text-[#98a7b5]"}>{item.aposta} Dez mil+</div>
+            render: (item: any) => (
+                <div className={"text-[0.12rem] text-[#98a7b5]"}>{item?.bet} Dez mil+</div>
             ),
         },
         {
             title: <div className={"text-center text-[#98a7b5]"}>Comissão</div>,
-            dataIndex: "cashback",
-            render: (item: Rule) => (
+            dataIndex: "ratio",
+            render: (item: any) => (
                 <div className={"text-center text-[0.12rem] text-[#db922b]"}>
-                    {item.cashback}
+                    {item?.ratio}
                     <span className={"text-[#98a7b5]"}>/Dez mill</span>
                 </div>
             ),
@@ -61,12 +59,14 @@ const RulesClient = () => {
 
     const getCashBackApi = async () => {
         return server
-            .request<CashbackTypes>({
-                url: "/v1/api/front/activity_cash",
+            .request<any>({
+                url: "/v1/api/user/get_user_config_agent_info",
                 method: "post",
             })
             .then((res) => {
-                return res.data;
+                return {
+                    rules: res.data || []
+                };
             })
             .catch((error) => {
                 return {

+ 22 - 13
src/components/Card/Card.tsx

@@ -41,11 +41,17 @@ const Card: FC<PropsWithChildren<CardProps>> = (props) => {
             router.push("/deposit");
             return;
         }
-
-        const params = {
+        let params: any = {
             id: game.id + "",
             mode: groupType!,
         };
+        // demo试玩
+        if (game?.demo) {
+            params = {
+                id: game.id + "",
+                demo: game.demo,
+            };
+        }
         getGameUrl(brandRef.current!, params);
     };
     return (
@@ -78,7 +84,7 @@ const Card: FC<PropsWithChildren<CardProps>> = (props) => {
                     <div className={styles.cardWrap} style={{ width: "1.1rem" }}>
                         <img
                             src={item?.game_icon}
-                            alt={item?.game_name_cn}
+                            alt={item?.game_name_cn +'-'+ item?.category_name}
                             className={"h-[100%] w-[100%]"}
                         />
                     </div>
@@ -86,16 +92,19 @@ const Card: FC<PropsWithChildren<CardProps>> = (props) => {
                         <p className={"h-[0.6rem]"}>{item?.game_name_cn}</p>
 
                         <div className={"flex w-[2.2rem] justify-around"}>
-                            {/*<Button*/}
-                            {/*    onClick={playGameHandler}*/}
-                            {/*    className={*/}
-                            {/*        "h-[0.39rem] w-[0.89rem] rounded-[0.05rem] text-[0.15rem]" +*/}
-                            {/*        " bg-[#3a3a3a]" +*/}
-                            {/*        " font-bold"*/}
-                            {/*    }*/}
-                            {/*>*/}
-                            {/*    {t("demo")}*/}
-                            {/*</Button>*/}
+                            {/* 只是PG游戏展示demo试玩按钮 */}
+                            {
+                               (item?.category_name === 'Pragmaticplay' || item?.category_name === 'PP') && <Button
+                                    onClick={() => playGameHandler({...item!, demo: 1})}
+                                    className={
+                                    "h-[0.39rem] w-[0.89rem] rounded-[0.05rem] text-[0.15rem]" +
+                                    " bg-[#3a3a3a]" +
+                                    " font-bold"
+                                    }
+                                >
+                                    {t("demo")}
+                                </Button> 
+                            }
                             <Button
                                 onClick={() => playGameHandler(item!)}
                                 style={{

+ 1 - 1
src/components/Card/SwiperGroup.tsx

@@ -60,7 +60,7 @@ const HomeSwiper: FC<PropsWithChildren<SwiperGroupProps>> = (props) => {
         .map((_, index) => {
             return {
                 key: index,
-                data: gameList.slice(index * lineNum, index * lineNum + lineNum),
+                data: gameList.slice(index * lineNum, index * lineNum + lineNum).map(subItem => ({ ...subItem, category_name: group.category_name }))
             };
         });
     const prev = () => {

+ 9 - 2
src/components/ModalPopup/SlotsModal/index.tsx

@@ -217,16 +217,23 @@ const SlotsClient: FC<SlotsClientProps> = (props) => {
         }, 200);
         slotsRef.current?.play();
 
+        const Interval = setInterval(() => {
+            const num = Math.floor(Math.random() * 99) + 1
+            setRatio(() => (numberPadding(num, 2)))
+        }, 500)
+
         // 数据获取
         getGiveReceiveApi(params as SlotParams)
             .then((res) => {
                 setTimeout(() => {
+                    Interval && clearInterval(Interval)
                     const rollover = flatPoint(res.data.rollover / 100);
                     slotsRef.current?.stop(numberPadding(res.data.amount));
                     setRatio(numberPadding(rollover > 100 ? 99 : rollover, 2));
-                }, 2500);
+                }, 3000);
             })
             .catch((error) => {
+                Interval && clearInterval(Interval)
                 slotsRef.current.init();
                 rotating.current = false;
                 Toast.show(t(`code.${error.data.code}`));
@@ -234,7 +241,7 @@ const SlotsClient: FC<SlotsClientProps> = (props) => {
     }, 300);
     // 结束旋转
     const endHandler = (prize: any) => {
-        rotating.current = false;
+        // rotating.current = false;
 
         onRotateAfter && onRotateAfter();
     };

+ 17 - 14
src/components/ModalPopup/WalletDescribeModal/index.tsx

@@ -60,8 +60,8 @@ export const BalanceContent = (props: { wallet: Wallet }) => {
     );
 };
 
-export const BonusContent = (props: { wallet: Wallet }) => {
-    const { wallet } = props;
+export const BonusContent = (props: { wallet: Wallet, handleAcquire?: any }) => {
+    const { wallet, handleAcquire } = props;
     const t = useTranslations("ProfilePage");
     return (
         <div>
@@ -77,12 +77,15 @@ export const BonusContent = (props: { wallet: Wallet }) => {
                 <li>{t("bonusDesc2")}</li>
                 <li>{t("bonusDesc3")}</li>
             </ul>
+            {
+                handleAcquire && <a className={`carteira-box ${wallet.is_point_transfer ? 'active' : ''}`} onClick={() => handleAcquire(2, wallet.is_point_transfer)}>{t("carteira")}</a>
+            }
         </div>
     );
 };
 
-export const FreeContent = (props: { wallet: Wallet }) => {
-    const { wallet } = props;
+export const FreeContent = (props: { wallet: Wallet, handleAcquire?: any }) => {
+    const { wallet, handleAcquire } = props;
     const t = useTranslations("ProfilePage");
     return (
         <div>
@@ -90,21 +93,21 @@ export const FreeContent = (props: { wallet: Wallet }) => {
                 difference={wallet.target_free_score_rollover - wallet.current_free_score_rollover}
                 type={t("free")}
                 current={wallet.free_score || 0}
-                percentage={percentage(
-                    wallet.current_free_score_rollover,
-                    wallet.target_free_score_rollover
-                )}
+                percentage={percentage(wallet.current_free_score_rollover, wallet.target_free_score_rollover)}
             />
             <p className={"text-center"}>{t("freeArticle")}</p>
             <ul className={"ml-[0.1389rem] list-decimal text-[0.12rem] text-[#666]"}>
                 <li>{t("freeDesc1")}</li>
                 <li>{t("freeDesc2")}</li>
             </ul>
+            {
+                handleAcquire && <a className={`carteira-box ${wallet.is_free_transfer ? 'active' : ''}`} onClick={() => handleAcquire(3, wallet.is_free_transfer)}>{t("carteira")}</a>
+            }
         </div>
     );
 };
-export const ReplayContent = (props: { wallet: Wallet }) => {
-    const { wallet } = props;
+export const ReplayContent = (props: { wallet: Wallet, handleAcquire?: any }) => {
+    const { wallet, handleAcquire } = props;
     const t = useTranslations("ProfilePage");
     return (
         <div>
@@ -112,16 +115,16 @@ export const ReplayContent = (props: { wallet: Wallet }) => {
                 difference={wallet.target_lose_score_rollover - wallet.current_lose_score_rollover}
                 type={t("replay")}
                 current={wallet.lose_score || 0}
-                percentage={percentage(
-                    wallet.current_lose_score_rollover,
-                    wallet.target_lose_score_rollover
-                )}
+                percentage={percentage(wallet.current_lose_score_rollover, wallet.target_lose_score_rollover)}
             />
             <p className={"text-center"}>{t("replayArticle")}</p>
             <ul className={"ml-[0.1389rem] list-decimal text-[0.12rem] text-[#666]"}>
                 <li>{t("replayDesc1")}</li>
                 <li>{t("replayDesc2")}</li>
             </ul>
+            {
+                handleAcquire && <a className={`carteira-box ${wallet.is_lose_transfer ? 'active' : ''}`} onClick={() => handleAcquire(4, wallet.is_lose_transfer)}>{t("carteira")}</a>
+            }
         </div>
     );
 };

+ 16 - 10
src/components/Tabs/index.tsx

@@ -42,16 +42,22 @@ const Transactions: FC<PropsWithChildren<Props>> = (props) => {
                         key={tab.id}
                         className={styles.badge}
                         title={
-                            <Badge
-                                content={tab.content > 0 ? tab.content : null}
-                                style={{
-                                    "--right": "-0.0972rem",
-                                    "--top": "8px",
-                                }}
-                                color={"#ff311b"}
-                            >
-                                {tab.name}
-                            </Badge>
+                            // <Badge
+                            //     content={tab.content > 0 ? tab.content : null}
+                            //     style={{
+                            //         "--right": "-0.1rem",
+                            //         "--top": "8px",
+                            //     }}
+                            //     color={"#ff311b"}
+                            // >
+                            //     {tab.name}
+                            // </Badge>
+                            <div style={{position: 'relative'}}>
+                              {tab.name}
+                              {
+                                tab.content > 0 && <div className={`mr-[0.1rem] h-[0.15rem] w-[0.15rem] text-[#fff] flex items-center justify-center`} style={{position: 'absolute', borderRadius: "0.075rem", backgroundColor: "#ff311b",  fontSize: "0.1rem", top: '-0.02rem', right: '-0.24rem'}}>{tab.content}</div>
+                              }
+                            </div>
                         }
                     >
                         {tab.render}

+ 4 - 4
src/components/Tabs/style.module.scss

@@ -1,13 +1,13 @@
 
 .badge{
   :global(.adm-badge-content){
-    width: 0.1806rem;
-    height: 0.1389rem;
+    // width: 0.1806rem;
+    // height: 0.1389rem;
     display: flex;
     justify-content: center;
     align-items: center;
-    padding: 1px 0;
-    font-size: 0.1111rem;
+    padding: 5px;
+    font-size: 0.12rem;
   }
 }
 

+ 5 - 3
src/hooks/useGame.tsx

@@ -1,6 +1,7 @@
 import { GameListRep, GameRequest, getGameDetailApi } from "@/api/home";
-import { useRouter } from "@/i18n/routing";
+import { useRouter, defaultLocale } from "@/i18n/routing";
 import { brandList } from "@/utils/constant";
+import { getCookies } from "@/utils/Cookies";
 import { Toast } from "antd-mobile";
 import { useTranslations } from "next-intl";
 // 地址白名单
@@ -15,11 +16,12 @@ const useGame = () => {
             maskStyle: { zIndex: 99999, background: "rgba(0,0,0,0.5)" },
         });
         const brand = brandList.find((item) => item.gid === game.game_id)?.brand ?? "";
-        getGameDetailApi(params)
+        const lang = getCookies("language") || defaultLocale;
+        getGameDetailApi({...params, language: lang === 'br' ? 'pt' : lang})
             .then((res) => {
                 Toast.clear();
                 if (res.data && res.data.game_url) {
-                    const url = `${res.data?.game_url}&brand=${brand}&return_url=${process.env.NEXT_PUBLIC_SHARE_URL}`;
+                    const url = `${encodeURI(res.data.game_url)}&brand=${brand}&return_url=${process.env.NEXT_PUBLIC_SHARE_URL}`;
                     const protocol = new URL(url).protocol;
                     if (
                         whiteUrls.indexOf(window.location.hostname) !== -1 ||