소스 검색

Merge branch 'dev' of http://192.168.0.111:3000/bcwin/site_front into dev

XianCH 1 년 전
부모
커밋
abced162cf

+ 4 - 0
messages/br.json

@@ -10,5 +10,9 @@
     "login": "Login",
     "register": "Cadastre-se",
     "locale": "Preferência de Localização"
+  },
+  "Game": {
+    "demo":"Demo",
+    "join":"JUGUE"
   }
 }

+ 8 - 8
src/api/home.ts

@@ -4,35 +4,35 @@ export interface EntityGameListRep {
     /**
      * 游戏ICON
      */
-    game_icon?: string;
+    game_icon: string;
     /**
      * 游戏ID
      */
-    game_id?: string;
+    game_id: string;
     /**
      * 游戏名称
      */
-    game_name?: string;
+    game_name: string;
     /**
      * 游戏名称中文
      */
-    game_name_cn?: string;
+    game_name_cn: string;
     /**
      * 游戏类型
      */
-    game_type?: string;
+    game_type: string;
     /**
      * id
      */
-    id?: number;
+    id: number;
     /**
      * 厂商名字 besoft 等等
      */
-    provider?: string;
+    provider: string;
     /**
      * 时间
      */
-    release_date?: string;
+    release_date: string;
 }
 
 export interface GroupType {

+ 14 - 3
src/api/user.ts

@@ -1,30 +1,36 @@
 import { server } from "@/utils/server";
 
+
+// 前台用户绑定手机号
 export const getBindPhoneApi = () => {
     return server.post<any>({
         url: "/v1/api/user/bind_phone",
     });
 };
 
+// 前台用户手机号是否存在
 export const getCheckUserPhoneExistApi = (params: any) => {
-    return server.post<any>({
+    return server.get<any>({
         url: "/v1/api/user/check_user_phone_exist",
         params
     });
 };
 
+// 找回密码
 export const getFindPwdApi = () => {
     return server.post<any>({
         url: "/v1/api/user/find_pwd"
     });
 };
 
+// 前台用户谷歌登录
 export const getGoogleLoginApi = () => {
     return server.post<any>({
         url: "/v1/api/user/google_login"
     });
 };
 
+// 前台用户登录
 export const getLoginApi = (data: any) => {
     return server.post<any>({
         url: "/v1/api/user/login",
@@ -32,12 +38,14 @@ export const getLoginApi = (data: any) => {
     });
 };
 
+// 前台用户登出
 export const getLogoutApi = () => {
     return server.post<any>({
         url: "/v1/api/user/logout"
     });
 };
 
+// 前台用户注册
 export const getRegisterApi = (data: any) => {
     return server.post<any>({
         url: "/v1/api/user/register",
@@ -45,12 +53,15 @@ export const getRegisterApi = (data: any) => {
     });
 };
 
-export const getSendCodeApi = () => {
+// 前台用户注册发送验证码
+export const getSendCodeApi = (params: any) => {
     return server.get<any>({
-        url: "/v1/api/user/send_code"
+        url: "/v1/api/user/send_code",
+        params
     });
 };
 
+// 前台用户获取信息
 export const getUserInfoApi = () => {
     return server.post<any>({
         url: "/v1/api/user/user_info"

+ 1 - 15
src/app/[locale]/_home/HomeGames.tsx

@@ -1,30 +1,16 @@
 "use client";
 import { getGamesApi, GroupType } from "@/api/home";
-import { getUserApi } from "@/api/test";
 import { SwiperGroup } from "@/components/Card";
 import { FC, PropsWithChildren, useEffect, useState } from "react";
 import "swiper/css";
 interface Props {}
-const urls = [
-    "https://images.hibigwin.com/9f/202405/mqletkfLwGeZkSH.jpg",
-    "https://images.hibigwin.com/9f/202402/jLkCmSkItvcqlid.jpg",
-    "https://images.hibigwin.com/9f/202404/DDnZEhXKutDVIYn.jpg",
-    "https://images.hibigwin.com/9f/202406/wOBQjusbGUZkBMA.jpg",
-    "https://images.hibigwin.com/9f/202402/jLkCmSkItvcqlid.jpg",
-    "https://images.hibigwin.com/9f/202405/mqletkfLwGeZkSH.jpg",
-    "https://images.hibigwin.com/9f/202407/LPpEiiltiXwcdYz.jpg",
-    "https://images.hibigwin.com/9f/202406/veFfaahiTGAyDpy.jpg",
-];
+
 const HomeSwiper: FC<PropsWithChildren<Props>> = (props) => {
     const [groupGames, setGroupGames] = useState<GroupType[]>([]);
     useEffect(() => {
         getGamesApi().then((res) => {
             setGroupGames(res.data);
         });
-
-        getUserApi().then((res) => {
-            console.log(`🎯🎯🎯🎯🎯-> in HomeGames.tsx on 25`, res);
-        });
     }, []);
     return (
         <div>

+ 1 - 4
src/app/[locale]/_home/HomeSwiper.tsx

@@ -1,9 +1,6 @@
 "use client";
 import { FC, PropsWithChildren } from "react";
-import "swiper/css";
-import "swiper/css/autoplay";
-import "swiper/css/pagination";
-import "swiper/css/virtual";
+
 import { Autoplay, Pagination } from "swiper/modules";
 import { Swiper, SwiperSlide } from "swiper/react";
 interface Props {}

+ 5 - 5
src/app/[locale]/login/component/FromCom/index.tsx

@@ -38,10 +38,11 @@ const FromCom: FC<PropsWithChildren<FromComProps>> = ({type = 'login', msgError
     }, [fromParam]);
 
 
-    const setInputVal = (e: ChangeEvent<HTMLInputElement>, propsName: string) => {
+    const setInputVal = (e: ChangeEvent<HTMLInputElement>) => {
+        const {name, value} = e.target;
         setFromParam({
             ...fromParam,
-            [propsName]: e.target.value
+            [name]: value
         })
     }
 
@@ -49,7 +50,6 @@ const FromCom: FC<PropsWithChildren<FromComProps>> = ({type = 'login', msgError
         let pwd = e.target.value || '';
         pwd.replaceAll(/[^a-zA-Z0-9_-]/g, '')
         setFromParam({ ...fromParam, pwd })
-        console.log('fromParam', fromParam.pwd)
     }
 
     const submitRequest = () => {
@@ -60,10 +60,10 @@ const FromCom: FC<PropsWithChildren<FromComProps>> = ({type = 'login', msgError
         <div className="FromCom">
             <div className="phoneInput">
                 <span className="after">+55</span>
-                <input type="tel" value={fromParam.userPhone} onChange={(e) => setInputVal(e, 'userPhone') } placeholder="Número de Celular" maxLength={11} />
+                <input name="userPhone" type="tel" value={fromParam.userPhone} onChange={setInputVal} placeholder="Número de Celular" maxLength={11} />
             </div>
             <div className="passwordInput">
-                <input type={pwdVisible?'text':'password'} value={fromParam.pwd} onChange={(e) => setInputVal(e, 'pwd') } onInput={verifyPwd} placeholder="Senha" maxLength={12}/>
+                <input name="pwd" type={pwdVisible?'text':'password'} value={fromParam.pwd} onChange={setInputVal} onInput={verifyPwd} placeholder="Senha" maxLength={12}/>
                 <span className={spanClassName} onClick={() => setPwdVisible(!pwdVisible)}></span>
             </div>
             <div className="btnContent">

+ 2 - 2
src/app/[locale]/page.tsx

@@ -11,13 +11,13 @@ const App: FC<LocalPropsWithChildren> = (props) => {
     const t = useTranslations("global");
     return (
         <Layout>
-            <>
+            <div>
                 <Box>
                     <HomeSwiper></HomeSwiper>
                     <HomeCard></HomeCard>
                 </Box>
                 <HomeGames />
-            </>
+            </div>
         </Layout>
     );
 };

+ 2 - 2
src/app/[locale]/resetPhone/page.scss

@@ -4,7 +4,7 @@
     background-color: rgb(31, 31, 31);
     display: flex;
     flex-direction: column;
-  }
+  
   .main {
     background-color: #1f1f1f;
     padding: .72rem .18rem 0;
@@ -71,4 +71,4 @@
       margin: .29rem 0 .19rem;
     }
   }
-  
+}

+ 45 - 10
src/app/[locale]/resetPhone/page.tsx

@@ -1,23 +1,58 @@
 "use client";
-import { FC, PropsWithChildren } from "react";
+import { FC, PropsWithChildren, useState } from "react";
 import HeaderBack from "@/components/HeaderBack";
 import ButtonOwn from "@/components/ButtonOwn";
 import DomainFooter from "@/components/DomainFooter";
 import './page.scss'
 import React from "react";
-import {getCheckUserPhoneExistApi} from "@/api/user";
+import { phoneRegex } from "@/utils";
+import {getCheckUserPhoneExistApi, getSendCodeApi} from "@/api/user";
+import { useRouter } from "@/i18n";
 
 interface Props {}
 
 const ResetPhone: FC<PropsWithChildren<Props>> = () => {
+    const router:any = useRouter()
+    let [userPhone, setUserPhone] = useState('')
+    const changeUserPhone = (e: { target: { value: any; }; }) => {
+        setUserPhone(e.target.value)
+    }
+    let [verifyInfo, setVerifyInfo] = useState({
+        msgError: '',
+        check: false
+    })
+    const blurVerifyPhone = (e: { target: { value: any; }; }) => {
+        const {value} = e.target;
+        if (value && !phoneRegex(value)) {
+            setVerifyInfo({
+                msgError: '请输入正确的手机号',
+                check: false
+            })
+            return
+        }
+        if (!value) {
+            setVerifyInfo({
+                msgError: '',
+                check: false
+            })
+            return
+        }
+        setVerifyInfo({
+            msgError: '',
+            check: true
+        })
+    }
     const checkUserPhoneRequest = async () => {
-        let { code, msg } = await getCheckUserPhoneExistApi({user_phone: '18215519037'})
+        if(!phoneRegex(userPhone)) return
+        let { code, msg } = await getCheckUserPhoneExistApi({user_phone: userPhone})
         if(code == 200) {
-            alert('验证成功')
-            // router.replace('/login')
-        } else {
-            // setMsgError(msg)
+            router.push(`/verification?userPhone=${userPhone}`)
+            return
         }
+        setVerifyInfo({
+            ...verifyInfo,
+            msgError: msg,
+        })
     }
     return (
         <div className="resetPhone-box">
@@ -29,11 +64,11 @@ const ResetPhone: FC<PropsWithChildren<Props>> = () => {
                 </div>
                 <div className="phoneInput">
                     <span className="after">+55</span>
-                    <input type="tel" placeholder="Número de Celular" />
+                    <input type="tel" value={userPhone} onChange={changeUserPhone} onBlur={blurVerifyPhone} placeholder="Número de Celular" maxLength={11} />
                 </div>
-                <div className="tips"> O número de telefone não existe. </div>
+                { verifyInfo.msgError && <div className="tips"> {verifyInfo.msgError} </div> }
                 <div className="btnContent">
-                    <ButtonOwn active={true} callbackFun={checkUserPhoneRequest}>Continuar</ButtonOwn>
+                    <ButtonOwn active={verifyInfo.check} callbackFun={checkUserPhoneRequest}>Continuar</ButtonOwn>
                 </div>
             </div>
             <DomainFooter />

+ 71 - 0
src/app/[locale]/verification/page.scss

@@ -0,0 +1,71 @@
+.verification-box {
+    width: 100%;
+    min-height: 100vh;
+    background-color: rgb(31, 31, 31);
+    display: flex;
+    flex-direction: column;
+  
+  .main {
+    background-color: #1f1f1f;
+    padding: .72rem .18rem 0;
+    -webkit-box-sizing: border-box;
+    box-sizing: border-box;
+    .title {
+      font-size: .18rem;
+      h2 {
+        color: #fcde26;
+        line-height: .22rem;
+      }
+      div {
+        color: #fff;
+        font-size: .12rem;
+        margin: .06rem 0;
+        line-height: .2rem;
+      }
+    }
+    .phoneInput {
+      width: 100%;
+      height: auto;
+      background-color: #494949;
+      border-radius: 4px;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      overflow: hidden;
+      margin-top: 0.2rem;
+      .after {
+        margin-left: .1rem;
+        font-size: .14rem;
+        color: #868686;
+      }
+      input {
+        padding-left: .14rem;
+        -webkit-box-sizing: border-box;
+        box-sizing: border-box;
+      }
+    }
+    
+    input {
+      flex: 1;
+      background-color: #494949;
+      height: .48rem;
+      color: #868686;
+      font-size: .14rem;
+      outline: none;
+      &::placeholder {
+        color: #868686;
+      }
+    }
+
+    .tips {
+      width: 100%;
+      color: #e53535;
+      font-size: 0.12rem;
+      margin-top: .02rem;
+    }
+
+    .btnContent {
+      margin: .29rem 0 .19rem;
+    }
+  }
+}

+ 63 - 0
src/app/[locale]/verification/page.tsx

@@ -0,0 +1,63 @@
+"use client";
+import { FC, PropsWithChildren, useState } from "react";
+import HeaderBack from "@/components/HeaderBack";
+import ButtonOwn from "@/components/ButtonOwn";
+import DomainFooter from "@/components/DomainFooter";
+import './page.scss'
+import React from "react";
+import { phoneRegex } from "@/utils";
+import {getCheckUserPhoneExistApi, getSendCodeApi} from "@/api/user";
+
+interface Props {}
+
+const ResetPhone: FC<PropsWithChildren<Props>> = () => {
+
+    let [userPhone, setUserPhone] = useState('')
+    const changeUserPhone = (e: { target: { value: any; }; }) => {
+        setUserPhone(e.target.value)
+    }
+    let [verifyInfo, setVerifyInfo] = useState({
+        msgError: '',
+        check: false
+    })
+
+    const checkUserPhoneRequest = async () => {
+        let { code, msg } = await getCheckUserPhoneExistApi({user_phone: userPhone})
+        if(code == 200) {
+            getSendCodeApi({user_phone: userPhone}).then((res) => {
+                if(res.code == 200) {
+                    alert('验证码发送成功')
+                     router.push('/verification')
+                }
+            })
+            router.push('/verification')
+            return
+        }
+        setVerifyInfo({
+            ...verifyInfo,
+            msgError: msg,
+        })
+    }
+    return (
+        <div className="verification-box">
+            <HeaderBack />
+            <div className="main">
+                <div className="title">
+                    <h2>Ativa a sua conta por entrar a Senha de Verificação!</h2>
+                    <div>A senha de verificação foi enviado para o teu telemóvel 16982013895</div>
+                </div>
+                <div className="phoneInput">
+                    <input type="tel" value={userPhone} onChange={changeUserPhone} placeholder="Reenviar código" maxLength={6} />
+                    <span className="after">+55</span>
+                </div>
+                { verifyInfo.msgError && <div className="tips"> {verifyInfo.msgError} </div> }
+                <div className="btnContent">
+                    <ButtonOwn active={verifyInfo.check} callbackFun={checkUserPhoneRequest}>Completar</ButtonOwn>
+                </div>
+            </div>
+            <DomainFooter />
+        </div>
+    );
+};
+
+export default ResetPhone;

+ 8 - 0
src/app/globals.css

@@ -3,6 +3,13 @@
 @tailwind utilities;
 @import "@/styles/iconfont/iconfont.css";
 
+/* swiper */
+@import "swiper/css";
+@import "swiper/css/autoplay";
+@import "swiper/css/pagination";
+@import "swiper/css/virtual";
+
+
 :root{
   --swiper-pagination-bullet-width: 0.23rem;
   --swiper-pagination-bullet-height: 0.05rem;
@@ -31,4 +38,5 @@ html {
     height: auto;
     margin: 0 auto;
     font-size: 0.14rem;
+    position: relative;
 }

+ 75 - 8
src/components/Card/Card.tsx

@@ -1,17 +1,84 @@
+"use client";
+import { EntityGameListRep } from "@/api/home";
+import { Button, Modal, ModalBody, ModalContent, useDisclosure } from "@nextui-org/react";
+import { useTranslations } from "next-intl";
 import { FC, PropsWithChildren, ReactNode } from "react";
 import styles from "./style.module.scss";
 export interface CardProps {
-    url?: string;
-    alt?: string;
-    render?: () => ReactNode;
+    item?: EntityGameListRep;
+    render?: (value: EntityGameListRep) => ReactNode;
 }
-
 const Card: FC<PropsWithChildren<CardProps>> = (props) => {
-    const { render, url, alt } = props;
+    const { render, item } = props;
+    const { isOpen, onOpen, onOpenChange } = useDisclosure();
+    const app: HTMLElement = document.querySelector("#app")!;
+    const t = useTranslations("Game");
+    const handler = (game: EntityGameListRep) => {
+        onOpen();
+    };
     return (
-        <div className={styles.cardWrap}>
-            {render ? render() : <img src={url} alt={alt} className={"h-1/1"} />}
-        </div>
+        <>
+            <div className={styles.cardWrap} onClick={() => handler(item!)}>
+                {render ? (
+                    render(item!)
+                ) : (
+                    <img src={item?.game_icon} alt={item?.game_name_cn} className={"h-1/1"} />
+                )}
+            </div>
+            <Modal
+                isOpen={isOpen}
+                portalContainer={app}
+                placement={"bottom"}
+                onOpenChange={onOpenChange}
+                classNames={{
+                    header: "px-0 pb-0 ",
+                    wrapper: "w-[100vw]  m-auto",
+                    closeButton: "text-[20px] top-[0rem] right-0 text-[#fff] ",
+                    backdrop: "absolute top-0 left-0 sm:my-0 ",
+                    base: "my-0 my-0 sm:mx-[0] mx-0 sm:my-0 max-w-[4.02rem]  ",
+                    body: "py-[12px]",
+                }}
+            >
+                <ModalContent>
+                    {(onClose) => (
+                        <>
+                            <ModalBody className={"w-[4rem] text-[0.1111rem]"}>
+                                <div className={"w-1/1 flex flex-1"}>
+                                    <div className={styles.cardWrap}>
+                                        <img src={item?.game_icon} alt={item?.game_name_cn} />
+                                    </div>
+                                    <div className={styles.cardWrapGmeInfo}>
+                                        <p className={"h-[0.6rem]"}>{item?.game_name_cn}</p>
+
+                                        <div className={"flex w-[2.2rem] justify-around"}>
+                                            <Button
+                                                className={
+                                                    "h-[0.39rem] w-[0.89rem] rounded-[0.05rem] text-[0.15rem]" +
+                                                    " bg-[#3a3a3a]" +
+                                                    " font-bold"
+                                                }
+                                            >
+                                                {t("demo")}
+                                            </Button>
+                                            <Button
+                                                className={
+                                                    "h-[0.39rem] w-[0.89rem] text-[0.15rem]" +
+                                                    " rounded-[0.05rem]" +
+                                                    " bg-[#009d80]" +
+                                                    " font-bold"
+                                                }
+                                            >
+                                                {t("join")}
+                                            </Button>
+                                        </div>
+                                    </div>
+                                </div>
+                            </ModalBody>
+                        </>
+                    )}
+                </ModalContent>
+            </Modal>
+        </>
     );
 };
 

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

@@ -19,7 +19,7 @@ const GroupCard: FC<GroupProps> = (props) => {
     );
     return (
         <div className={"flex flex-wrap justify-between gap-y-4"}>
-            {data?.map((item, index) => <Card key={index} url={item.game_icon} {...other} />)}
+            {data?.map((item, index) => <Card key={index} item={item} {...other} />)}
         </div>
     );
 };

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

@@ -1,10 +1,7 @@
 "use client";
 import Box from "@/components/Box";
 import { FC, PropsWithChildren, useRef } from "react";
-import "swiper/css";
-import "swiper/css/autoplay";
-import "swiper/css/pagination";
-import "swiper/css/virtual";
+
 import { Swiper, SwiperClass, SwiperSlide } from "swiper/react";
 
 import { GroupType } from "@/api/home";

+ 5 - 1
src/components/Card/style.module.scss

@@ -8,7 +8,11 @@
   background: #212a36;
   border-radius: .1rem;
 }
-
+.cardWrapGmeInfo{
+  color: #fff;
+  font-size: .2rem;
+  margin: .2rem 0 0 .17rem;
+}
 
 .mainTitle{
     height: .34rem;

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 5 - 1
src/components/Header/HerderTitle.tsx


+ 1 - 1
src/components/Layout/index.tsx

@@ -4,7 +4,7 @@ import { FC, PropsWithChildren } from "react";
 import styles from "./style.module.scss";
 type Props = FooterProps & HeaderProps;
 const Layout: FC<PropsWithChildren<Props>> = (props) => {
-    const { children, headerRender, footerRender } = props;
+    const { children } = props;
     return (
         <div className="relative h-[100vh]">
             <Header {...props}></Header>

+ 6 - 0
src/utils/index.ts

@@ -23,4 +23,10 @@ export const setHtmlFontSize = () => {
 export const pwdRegex = (pwd = '') => {
 	let regex = /^[a-zA-Z0-9_-]{6,12}$/;
 	return regex.test(pwd)
+}
+
+// 密码正则 6到12位(字母,数字,下划线,减号)
+export const phoneRegex = (pwd = '') => {
+	let regex =  /^1[3-9]\d{9}$/;
+	return regex.test(pwd)
 }

+ 2 - 2
src/utils/server/index.ts

@@ -1,8 +1,8 @@
 import Request from "./axios";
 const server = new Request({
     timeout: 10 * 1000,
-    baseURL: "http://127.0.0.1:4523/m1/4790544-4444647-default",
-    // baseURL: "http://192.168.0.66:6060",
+    // baseURL: "http://127.0.0.1:4523/m1/4790544-4444647-default",
+    baseURL: "http://192.168.0.66:6060",
     transform: {
         // instance  interceptor
         requestInterceptor: (config) => {

이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.