Ver Fonte

侧边栏 福利中心 低保 首冲 绑定

zhejiushizhuce há 2 anos atrás
pai
commit
4393ab8a2e
44 ficheiros alterados com 638 adições e 12 exclusões
  1. 13 2
      src/App.js
  2. 18 0
      src/Global.js
  3. 3 0
      src/api/config.js
  4. BIN
      src/assets/bindPrompt/btn.png
  5. BIN
      src/assets/bindPrompt/connect_now_en.png
  6. BIN
      src/assets/bindPrompt/connect_now_es.png
  7. BIN
      src/assets/bindPrompt/connect_now_pt.png
  8. BIN
      src/assets/bindPrompt/connect_now_ru.png
  9. BIN
      src/assets/firstPay/bglight.png
  10. BIN
      src/assets/firstPay/button.png
  11. BIN
      src/assets/firstPay/en.png
  12. BIN
      src/assets/firstPay/es.png
  13. BIN
      src/assets/firstPay/pack.png
  14. BIN
      src/assets/firstPay/percent.png
  15. BIN
      src/assets/firstPay/pt.png
  16. BIN
      src/assets/firstPay/ru.png
  17. BIN
      src/assets/protect/p_bg.png
  18. BIN
      src/assets/protect/p_btn.png
  19. BIN
      src/assets/protect/p_close.png
  20. BIN
      src/assets/welfare/bind.png
  21. BIN
      src/assets/welfare/first_pay.png
  22. BIN
      src/assets/welfare/leftb.png
  23. BIN
      src/assets/welfare/leftb_1.png
  24. BIN
      src/assets/welfare/protect.png
  25. 33 0
      src/components/Loading/LoadingCircular.jsx
  26. 3 0
      src/features/mainSlice.js
  27. 8 5
      src/layout/BottomNav/index.jsx
  28. 6 0
      src/layout/BottomNav/styles.module.scss
  29. 8 0
      src/layout/Layout.jsx
  30. 9 0
      src/locales/languages/en_US.json
  31. 5 0
      src/locales/languages/es_MX.json
  32. 5 0
      src/locales/languages/pt_BR.json
  33. 5 0
      src/locales/languages/ru_RU.json
  34. 5 0
      src/locales/languages/zh_TW.json
  35. 14 0
      src/styles/_global.scss
  36. 1 0
      src/styles/_vars.scss
  37. 3 0
      src/widgets/WBindPrompt/index.jsx
  38. 25 5
      src/widgets/WBindPrompt/styles.module.scss
  39. 54 0
      src/widgets/WFirstPay/index.jsx
  40. 171 0
      src/widgets/WFirstPay/styles.module.scss
  41. 57 0
      src/widgets/WProtect/index.jsx
  42. 101 0
      src/widgets/WProtect/styles.module.scss
  43. 47 0
      src/widgets/WWelfarebar/index.jsx
  44. 44 0
      src/widgets/WWelfarebar/styles.module.scss

+ 13 - 2
src/App.js

@@ -44,11 +44,11 @@ import Layout from "@layout/Layout";
 import {
     getBFP,
     getFetchStatus,
-    getHallServerUrl, getKickState, getOpenPay, getPromoteInstall,getPopWheel,
+    getHallServerUrl, getKickState, getOpenPay, getPromoteInstall, getPopWheel,
     getUserID,
     getUserInfo,
     isLogined,
-    updateCurrGame, updateOpenPay
+    updateCurrGame, updateOpenPay, getIsGuest, getPopBindPhone
 } from '@features/mainSlice';
 import {useDispatch, useSelector} from "react-redux";
 import {REQ_STATUS} from "@api/config";
@@ -103,6 +103,8 @@ const App = () => {
     const promoteInstall=useSelector(getPromoteInstall);
     const popWheel=useSelector(getPopWheel);
     const openPay=useSelector(getOpenPay);
+    const guest=useSelector(getIsGuest);
+    const popBindPhone=useSelector(getPopBindPhone);
     const muiTheme = createTheme({
         direction: direction,
     });
@@ -181,6 +183,7 @@ const App = () => {
             //Mail红点屏蔽
             dispatch(reqMailCheck());
             dispatch(reqFavoGet());
+            checkOpenBindPrompt();
         }
         else
         {
@@ -265,6 +268,14 @@ const App = () => {
             }
         },time);
     }
+    //检查打开绑定提示
+    const checkOpenBindPrompt=()=>{
+        if (guest!==1)return;
+        if (popBindPhone!==1)return;
+        if (global.ispopBindPhone===1)return;
+        global.showBindPrompt();
+        global.ispopBindPhone=1;
+    }
     //app Effect
     //初始化
     useEffect(() => {

+ 18 - 0
src/Global.js

@@ -82,4 +82,22 @@ global.showBindPrompt=()=>{
 global.hideBindPrompt=()=>{
     if (global.bindPrompt)global.bindPrompt.hide();
 }
+global.showProtectReward=()=>{
+    if (global.protectReward)global.protectReward.show();
+}
+global.hideProtectReward=()=>{
+    if (global.protectReward)global.protectReward.hide();
+}
+global.showLoadingCircular=(showMask=false)=>{
+    if (global.loadingCircular)global.loadingCircular.show(showMask);
+}
+global.hideLoadingCircular=()=>{
+    if (global.loadingCircular)global.loadingCircular.hide();
+}
+global.showFirstPay=()=>{
+    if (global.firstPay)global.firstPay.show();
+}
+global.hideFirstPay=()=>{
+    if (global.firstPay)global.firstPay.hide();
+}
 //wd pass

+ 3 - 0
src/api/config.js

@@ -103,3 +103,6 @@ export const APP_BIND_SMS=BASE_PREFIX+"bindsms";
 export const APP_SMS_LOGIN=BASE_PREFIX+"smslogin";
 //apk
 export const APP_GAME_APK=BASE_PREFIX+"apk";
+//protect
+export const APP_PROTECT_CHECK=BASE_PREFIX+"protect/check";
+export const APP_PROTECT_GET=BASE_PREFIX+"protect/get";

BIN
src/assets/bindPrompt/btn.png


BIN
src/assets/bindPrompt/connect_now_en.png


BIN
src/assets/bindPrompt/connect_now_es.png


BIN
src/assets/bindPrompt/connect_now_pt.png


BIN
src/assets/bindPrompt/connect_now_ru.png


BIN
src/assets/firstPay/bglight.png


BIN
src/assets/firstPay/button.png


BIN
src/assets/firstPay/en.png


BIN
src/assets/firstPay/es.png


BIN
src/assets/firstPay/pack.png


BIN
src/assets/firstPay/percent.png


BIN
src/assets/firstPay/pt.png


BIN
src/assets/firstPay/ru.png


BIN
src/assets/protect/p_bg.png


BIN
src/assets/protect/p_btn.png


BIN
src/assets/protect/p_close.png


BIN
src/assets/welfare/bind.png


BIN
src/assets/welfare/first_pay.png


BIN
src/assets/welfare/leftb.png


BIN
src/assets/welfare/leftb_1.png


BIN
src/assets/welfare/protect.png


+ 33 - 0
src/components/Loading/LoadingCircular.jsx

@@ -0,0 +1,33 @@
+import React, {useEffect, useState} from "react";
+import {CircularProgress} from "@mui/material";
+
+const LoadingCircular=()=>{
+    const [isShow, setIsShow] = useState(false);
+    const [showMask,setShowMask]=useState(false);
+    const show=(showMask=false)=>{
+        setIsShow(true);
+        setShowMask(showMask);
+    }
+    const hide=()=>{
+        setIsShow(false);
+    }
+    useEffect(()=>{
+        const loadingCircular={
+            show,
+            hide
+        };
+        global.loadingCircular=loadingCircular;
+    },[])
+    return (
+        <>
+            {
+                isShow? (
+                    <div className={`loading-circular ${showMask?'loading-circular_mask':''}`}>
+                        <CircularProgress color="success" size={40} thickness={4}/>
+                    </div>
+                ):(<></>)
+            }
+        </>
+    )
+}
+export default LoadingCircular;

+ 3 - 0
src/features/mainSlice.js

@@ -803,6 +803,9 @@ export const getIsGuest=(state)=>{
 export const getUpgradeBonus=(state)=>{
     return state.main.upgradeBonus;
 }
+export const getPopBindPhone=(state)=>{
+    return state.main.popBindPhone;
+}
 //数据获取
 export default Main.reducer;
 

+ 8 - 5
src/layout/BottomNav/index.jsx

@@ -22,6 +22,8 @@ import {ROUTE_PATH} from "@constants/routes";
 import {useSelector} from "react-redux";
 import {getMailNew} from "@features/mailSlice";
 import {checkIsStandalone} from "@utils/helpers";
+import {useThemeProvider} from "@contexts/themeContext";
+import {APP_THEME} from "@constants/app";
 const i18n=global.i18n;
 
 const BottomNav = () => {
@@ -30,7 +32,8 @@ const BottomNav = () => {
     const isStoreRoute = useStoreRoute();
     const {setCartOpen} = useShopProvider();
     const mailNew=useSelector(getMailNew);
-    const isStandalone=checkIsStandalone()
+    const isStandalone=checkIsStandalone();
+    const {theme} = useThemeProvider();
 
     // return (
     //     <div className={styles.container}>
@@ -83,7 +86,7 @@ const BottomNav = () => {
                 {/*    <use xlinkHref={`${ticon_gift}#gift`} />*/}
                 {/*</svg>*/}
                 {/*<TabGift className={styles.icon}/>*/}
-                <svg className={styles.bottomicon}>
+                <svg className={`${styles.bottomicon} ${theme===APP_THEME.LIGHT?styles.bottomicon_light:''}`}>
                     <use xlinkHref={`${symbol}#icon_Giftbox`}/>
                 </svg>
                 <span className={styles.bottomtxt}>{i18n.t("tab.promotion")}</span>
@@ -93,7 +96,7 @@ const BottomNav = () => {
                 {/* <use xlinkHref={`${symbol_m}#icon_Home_1`} />*/}
                 {/*</svg>*/}
                 {/*<TabWithdraw className={styles.icon}/>*/}
-                <svg className={styles.bottomicon}>
+                <svg className={`${styles.bottomicon} ${theme===APP_THEME.LIGHT?styles.bottomicon_light:''}`}>
                     <use xlinkHref={`${symbol}#icon_WithDraw`}/>
                 </svg>
                 <span className={styles.bottomtxt}>{i18n.t("tab.withdraw")}</span>
@@ -111,7 +114,7 @@ const BottomNav = () => {
                 {/*    <use xlinkHref={`${symbol_m}#icon_Account`} />*/}
                 {/*</svg>*/}
                 {/*<TabMessage className={styles.icon}/>*/}
-                <svg className={styles.bottomicon}>
+                <svg className={`${styles.bottomicon} ${theme===APP_THEME.LIGHT?styles.bottomicon_light:''}`}>
                     <use xlinkHref={`${symbol}#icon_Mail`}/>
                 </svg>
                 <span className={styles.bottomtxt}>{i18n.t("tab.message")}</span>
@@ -121,7 +124,7 @@ const BottomNav = () => {
                 {/*    <use xlinkHref={`${symbol}#icon_Chat`} />*/}
                 {/*</svg>*/}
                 {/*<TabSett className={styles.icon}></TabSett>*/}
-                <svg className={styles.bottomicon}>
+                <svg className={`${styles.bottomicon} ${theme===APP_THEME.LIGHT?styles.bottomicon_light:''}`}>
                     <use xlinkHref={`${symbol}#icon_Support`}/>
                 </svg>
                 <span className={styles.bottomtxt}>{i18n.t("tab.service")}</span>

+ 6 - 0
src/layout/BottomNav/styles.module.scss

@@ -57,6 +57,12 @@
         g{
             fill: url(#gradient-vertical) #fffee7;
         }
+        &_light{
+            fill: url(#gradient-vertical-dark) #fffee7;
+            g{
+                fill: url(#gradient-vertical-dark) #fffee7;
+            }
+        }
     }
 
     & .icon_yellow{

+ 8 - 0
src/layout/Layout.jsx

@@ -33,6 +33,10 @@ import MailNew from "@components/MailNew";
 import WInstallBox from "@widgets/WInstallBox";
 import WBindPhone from "@widgets/WBindPhone";
 import WBindPrompt from "@widgets/WBindPrompt";
+import WWelfarebar from "@widgets/WWelfarebar";
+import WProtect from "@widgets/WProtect";
+import LoadingCircular from "@components/Loading/LoadingCircular";
+import WFirstPay from "@widgets/WFirstPay";
 const PageNotFound = lazy(() => import('@pages/PageNotFound'));
 
 const Layout=({...props})=>{
@@ -85,6 +89,7 @@ const Layout=({...props})=>{
                     <Sidebar/>
                     <Navbar/>
                     {isMobile() && <BottomNav/>}
+                    <WWelfarebar/>
                 </div>
             </>
         )
@@ -126,6 +131,8 @@ const Layout=({...props})=>{
                 {/*<WInstallBox/>*/}
                 <WBindPhone/>
                 <WBindPrompt/>
+                <WProtect/>
+                <WFirstPay/>
             </>
         )
     }
@@ -134,6 +141,7 @@ const Layout=({...props})=>{
             <>
                 <DropCoins/>
                 <MailNew/>
+                <LoadingCircular/>
             </>
         )
     }

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

@@ -625,6 +625,15 @@
     "content": "After binding, you can log in to the game via your mobile phone number, which is safe!",
     "tips": "Play guest accounts. If you replace or reinstall your phone, you will lose your account. Immediate membership is recommended"
   },
+  "protect": {
+    "title": "Relief Funds",
+    "des": "You can get it when your balance is less than ",
+    "tips": "Only 1 time a day",
+    "btn_get": "To obtain"
+  },
+  "firstPay": {
+    "only_need": "Only need"
+  },
   "web": {
     "activity": {
       "redpack_not_available": "There is no RedPack",

+ 5 - 0
src/locales/languages/es_MX.json

@@ -609,6 +609,11 @@
     "btn_submit": "ENVIAR",
     "tips": "Vincula tu móvil y obtén una recompensa de {0} fichas"
   },
+  "bindPrompt": {
+    "title": "Recompensa vinculante",
+    "content": "Después de la vinculación, podrás iniciar sesión en el juego a través de tu número de teléfono móvil, ¡lo cual es seguro!",
+    "tips": "Cuentas de invitado de Play. Si reemplazas o reinstalas tu teléfono, perderás tu cuenta. Se recomienda la membresía inmediata"
+  },
   "web": {
     "activity": {
       "redpack_not_available": "No hay RedPack",

+ 5 - 0
src/locales/languages/pt_BR.json

@@ -609,6 +609,11 @@
     "btn_submit": "ENVIAR",
     "tips": "Vincule seu celular e ganhe {0} fichas de recompensa"
   },
+  "bindPrompt": {
+    "title": "Recompensa vinculativa",
+    "content": "Após a vinculação, você pode fazer login no jogo usando seu número de celular, que é seguro!",
+    "tips": "Jogue contas de convidado. Se você substituir ou reinstalar seu telefone, você perderá sua conta. A assinatura imediata é recomendada"
+  },
   "web": {
     "activity": {
       "redpack_not_available": "Não há RedPack",

+ 5 - 0
src/locales/languages/ru_RU.json

@@ -609,6 +609,11 @@
     "btn_submit": "ПОДТВЕРДИТЬ",
     "tips": "Свяжите свой мобильный телефон и получите награду - {0} фишек"
   },
+  "bindPrompt": {
+    "title": "Обязательное вознаграждение",
+    "content": "После привязки вы сможете войти в игру через свой номер мобильного телефона, это безопасно!",
+    "tips": "Играйте в гостевые аккаунты. Если вы замените или переустановите свой телефон, вы потеряете свой аккаунт. Рекомендуется немедленное членство"
+  },
   "web": {
     "activity": {
       "redpack_not_available": "Нет RedPack",

+ 5 - 0
src/locales/languages/zh_TW.json

@@ -609,6 +609,11 @@
     "btn_submit": "提交",
     "tips": "連接您的手機並獲得 {0} 積分獎勵"
   },
+  "bindPrompt": {
+    "title": "綁定獎勵",
+    "content": "綁定後即可透過手機號碼登入遊戲,安全!",
+    "tips": "玩訪客帳戶。如果您更換或重新安裝手機,您將遺\u200B\u200B失您的帳戶。建議立即加入會員"
+  },
   "web": {
     "activity": {
       "redpack_not_available": "沒有紅包",

+ 14 - 0
src/styles/_global.scss

@@ -230,5 +230,19 @@ input, input::placeholder {
     width: 100vw;
     height: 100vh;
 }
+.loading-circular{
+    display: flex;
+    flex-direction: row;
+    align-items: center;
+    justify-content: center;
+    position: fixed;
+    inset: 0px;
+    z-index: var(--zindex-effect);
+    background-color: rgba(0, 0, 0, 0);
+    transition: all var(--transition);
+    &_mask{
+        background-color: rgba(0, 0, 0, 0.3);
+    }
+}
 body.progressier-blurring > *:not(.no-blurring){-webkit-filter:none !important;filter: none !important;pointer-events:none;z-index: 888 !important;}
 

+ 1 - 0
src/styles/_vars.scss

@@ -65,6 +65,7 @@ $width-desktop-big-max:1564px;
     --side-open:250px;
     --side-close:65px;
     --zindex-in:500;
+    --zindex-welfare:600;
     --zindex-second:1000;
     --zindex-drawer:1200;
     --zindex-popup:1300;

+ 3 - 0
src/widgets/WBindPrompt/index.jsx

@@ -42,6 +42,9 @@ const WBindPrompt=({})=>{
                                 <span className={styles.title}>{i18n.t("bindPrompt.title")}</span>
                                 <span className={styles.reward}>{global.DOLLAR+""+regCoins}</span>
                                 <span className={styles.des}>{i18n.t("bindPrompt.content")}</span>
+                                <button className={styles.btn_now}>
+                                    <img src={require('@assets/bindPrompt/connect_now_'+i18n.language+'.png')}/>
+                                </button>
                             </div>
                             <span className={styles.tips}>{i18n.t("bindPrompt.tips")}</span>
                         </div>

+ 25 - 5
src/widgets/WBindPrompt/styles.module.scss

@@ -1,4 +1,5 @@
 $bg:"./../../assets/bindPrompt/bg.png";
+$btn:"./../../assets/bindPrompt/btn.png";
 .continer{
   display: flex;
   flex-direction: column;
@@ -14,6 +15,7 @@ $bg:"./../../assets/bindPrompt/bg.png";
   display: flex;
   flex-direction: column;
   width: 100%;
+  max-width: 25.875rem;
   background: url($bg);
   aspect-ratio: 773/497;
   background-size: 100% 100%;
@@ -25,13 +27,13 @@ $bg:"./../../assets/bindPrompt/bg.png";
     flex-direction: column;
     width: 100%;
     align-items: center;
-    padding: 1.8rem 1rem 1.8rem 4rem;
+    padding: 1.8rem 1rem 0rem 4rem;
     transform: rotate(-6deg);
-    gap: 1rem;
+    gap: 0.75rem;
     & .title{
       color: #6a005e;
       font-weight: bold;
-      font-size: 1.3rem;
+      font-size: 1.1rem;
     }
     & .reward{
       color: #3244c3;
@@ -41,7 +43,25 @@ $bg:"./../../assets/bindPrompt/bg.png";
     & .des{
       color: #6a005e;
       padding: 0rem 2.5rem;
-      line-height: 1.2rem;
+      font-size: 0.8rem;
+      line-height: 1rem;
+    }
+    & .btn_now{
+      display: flex;
+      flex-direction: row;
+      align-items: center;
+      justify-content: center;
+      background: url($btn);
+      width: 50%;
+      aspect-ratio: 248/85;
+      background-size: 100% 100%;
+      transform: rotate(5.5deg);
+      margin-top: -1rem;
+      img{
+        transform: rotate(-5.5deg);
+        height: 30%;
+        width: auto;
+      }
     }
   }
   & .tips{
@@ -49,7 +69,7 @@ $bg:"./../../assets/bindPrompt/bg.png";
     flex-direction: row;
     align-items: center;
     justify-content: center;
-    padding: 1rem 1rem 1.8rem 4rem;
+    padding: 0.4rem 1rem 1.8rem 4rem;
     color: #fff;
     transform: rotate(-6deg);
     line-height: 0.8rem;

+ 54 - 0
src/widgets/WFirstPay/index.jsx

@@ -0,0 +1,54 @@
+import {useEffect, useState} from "react";
+import styles from "./styles.module.scss";
+import Modal from "@mui/material/Modal";
+import Fade from "@mui/material/Fade";
+import Grow from "@mui/material/Grow";
+const i18n=global.i18n;
+
+const WFirstPay=()=>{
+    const [isShow, setIsShow] = useState(false);
+    const show=()=>{
+        setIsShow(true);
+    }
+    const hide=()=>{
+        setIsShow(false);
+    }
+    useEffect(()=>{
+        const firstPay={
+            show,
+            hide
+        };
+        global.firstPay=firstPay;
+        return ()=>{
+        }
+    },[])
+    return (
+        <Modal open={isShow} onClose={hide} closeAfterTransition>
+            <Fade in={isShow} timeout={500}>
+                <div className={styles.container}>
+                    <Grow in={isShow} timeout={500}>
+                        <div className={styles.f_con}>
+                            <img className={styles.title} src={require(`@assets/firstPay/${i18n.language}.png`)}/>
+                            <div className={styles.f_main}>
+                                <img className={styles.bglight} src={require('@assets/firstPay/bglight.png')}/>
+                                <div className={styles.pack_con}>
+                                    <div className={styles.percent_con}>
+                                        <div data-title="+50%" className={styles.text}>+50%</div>
+                                    </div>
+                                    <div className={styles.bonus_con}>
+                                        <div data-title={"20"} className={styles.bonus}>20</div>
+                                    </div>
+                                </div>
+                            </div>
+                            <button className={styles.f_btnpay}>
+                                <span data-title={i18n.t("firstPay.only_need")} className={styles.label}>{i18n.t("firstPay.only_need")}</span>
+                                <span data-title={global.DOLLAR+10} className={styles.pay_num}>{global.DOLLAR+10}</span>
+                            </button>
+                        </div>
+                    </Grow>
+                </div>
+            </Fade>
+        </Modal>
+    )
+}
+export default WFirstPay;

+ 171 - 0
src/widgets/WFirstPay/styles.module.scss

@@ -0,0 +1,171 @@
+$bg:"./../../assets/firstPay/pack.png";
+$btnbg:"./../../assets/firstPay/button.png";
+$pbg:"./../../assets/firstPay/percent.png";
+.container{
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  width: 100%;
+  height: 100%;
+  padding: 1rem;
+  pointer-events: none;
+  position: relative;
+}
+.f_con{
+  display: flex;
+  flex-direction: column;
+  width: 100%;
+  max-width: 25.875rem;
+  pointer-events: auto;
+  align-items: center;
+  position:relative;
+  gap: 0.5rem;
+  & .title{
+    max-width: 90%;
+    height: auto;
+  }
+  & .f_main{
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    justify-content: center;
+    width: 80%;
+    aspect-ratio: 583/442;
+    height: auto;
+    position: relative;
+    & .bglight{
+      width: 127%;
+      position: absolute;
+      z-index: 1;
+      pointer-events: none;
+      animation: bg_light_ani 20s linear infinite;
+      transform: translateZ(0);
+    }
+    & .pack_con{
+      display: flex;
+      flex-direction: column;
+      position: absolute;
+      align-items: center;
+      justify-content: flex-end;
+      z-index: 2;
+      width: 100%;
+      aspect-ratio: 583/442;
+      background: url($bg);
+      background-size: 100% 100%;
+      & .percent_con{
+        display: flex;
+        flex-direction: row;
+        align-items: center;
+        justify-content: center;
+        position: absolute;
+        z-index: 2;
+        background: url($pbg);
+        background-size: 100% 100%;
+        width: 24%;
+        aspect-ratio: 137/136;
+        right: 16%;
+        bottom: 15%;
+        transform: rotate(-10deg);
+        & .text{
+          &::before{
+            content: attr(data-title);
+            position: absolute;
+            background-image: linear-gradient(to right,#ffd63c,#ffd63c, #fdfdd1);
+            background-clip: text;
+            -webkit-background-clip: text;
+            -webkit-text-fill-color: transparent;
+            -webkit-text-stroke: 0px #483be3;
+            font-weight: bold;
+            font-size: 1rem;
+            pointer-events: none;
+          }
+          font-weight: bold;
+          font-size: 1rem;
+          -webkit-text-stroke: 2px #483be3;
+          filter: drop-shadow(0 1px 1px #3615a0);
+        }
+      }
+      & .bonus_con{
+        display: flex;
+        flex-direction: row;
+        align-items: center;
+        justify-content: center;
+        width: 100%;
+        height: 21%;
+        & .bonus{
+          &::before{
+            content: attr(data-title);
+            position: absolute;
+            background-image: linear-gradient(to bottom,#fffd5a 0%,#fffd5a 30%,#fffdea 60%,#ffb643 70%);
+            background-clip: text;
+            -webkit-background-clip: text;
+            -webkit-text-fill-color: transparent;
+            -webkit-text-stroke: 0px #483be3;
+            font-weight: bold;
+            font-size: 1.8rem;
+            pointer-events: none;
+          }
+          font-weight: bold;
+          font-size: 1.8rem;
+          filter: drop-shadow(0 3px 1px #120519);
+        }
+      }
+    }
+  }
+  & .f_btnpay{
+    display: flex;
+    flex-direction: row;
+    align-items: center;
+    justify-content: center;
+    margin-top: 0.8rem;
+    width: 48%;
+    aspect-ratio: 347/91;
+    background: url($btnbg);
+    background-size: 100% 100%;
+    font-weight: bold;
+    font-size: 1.1rem;
+    gap: 0.5rem;
+    & .label{
+      margin-top: -0.3rem;
+      color: #fff;
+      -webkit-text-stroke: 4px #1c4014;
+      &::before{
+        content: attr(data-title);
+        position: absolute;
+        background-image: linear-gradient(to bottom,#fff,#fff);
+        background-clip: text;
+        -webkit-background-clip: text;
+        -webkit-text-fill-color: transparent;
+        -webkit-text-stroke: 0px #1c4014;
+        font-weight: bold;
+        font-size: 1.1rem;
+      }
+    }
+    & .pay_num{
+      margin-top: -0.3rem;
+      font-size: 1.2rem;
+      color: #f4eb00;
+      -webkit-text-stroke: 4px #830662;
+      &::before{
+        content: attr(data-title);
+        position: absolute;
+        background-image: linear-gradient(to bottom,#f4eb00,#f4eb00);
+        background-clip: text;
+        -webkit-background-clip: text;
+        -webkit-text-fill-color: transparent;
+        -webkit-text-stroke: 0px #830662;
+        font-weight: bold;
+        font-size: 1.2rem;
+      }
+    }
+  }
+}
+@keyframes bg_light_ani {
+  0%{
+    transform: rotate(0deg);
+  }
+  100%{
+    transform: rotate(1turn);
+  }
+}

+ 57 - 0
src/widgets/WProtect/index.jsx

@@ -0,0 +1,57 @@
+import {useEffect, useState} from "react";
+import Fade from "@mui/material/Fade";
+import Modal from "@mui/material/Modal";
+import styles from "./styles.module.scss";
+import Grow from "@mui/material/Grow";
+import SmallLoading from "@components/SmallLoading";
+const i18n=global.i18n;
+const WProtect = () => {
+    const [isShow, setIsShow] = useState(false);
+    const show=()=>{
+        setIsShow(true);
+    }
+    const hide=()=>{
+        setIsShow(false);
+    }
+    useEffect(()=>{
+        const protectReward={
+            show,
+            hide
+        };
+        global.protectReward=protectReward;
+        return ()=>{
+        }
+    },[])
+    return (
+        <Modal open={isShow} onClose={hide} closeAfterTransition>
+            <Fade in={isShow} timeout={500}>
+                <div className={styles.container}>
+                    <Grow in={isShow} timeout={500}>
+                        <div className={styles.p_con}>
+                            <button className={styles.p_close} onClick={hide}>
+                                <img src={require("@assets/protect/p_close.png")}/>
+                            </button>
+                            <div className={styles.p_content}>
+                                <div className={styles.p_info}>
+                                    <span className={styles.title}>{i18n.t("protect.title")}</span>
+                                    <div className={styles.des}>
+                                        {i18n.t("protect.des")}
+                                        <span className={styles.coin}>{global.DOLLAR+2}</span>
+                                    </div>
+                                    <div className={styles.rewad}>{global.DOLLAR+1}</div>
+                                    <span className={styles.tips}>{i18n.t("protect.tips")}</span>
+                                </div>
+                                <button className={styles.p_get_btn}>
+                                    <span className={styles.text}>
+                                        {i18n.t("protect.btn_get")}
+                                    </span>
+                                </button>
+                            </div>
+                        </div>
+                    </Grow>
+                </div>
+            </Fade>
+        </Modal>
+)
+}
+export default WProtect;

+ 101 - 0
src/widgets/WProtect/styles.module.scss

@@ -0,0 +1,101 @@
+$bg:"./../../assets/protect/p_bg.png";
+$btn_bg:"./../../assets/protect/p_btn.png";
+.container{
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  width: 100%;
+  height: 100%;
+  padding: 1rem;
+  pointer-events: none;
+  position: relative;
+}
+.p_con{
+  display: flex;
+  flex-direction: column;
+  width: 100%;
+  max-width: 25.875rem;
+  background: url($bg);
+  aspect-ratio: 719/571;
+  background-size: 100% 100%;
+  pointer-events: auto;
+  align-items: center;
+  position:relative;
+}
+.p_content{
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: space-between;
+  width: 100%;
+  height: 100%;
+}
+.p_info{
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  gap: 1rem;
+  width: 100%;
+  height: 100%;
+  & .title{
+    margin-top: 15.5%;
+    font-size: 1.1rem;
+    font-weight: bold;
+    color: #f4eb90;
+  }
+  & .des{
+    font-weight: bold;
+    color: #fff;
+    width: 48%;
+    line-height: 1rem;
+    & .coin{
+      color: #ffcc00;
+    }
+  }
+  & .rewad{
+    margin-top: 12%;
+    font-size: 1.2rem;
+    font-weight: bold;
+    color: #fbd630;
+    text-shadow:
+            -1px -1px 0 #d82b2f,
+            1px -1px 0 #d82b2f,
+            -1px  1px 0 #d82b2f,
+            1px  1px 0 #d82b2f;
+  }
+  & .tips{
+    margin-top: -1rem;
+    font-weight: bold;
+    font-size: 0.75rem;
+    color: #2563c8;
+  }
+}
+.p_get_btn{
+  display: flex;
+  flex-direction: row;
+  justify-content: center;
+  align-items: center;
+  width: 38%;
+  background: url($btn_bg);
+  background-size: 100% 100%;
+  aspect-ratio: 275/105;
+  margin-left: 0.5rem;
+  margin-bottom: 0.6rem;
+  color: #116f02;
+  font-size: 1.1rem;
+  font-weight: bold;
+  & .text{
+    margin-top: -0.3rem;
+  }
+}
+.p_close{
+  position: absolute;
+  z-index: 2;
+  top: 1rem;
+  right: 2rem;
+  img{
+    width: 2.5rem;
+    height: auto;
+  }
+}

+ 47 - 0
src/widgets/WWelfarebar/index.jsx

@@ -0,0 +1,47 @@
+import styles from './styles.module.scss';
+import {useState} from "react";
+const WelfareBtn=({children,...props})=>{
+    const [isPressed, setIsPressed] = useState(false);
+    const handleMouseDown = () => {
+        setIsPressed(true);
+    };
+
+    const handleMouseUp = () => {
+        setIsPressed(false);
+    };
+    return (
+        <button className={`${styles.wlf_btn} ${isPressed?styles.wlf_btn_press:''}`}
+                onMouseDown={handleMouseDown}
+                onMouseUp={handleMouseUp}
+                {...props}
+        >
+            {
+                children==null?(<></>):children
+            }
+        </button>
+    )
+}
+const WWelfarebar = () => {
+    return (
+        <div className={styles.container}>
+            <div className={styles.content}>
+                <WelfareBtn key={"protect"} onClick={()=>{
+                    global.showProtectReward();
+                }}>
+                    <img className={styles.wlf_protect} src={require("@assets/welfare/protect.png")}/>
+                </WelfareBtn>
+                <WelfareBtn key={"first_pay"} onClick={()=>{
+                    global.showFirstPay();
+                }}>
+                    <img className={styles.wlf_first} src={require("@assets/welfare/first_pay.png")}/>
+                </WelfareBtn>
+                <WelfareBtn key={"bind"} onClick={()=>{
+                    global.showBindPhone();
+                }}>
+                    <img className={styles.wlf_bind} src={require("@assets/welfare/bind.png")}/>
+                </WelfareBtn>
+            </div>
+        </div>
+    )
+}
+export default WWelfarebar;

+ 44 - 0
src/widgets/WWelfarebar/styles.module.scss

@@ -0,0 +1,44 @@
+$leftb:"./../../assets/welfare/leftb.png";
+$leftb_1:"./../../assets/welfare/leftb_1.png";
+.container{
+  display: flex;
+  flex-direction: column;
+  position: fixed;
+  z-index: var(--zindex-welfare);
+  left: 0;
+  bottom: 12rem;
+}
+.content{
+  display: flex;
+  flex-direction: column;
+  gap: 0.8rem;
+}
+.wlf_btn{
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  justify-content: center;
+  pointer-events: auto;
+  width: 5rem;
+  aspect-ratio: 144/162;
+  background: url($leftb);
+  background-size: 100% 100%;
+  &_press{
+    background: url($leftb_1);
+  }
+}
+.wlf_protect{
+  width: 6rem;
+  height: auto;
+  margin-top: -0.5rem;
+}
+.wlf_first{
+  width: 3.2rem;
+  height: auto;
+  margin-left: -0.5rem;
+}
+.wlf_bind{
+  width: 3.5rem;
+  height: auto;
+  margin-left: -0.5rem;
+}