ソースを参照

Merge branch 'dev' into feature-lucky

xiaolin.fu 1 年間 前
コミット
9c68f80fa9

+ 1 - 0
next.config.mjs

@@ -6,6 +6,7 @@ const withNextIntl = createNextIntlPlugin();
 /** @type {import('next').NextConfig} */
 const nextConfig = {
     reactStrictMode: true,
+  transpilePackages: ['antd-mobile'],
     sassOptions: {
       prependData: `@import "./src/styles/variables.scss";`
     },

+ 121 - 32
src/api/home.ts

@@ -1,6 +1,94 @@
 import { server } from "@/utils/server";
 
-export interface EntityGameListRep {
+/**
+ * entity.HomeCategory
+ */
+export interface GroupType {
+    category: Category[];
+    /**
+     * 分类名字
+     */
+    category_name: string;
+    /**
+     * 隐藏模板中的厂商、类型两个标签。1:开启,2:关闭
+     */
+    hide_status: number;
+    /**
+     * 正序排序
+     */
+    sort: number;
+    /**
+     * 展示风格 展示风格,1:横排,2:竖排,3:竖排-分类左边-连续,4:竖排-分类左边-拆开
+     */
+    style_type: number;
+}
+
+/**
+ * entity.Category
+ */
+export interface Category {
+    /**
+     * 多语言名字
+     */
+    category_name: string;
+    /**
+     * 游戏列表
+     */
+    game_list: GameListRep[];
+    /**
+     * 前置图标 -就是名字前面的那个小标签
+     */
+    icon: string;
+    /**
+     * 图标类型,1:游戏图标,2:厂商图标',
+     */
+    icon_type: string;
+    /**
+     * 跳转ID
+     */
+    jump_id: number;
+    /**
+     * 每页展示多少条
+     */
+    line_config_amount: number;
+    /**
+     * 每页条数
+     */
+    line_num: number;
+    /**
+     * 是否显示厂商名称 厂商模块,1:开启,2:关闭
+     */
+    show_factory_name: number;
+    /**
+     * 是否显示游戏类型 游戏类型,1:开启,2:关闭
+     */
+    show_game_type: number;
+    /**
+     * 是否显示体育模块 体育模块,1:开启,2:关闭
+     */
+    show_sport: number;
+    /**
+     * 特殊显示 特殊显示,1:开启,2:关闭
+     */
+    special_show: string;
+    /**
+     * 标签
+     */
+    tag: string;
+    /**
+     * 当前分类的数量
+     */
+    to_tal: number;
+    /**
+     * 类型 1:game 2:brand 3:title
+     */
+    type: number;
+}
+
+/**
+ * entity.GameListRep
+ */
+export interface GameListRep {
     /**
      * 游戏ICON
      */
@@ -35,47 +123,48 @@ export interface EntityGameListRep {
     release_date: string;
 }
 
-export interface GroupType {
-    /**
-     * 多语言名字
-     */
-    category_name?: string;
-    /**
-     * 游戏列表
-     */
-    game_list?: EntityGameListRep[];
-    /**
-     * 分类图标
-     */
-    icon?: string;
+export const getGamesApi = () => {
+    return server.post<GroupType[]>({
+        url: "/v1/api/front/game_list",
+        data: {},
+    });
+};
+
+/**
+ * @description
+ * entity.GameInfo
+ */
+export interface GameInfo {
+    game_url: string;
+}
+/**
+ * form.LoginGameReq
+ */
+export interface GameRequest {
     /**
-     * 每页展示多少条
+     * 玩家渠道,pc/mobile
      */
-    line_config_amount?: number;
+    channel?: string;
     /**
-     * 每页条数
+     * 用于显示全画面(部份游戏提供此功能)
      */
-    line_num?: number;
+    full_screen?: boolean;
     /**
-     * 特殊显示 特殊显示,1:开启,2:关闭
+     * 游戏列表ID
      */
-    special_show?: string;
+    id?: number;
     /**
-     * 展示风格 展示风格,1:横排,2:竖排,3:竖排-分类左边-连续,4:竖排-分类左边-拆开
+     * 语言,cn/en
      */
-    style_type?: number;
+    language?: string;
     /**
-     * 标签
-     */
-    tag?: string;
-    /**
-     * 当前分类的数量
+     * 用于主页按钮和重新导向 URL (部份游戏提供此功能)
      */
-    to_tal?: number;
+    return_url?: string;
 }
-
-export const getGamesApi = () => {
-    return server.post<GroupType[]>({
-        url: "/v1/api/front/game_list",
+export const getGameDetailApi = (data: GameRequest) => {
+    return server.post<GameInfo>({
+        url: "/v1/api/front/game_info_by_id",
+        data,
     });
 };

+ 11 - 2
src/app/[locale]/(extend)/gameList/[gameListFlag]/page.tsx

@@ -6,8 +6,17 @@ interface Props {}
 
 const GameListFlag: FC<PropsWithChildren<Props>> = (props) => {
     const params = useParams();
-    console.log(`🎯🎯🎯🎯🎯-> in page.tsx on 10`, params);
-    return <div>hello React</div>;
+    return (
+        <div
+            className={
+                "w-1/1 flex h-[200px] items-center justify-center border-1" +
+                " border-[#4d4d4d]" +
+                " text-[0.12rem] text-[#4d4d4d]"
+            }
+        >
+            under development...
+        </div>
+    );
 };
 
 export default GameListFlag;

+ 33 - 4
src/app/[locale]/_home/HomeActions.tsx

@@ -19,10 +19,19 @@ const HomeActions: FC<PropsWithChildren<Props>> = (props) => {
         console.log(`🎯🎯🎯🎯🎯-> in HomeActions.tsx on 9`, url);
     };
 
+    const scrollToTop = () => {
+        const parentEle = document.querySelector("#maincontainer");
+        parentEle!.scrollTo({ top: 0, behavior: "smooth" });
+    };
+
     return (
         <div>
             {/*about*/}
-            <div className={"grid cursor-pointer grid-cols-3 text-center text-[0.12rem]"}>
+            <div
+                className={
+                    "grid cursor-pointer grid-cols-3 text-center text-[0.12rem]" + " text-[#fff]"
+                }
+            >
                 <div onClick={() => handler("1")}>{t("Sobre")}</div>
                 <div
                     onClick={() => handler("2")}
@@ -35,10 +44,10 @@ const HomeActions: FC<PropsWithChildren<Props>> = (props) => {
             {/* service */}
             <div className="mt-[0.26rem] flex flex-col items-center text-[0.12rem]">
                 <div className={"flex"}>
-                    <div className="m-[0.05rem] h-[0.3889rem] w-[0.3889rem] rounded bg-white">
+                    <div className="bg-white m-[0.05rem] h-[0.3889rem] w-[0.3889rem] rounded">
                         <img src="https://9f.com/img/service.fde992c6.png" alt="" />
                     </div>
-                    <div className="m-[0.05rem] h-[0.3889rem] w-[0.3889rem] rounded bg-white">
+                    <div className="bg-white m-[0.05rem] h-[0.3889rem] w-[0.3889rem] rounded">
                         <img src="https://9f.com/img/persons.da1a04fe.png" alt="" />
                     </div>
                 </div>
@@ -100,7 +109,27 @@ const HomeActions: FC<PropsWithChildren<Props>> = (props) => {
                     </div>
                 </div>
             </div>
-            <div className={"pb-[0.5rem]"}>123</div>
+            {/*support*/}
+            <div className={"mt-[0.3rem] flex items-center justify-around pb-[0.5rem] text-[#fff]"}>
+                <div
+                    className={
+                        "h-[0.45rem] w-[0.45rem] rounded bg-gradient-to-b from-[#ff9323]" +
+                        " flex items-center justify-center to-[#ff6a01]"
+                    }
+                >
+                    <span className={"iconfont icon-shoucang text-[0.15rem]"}></span>
+                </div>
+                <div
+                    className={
+                        "flex h-[0.46rem] w-[0.46rem] rounded-[0.02rem] bg-[#25272c]" +
+                        " flex-col items-center justify-center text-[0.12rem]"
+                    }
+                    onClick={scrollToTop}
+                >
+                    <span className={"iconfont icon-xiangshang text-[#ff6a01]"}></span>
+                    Top
+                </div>
+            </div>
         </div>
     );
 };

ファイルの差分が大きいため隠しています
+ 39 - 1
src/app/[locale]/_home/HomeGames.tsx


+ 1 - 1
src/app/[locale]/layout.tsx

@@ -30,7 +30,7 @@ export default async function LocaleLayout({
     const messages = await getMessages();
     return (
         <html lang={locale} suppressHydrationWarning>
-            <body className={clsx("bg-amber-50 font-sans", fontSans.variable)}>
+            <body className={clsx("bg-white font-sans", fontSans.variable)}>
                 <Providers themeProps={{ defaultTheme: "dark", attribute: "class" }}>
                     <NextIntlClientProvider messages={messages}>
                         <PageTransitionEffect>{children}</PageTransitionEffect>

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

@@ -1,11 +1,11 @@
 import HomeActions from "@/app/[locale]/_home/HomeActions";
+import HomeGames from "@/app/[locale]/_home/HomeGames";
 import Box from "@/components/Box";
 import Layout from "@/components/Layout";
 import { LocalPropsWithChildren } from "@/types";
 import { useTranslations } from "next-intl";
 import { FC } from "react";
 import HomeCard from "./_home/HomeCard";
-import HomeGames from "./_home/HomeGames";
 import HomeSwiper from "./_home/HomeSwiper";
 
 // Information

+ 6 - 1
src/app/globals.css

@@ -17,6 +17,8 @@
   --swiper-pagination-color: #fff;
   --swiper-pagination-bullet-active-bg: #fff;
   --swiper-pagination-bullet-inactive-color: hsla(0, 0%, 100%, .8);
+
+  --adm-color-text: #fff;
 }
 html, body {
     width: 100vw;
@@ -46,4 +48,7 @@ html {
 /* ant-design-ui */
 .adm-toast-mask .adm-toast-main-icon .adm-toast-icon svg {
   margin: 0 auto;
-}
+}
+.adm-input input{
+  color: #fff;
+}

+ 18 - 11
src/components/Card/Card.tsx

@@ -1,20 +1,30 @@
 "use client";
-import { EntityGameListRep } from "@/api/home";
+import { GameListRep, getGameDetailApi } 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 { FC, PropsWithChildren, ReactNode, useRef } from "react";
 import styles from "./style.module.scss";
 export interface CardProps {
-    item?: EntityGameListRep;
-    render?: (value: EntityGameListRep) => ReactNode;
+    item?: GameListRep;
+    render?: (value: GameListRep) => ReactNode;
 }
 const Card: FC<PropsWithChildren<CardProps>> = (props) => {
     const { render, item } = props;
     const { isOpen, onOpen, onOpenChange } = useDisclosure();
     const app: HTMLElement = document.querySelector("#app")!;
     const t = useTranslations("Game");
-    const handler = (game: EntityGameListRep) => {
+    const urlRef = useRef<string>("");
+    const handler = (game: GameListRep) => {
         onOpen();
+        const params = {
+            id: game.id,
+        };
+        getGameDetailApi(params).then((res) => {
+            urlRef.current = res.data.game_url;
+        });
+    };
+    const playGameHandler = () => {
+        window.open(urlRef.current);
     };
     return (
         <>
@@ -52,6 +62,7 @@ const Card: FC<PropsWithChildren<CardProps>> = (props) => {
 
                                         <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]" +
@@ -61,12 +72,8 @@ const Card: FC<PropsWithChildren<CardProps>> = (props) => {
                                                 {t("demo")}
                                             </Button>
                                             <Button
-                                                className={
-                                                    "h-[0.39rem] w-[0.89rem] text-[0.15rem]" +
-                                                    " rounded-[0.05rem]" +
-                                                    " bg-[#009d80]" +
-                                                    " font-bold"
-                                                }
+                                                onClick={playGameHandler}
+                                                className={`h-[0.39rem] w-[0.89rem] rounded-[0.05rem] bg-[#009d80] text-[0.15rem] font-bold`}
                                             >
                                                 {t("join")}
                                             </Button>

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

@@ -1,9 +1,9 @@
-import { EntityGameListRep } from "@/api/home";
+import { GameListRep } from "@/api/home";
 import clsx from "clsx";
 import { FC } from "react";
 import Card, { CardProps } from "./Card";
 export interface GroupProps extends CardProps {
-    data?: EntityGameListRep[];
+    data?: GameListRep[];
     col?: number;
     row?: number;
     gapX?: number;

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

@@ -4,16 +4,16 @@ import { FC, PropsWithChildren, ReactNode, useRef } from "react";
 
 import { Swiper, SwiperClass, SwiperSlide } from "swiper/react";
 
-import { EntityGameListRep, GroupType } from "@/api/home";
+import { Category, GameListRep } from "@/api/home";
 import { CardProps } from "@/components/Card/Card";
 import GroupCard, { GroupProps } from "@/components/Card/GroupCard";
 import clsx from "clsx";
 import styles from "./style.module.scss";
 
-type TodoHandler = (item: GroupType) => void;
+type TodoHandler = (item: Category) => void;
 
 interface SwiperGroupProps extends GroupProps, CardProps {
-    group: GroupType;
+    group: Category;
     page?: number;
     // style
     bg?: boolean;
@@ -26,7 +26,7 @@ interface SwiperGroupProps extends GroupProps, CardProps {
     offsetY?: number;
 
     // SwiperSlide
-    slideRender?: (data: EntityGameListRep[]) => ReactNode;
+    slideRender?: (data: GameListRep[]) => ReactNode;
 }
 
 const HomeSwiper: FC<PropsWithChildren<SwiperGroupProps>> = (props) => {

+ 46 - 43
src/components/Footer/index.tsx

@@ -1,9 +1,8 @@
 "use client";
-import { usePathname, useRouter} from "@/i18n";
-import { FC, PropsWithChildren, ReactNode } from "react";
+import { usePathname, useRouter } from "@/i18n";
 import clsx from "clsx";
+import { FC, PropsWithChildren, ReactNode } from "react";
 import "./style.scss";
-import { useTranslations } from "next-intl";
 
 /**
  * @description 底部Tab组件
@@ -11,66 +10,70 @@ import { useTranslations } from "next-intl";
  *
  */
 export interface FooterProps {
-    children?: () => ReactNode;
+    children?: ReactNode;
 }
 
-const Footer: FC<PropsWithChildren<FooterProps>> = () => {
-    const t = useTranslations("tabberList");
+const Footer: FC<PropsWithChildren> = () => {
     const tabList = [
         {
-            iconSpanName: 'icon-home',
-            label: t('tab1'),
-            path: '/'
+            iconSpanName: "icon-home",
+            label: "Início",
+            path: "/",
         },
         {
-            iconSpanName: 'icon-qianbao1',
-            label: t('tab2'),
-            path: '/deposit'
+            iconSpanName: "icon-qianbao1",
+            label: "Depósito",
+            path: "/deposit",
         },
         {
-            iconSpanName: 'icon-afiliado',
-            label: t('tab3'),
-            path: '/affiliate/summary'
+            iconSpanName: "icon-afiliado",
+            label: "Afiliado",
+            path: "/affiliate/summary",
         },
         {
-            iconSpanName: 'icon-tiyu',
-            label: t('tab4'),
-            path: '/'
+            iconSpanName: "icon-tiyu",
+            label: "Esportes",
+            path: "/",
         },
         {
-            iconSpanName: 'icon-yonghu',
-            label: t('tab5'),
-            path: '/profile'
+            iconSpanName: "icon-yonghu",
+            label: "Perfil",
+            path: "/profile",
         },
-    ]
+    ];
 
-    const pathname = usePathname()
+    const pathname = usePathname();
 
     const router = useRouter();
-    const goPage = (path = '/') => {
-        router.push(path)
-    }
+    const goPage = (path = "/") => {
+        router.push(path);
+    };
 
     return (
         <div className="footer-box">
             <ul>
-                {
-                    tabList.map((item, index) => {
-                        return (
-                            <li className={clsx(item.path == pathname && 'active')} onClick={() => goPage(item.path)} key={index}>
-                                <div className="icon-box">
-                                    {
-                                        index == 2 ? (
-                                            <><i className="icon-afiliado"></i><i className="icon-rs"></i></>
-                                        ) : <span className={clsx('iconfont',item.iconSpanName)}></span>
-                                    }
-                                    { index == 3 && <b className="icon-hot"></b> }
-                                </div>
-                                <label>{item.label}</label>
-                            </li>
-                        )
-                    })
-                }
+                {tabList.map((item, index) => {
+                    return (
+                        <li
+                            className={clsx(item.path == pathname && "active")}
+                            onClick={() => goPage(item.path)}
+                            key={index}
+                        >
+                            <div className="icon-box">
+                                {index == 2 ? (
+                                    <>
+                                        <i className="icon-afiliado"></i>
+                                        <i className="icon-rs"></i>
+                                    </>
+                                ) : (
+                                    <span className={clsx("iconfont", item.iconSpanName)}></span>
+                                )}
+                                {index == 3 && <b className="icon-hot"></b>}
+                            </div>
+                            <label>{item.label}</label>
+                        </li>
+                    );
+                })}
             </ul>
         </div>
     );

+ 2 - 3
src/components/Header/index.tsx

@@ -1,7 +1,7 @@
 import { Link } from "@/i18n";
 import clsx from "clsx";
 import { useTranslations } from "next-intl";
-import { FC, PropsWithChildren, ReactNode } from "react";
+import { FC, ReactNode } from "react";
 import HeaderTitle from "./HerderTitle";
 import styles from "./style.module.scss";
 /**
@@ -35,7 +35,7 @@ const DefaultHeader: FC = () => {
     );
 };
 
-const Header: FC<PropsWithChildren<HeaderProps>> = (props) => {
+const Header: FC<HeaderProps> = (props) => {
     const { headerPlaceholder = true, headerRender } = props;
     const cs = clsx({
         [styles.placeholder]: headerPlaceholder,
@@ -48,5 +48,4 @@ const Header: FC<PropsWithChildren<HeaderProps>> = (props) => {
         </div>
     );
 };
-
 export default Header;

+ 3 - 0
src/components/Header/style.module.scss

@@ -93,6 +93,9 @@
         font-size: .15rem;
         display: flex;
         align-items: center;
+        a {
+          color: #fff;
+        }
         .rightActive{
           background: linear-gradient(180deg, #ff9323, #ff6a01);
           padding: .04rem .05rem;

ファイルの差分が大きいため隠しています
+ 56 - 0
src/components/Layout/Sidebar.tsx


+ 38 - 5
src/components/Layout/index.tsx

@@ -1,16 +1,49 @@
+"use client";
 import Footer, { FooterProps } from "@/components/Footer";
 import Header, { HeaderProps } from "@/components/Header";
+import Sidebar from "@/components/Layout/Sidebar";
 import { FC, PropsWithChildren } from "react";
+import { Swiper, SwiperSlide } from "swiper/react";
 import styles from "./style.module.scss";
 type Props = FooterProps & HeaderProps;
 const Layout: FC<PropsWithChildren<Props>> = (props) => {
     const { children } = props;
+
+    const startHandler = () => {
+        console.log(`🎯🎯🎯🎯🎯-> in index.tsx on 12`, "start");
+    };
+    const endHandler = () => {
+        console.log(`🎯🎯🎯🎯🎯-> in index.tsx on 12`, "end");
+    };
     return (
-        <div className="relative h-[100vh]">
-            <Header {...props}></Header>
-            <main className={styles.main}>{children}</main>
-            <Footer {...props}></Footer>
-        </div>
+        <Swiper
+            initialSlide={1}
+            resistanceRatio={0}
+            slidesPerView={"auto"}
+            slideToClickedSlide
+            onSlideChangeTransitionStart={startHandler}
+            onSlideChangeTransitionEnd={endHandler}
+            // allowTouchMove={false}
+        >
+            <SwiperSlide
+                style={{ width: "70%" }}
+                className={"mx-w-[2.2222rem] " + " bg-[rgb(31,31,31)]"}
+            >
+                <section className="relative h-[100vh]">
+                    <Sidebar></Sidebar>
+                </section>
+            </SwiperSlide>
+
+            <SwiperSlide style={{ width: "100%" }}>
+                <div className="relative h-[100vh]">
+                    <Header {...props}></Header>
+                    <main className={styles.main} id="maincontainer">
+                        {children}
+                    </main>
+                    <Footer {...props}></Footer>
+                </div>
+            </SwiperSlide>
+        </Swiper>
     );
 };
 

+ 5 - 0
src/styles/variables.scss

@@ -7,3 +7,8 @@ $primary-color: #ff6a01;
 
 $-header-height: 0.4rem;
 $-footer-height: 0.6rem;
+
+
+:export {
+  primaryColor: $-theme-color;
+}

+ 3 - 0
tailwind.config.ts

@@ -36,6 +36,9 @@ const config: Config = {
                     "conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))",
             },
         },
+        colors: {
+            "primary-color": "#ff6a01",
+        },
     },
     plugins: [
         nextui({

この差分においてかなりの量のファイルが変更されているため、一部のファイルを表示していません