ansoni 1 місяць тому
батько
коміт
9b62571e69

+ 1 - 1
next.config.mjs

@@ -4,7 +4,7 @@ import createNextIntlPlugin from "next-intl/plugin";
 const withNextIntl = createNextIntlPlugin();
 /** @type {import('next').NextConfig} */
 const nextConfig = {
-    output: "standalone",
+    // output: "standalone",
     productionBrowserSourceMaps: true,
     reactStrictMode: false,
     env: {

+ 1 - 0
package.json

@@ -35,6 +35,7 @@
     "env-cmd": "^10.1.0",
     "firebase": "^11.0.1",
     "framer-motion": "^11.3.2",
+    "immer": "^10.1.1",
     "js-cookie": "^3.0.5",
     "next": "14.2.4",
     "next-intl": "^3.25.1",

+ 11 - 2
pnpm-lock.yaml

@@ -44,6 +44,9 @@ importers:
       framer-motion:
         specifier: ^11.3.2
         version: 11.15.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+      immer:
+        specifier: ^10.1.1
+        version: 10.1.1
       js-cookie:
         specifier: ^3.0.5
         version: 3.0.5
@@ -73,7 +76,7 @@ importers:
         version: 2.6.0
       zustand:
         specifier: ^4.5.4
-        version: 4.5.5(@types/react@18.3.18)(react@18.3.1)
+        version: 4.5.5(@types/react@18.3.18)(immer@10.1.1)(react@18.3.1)
     devDependencies:
       '@types/js-cookie':
         specifier: ^3.0.6
@@ -1458,6 +1461,9 @@ packages:
     resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
     engines: {node: '>= 4'}
 
+  immer@10.1.1:
+    resolution: {integrity: sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw==, tarball: https://registry.npmmirror.com/immer/-/immer-10.1.1.tgz}
+
   immutable@5.0.3:
     resolution: {integrity: sha512-P8IdPQHq3lA1xVeBRi5VPqUm5HDgKnx0Ru51wZz5mjxHr5n3RWhjIpOFU7ybkUxfB+5IToy+OLaHYDBIWsv+uw==}
 
@@ -4149,6 +4155,8 @@ snapshots:
 
   ignore@5.3.2: {}
 
+  immer@10.1.1: {}
+
   immutable@5.0.3: {}
 
   import-fresh@3.3.0:
@@ -5231,9 +5239,10 @@ snapshots:
 
   yocto-queue@0.1.0: {}
 
-  zustand@4.5.5(@types/react@18.3.18)(react@18.3.1):
+  zustand@4.5.5(@types/react@18.3.18)(immer@10.1.1)(react@18.3.1):
     dependencies:
       use-sync-external-store: 1.2.2(react@18.3.1)
     optionalDependencies:
       '@types/react': 18.3.18
+      immer: 10.1.1
       react: 18.3.1

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

@@ -17,8 +17,6 @@ export default async function LocaleLayout({
     children: ReactNode;
     params: { locale: string };
 }) {
-    console.log(locale);
-
     const t = await getTranslations("HeaderCom");
     return (
         <>
@@ -28,7 +26,7 @@ export default async function LocaleLayout({
             ></HeaderBack>
             <main className={"main-header bg-[#e8e8e8] px-[0.12rem]"}>
                 <TabsCom></TabsCom>
-                {children}
+                <>{children}</>
             </main>
         </>
     );

+ 70 - 54
src/app/[locale]/layout.tsx

@@ -2,12 +2,12 @@ import { ConfigType } from "@/api/config";
 import { routing } from "@/i18n/routing";
 import { server } from "@/utils/server";
 import clsx from "clsx";
-import { Metadata, Viewport } from "next";
+import { Viewport } from "next";
 import { NextIntlClientProvider } from "next-intl";
 import { getMessages } from "next-intl/server";
 import { Inter as FontSans } from "next/font/google";
 import { notFound } from "next/navigation";
-import { ReactNode, Suspense } from "react";
+import { ReactNode } from "react";
 import "../editor.scss";
 import "../globals.scss";
 import { Providers } from "./providers";
@@ -19,32 +19,32 @@ const fontSans = FontSans({
 });
 export const viewport: Viewport = {};
 
-export const metadata: Metadata = {
-    title: {
-        template: "%s | BCWin777",
-        default: "BCWin777",
-    },
-    keywords: ["BCWin777"],
-
-    description: "The home of over 30 million players",
-    appleWebApp: {
-        statusBarStyle: "black",
-    },
-
-    formatDetection: {
-        email: false,
-        address: false,
-        telephone: false,
-    },
-
-    referrer: "no-referrer",
-    other: {
-        viewport: [
-            "width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0," +
-                " viewport-fit=cover ",
-        ],
-    },
-};
+// export const metadata: Metadata = {
+//     title: {
+//         template: "%s | BCWin777",
+//         default: "BCWin777",
+//     },
+//     keywords: ["BCWin777"],
+//
+//     description: "The home of over 30 million players",
+//     appleWebApp: {
+//         statusBarStyle: "black",
+//     },
+//
+//     formatDetection: {
+//         email: false,
+//         address: false,
+//         telephone: false,
+//     },
+//
+//     referrer: "no-referrer",
+//     other: {
+//         viewport: [
+//             "width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0," +
+//                 " viewport-fit=cover ",
+//         ],
+//     },
+// };
 
 interface Og {
     description: string;
@@ -62,6 +62,47 @@ const getSystemReq = () => {
         method: "POST",
     });
 };
+export const generateMetadata = async () => {
+    const { data } = await getSystemReq();
+    return {
+        title: {
+            template: "%s | BCWin777",
+            default: "BCWin777",
+        },
+        keywords: ["BCWin777"],
+
+        description: "The home of over 30 million players",
+        appleWebApp: {
+            statusBarStyle: "black",
+        },
+
+        formatDetection: {
+            email: false,
+            address: false,
+            telephone: false,
+        },
+
+        referrer: "no-referrer",
+        other: {
+            viewport: [
+                "width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0," +
+                    " viewport-fit=cover ",
+            ],
+        },
+        openGraph: {
+            title: data?.og?.title,
+            description: data?.og?.description,
+            image: data?.og?.url,
+            url: data?.og?.address,
+        },
+        twitter: {
+            card: data?.og?.address,
+            title: data?.og?.title,
+            description: data?.og?.description,
+            image: data?.og?.url,
+        },
+    };
+};
 export default async function LocaleLayout({
     children,
     params: { locale },
@@ -73,36 +114,11 @@ export default async function LocaleLayout({
         notFound();
     }
     const messages = await getMessages();
-
-    const { data } = await getSystemReq();
-    // console.log(data)
     return (
         <html lang={locale} suppressHydrationWarning>
-            <head>
-                {/* <!-- SEO Metadata --> */}
-                {/* <meta name="description" content="{{ .Description }}" />
-                <meta name="keywords" content="{{ .Keywords }}" />
-                <meta name="author" content="Besoft" />
-                <meta name="viewport" content="width=device-width, initial-scale=1.0" /> */}
-
-                {/* <!-- Open Graph Metadata --> */}
-                <meta property="og:title" content={data?.og?.title || ""} />
-                <meta property="og:description" content={data?.og?.description || ""} />
-                <meta property="og:image" content={data?.og?.url || ""} />
-                <meta property="og:url" content={data?.og?.address || ""} />
-                <meta property="og:type" content="website" />
-
-                {/* <!-- Twitter Card Metadata --> */}
-                <meta name="twitter:card" content={data?.og?.address || ""} />
-                <meta name="twitter:title" content={data?.og?.title || ""} />
-                <meta name="twitter:description" content={data?.og?.description || ""} />
-                <meta name="twitter:image" content={data?.og?.url || ""} />
-            </head>
             <body className={clsx("font-sans", fontSans.variable)}>
                 <NextIntlClientProvider messages={messages}>
-                    <Providers themeProps={{ attribute: "class" }}>
-                        {children}
-                    </Providers>
+                    <Providers themeProps={{ attribute: "class" }}>{children}</Providers>
                 </NextIntlClientProvider>
             </body>
         </html>

+ 27 - 100
src/app/[locale]/providers.tsx

@@ -1,7 +1,7 @@
 "use client";
 import Sidebar from "@/components/Layout/Sidebar";
 import { useSystemStore } from "@/stores/useSystemStore";
-import { ConfigProvider, Mask } from "antd-mobile";
+import { ConfigProvider } from "antd-mobile";
 import ptBR from "antd-mobile/es/locales/pt-BR";
 import { ThemeProviderProps } from "next-themes/dist/types";
 import { ReactNode, useEffect, useMemo, useState } from "react";
@@ -18,7 +18,8 @@ import { setupFontSize } from "@/utils";
 import { Local } from "@/utils/storage";
 import { motion } from "framer-motion";
 
-import Image from "next/image";
+import { PollingState, usePollingStore } from "@/stores/usePollingStore";
+import { useWalletStore } from "@/stores/useWalletStore";
 import styles from "./style.module.scss";
 
 export interface ProvidersProps {
@@ -94,14 +95,11 @@ const getStopServiceApi = () => {
  * @description  停服通知
  */
 const StopServiceClient = () => {
-    const { data: isSuspension } = useRequest(getStopServiceApi, {
-        pollingInterval: 10000,
-        pollingErrorRetryCount: 3,
-    });
+    const data = usePollingStore((state) => state.system_suspension);
 
     return (
         <>
-            {isSuspension && (
+            {data?.able && (
                 <div
                     className={
                         "absolute left-0 right-0 top-[0.4rem] z-[99999] bg-[#fff] p-[20px]" +
@@ -134,99 +132,28 @@ const StopServiceClient = () => {
         </>
     );
 };
+const getPollingApi = () => {
+    return server
+        .post<PollingState>({
+            url: "/v1/api/user/user_state",
+        })
+        .then((res) => res.data);
+};
 
-/**
- * @description 全局弹窗
- */
-const GlobalNotify = () => {
-    const [visible, setVisible] = useState(false);
-    return (
-        <>
-            <Mask visible={visible} onMaskClick={() => setVisible(false)}>
-                <div className="absolute left-0 top-[22%] w-[100%]">
-                    <div className={"relative h-[2.6rem]"}>
-                        {/*内容*/}
-                        <div
-                            className={"absolute left-0 top-0 z-10 h-[100%] w-[100%] p-[0.4167rem]"}
-                        >
-                            <div className={"flex h-[100%] flex-col items-center justify-center"}>
-                                <p className={"text-[0.2083rem] font-semibold text-[#532e0a]"}>
-                                    GANHE UM BÔNUS DE
-                                </p>
-                                <p
-                                    className={
-                                        "text-[0.5rem] font-black leading-[0.5rem]" +
-                                        " text-[#ec5c52]"
-                                    }
-                                >
-                                    999.00
-                                </p>
-                            </div>
-                        </div>
-                        {/*title*/}
-                        <Image
-                            src={"/notify/title.png"}
-                            className={
-                                "absolute -top-[0.7rem] left-1/2 -translate-x-1/2" +
-                                " w-[2.7778rem]"
-                            }
-                            alt={""}
-                            width={400}
-                            height={70}
-                        />
+const PollingClient = () => {
+    const setWallet = useWalletStore((state) => state.setWallet);
+    // 用户钱包
+    useRequest(getPollingApi, {
+        pollingInterval: 3000,
+        pollingErrorRetryCount: 3,
+        onSuccess: (data) => {
+            // setPollingState(data);
+            console.log(`🚀🚀🚀🚀🚀-> in providers.tsx on 151`, data.user_info);
+            setWallet(data.user_info);
+        },
+    });
 
-                        {/*铃铛*/}
-                        <Image
-                            src={"/notify/bell.png"}
-                            className={
-                                "absolute -top-[0.1rem] left-1/2 w-[0.8333rem] -translate-x-1/2"
-                            }
-                            alt={""}
-                            width={120}
-                            height={70}
-                        />
-                        {/*金币*/}
-                        <Image
-                            src={"/notify/money.png"}
-                            alt={""}
-                            width={750}
-                            className={
-                                "absolute -top-[0.5rem] left-0 h-[3.2rem] animate-slow-bounce"
-                            }
-                            height={512}
-                        />
-                        {/*光*/}
-                        <Image
-                            src={"/notify/light.png"}
-                            alt={""}
-                            width={750}
-                            className={
-                                "absolute -top-[120px] left-0 -z-10 h-[4.2rem] animate-spin" +
-                                " border-[green]"
-                            }
-                            style={{ animationDuration: "4s" }}
-                            height={512}
-                        />
-                        <Image
-                            src={"/notify/light1.png"}
-                            alt={""}
-                            width={750}
-                            className={"absolute -top-[80px] left-0 -z-10 h-[3.2rem]"}
-                            height={512}
-                        />
-                        {/*背景*/}
-                        <Image
-                            src={"/notify/bg.png"}
-                            alt={""}
-                            width={750}
-                            height={424}
-                            className={"mx-auto h-[2.6rem] w-[90%]"}
-                        />
-                    </div>
-                </div>
-            </Mask>
-        </>
-    );
+    return <></>;
 };
 
 /**
@@ -354,8 +281,8 @@ export default function SidebarLayout({ children, themeProps }: ProvidersProps)
                 ></div>
                 {/*停服通知*/}
                 <StopServiceClient />
-                {/*充值成功通知*/}
-                <GlobalNotify />
+                {/*轮询*/}
+                <PollingClient />
                 <section className={clsx(isShowBg && styles.homePage, "relative h-[100%]")}>
                     {children}
                 </section>

+ 4 - 15
src/app/[locale]/(TabBar)/template.tsx → src/app/[locale]/template.tsx

@@ -2,28 +2,17 @@
 
 import { usePathname } from "@/i18n/routing";
 import { AnimatePresence, motion } from "framer-motion";
-import { ReactNode, useEffect } from "react";
-const routerStack = new Map();
+import { ReactNode } from "react";
 const Template = ({ children }: { children: ReactNode }) => {
     const key = usePathname();
-
-    useEffect(() => {
-        if (routerStack.has(key)) {
-            routerStack.delete(key);
-        } else {
-            routerStack.set(key, key);
-        }
-    }, [key]);
-    const isEnter = routerStack.has(key);
-
     return (
         <AnimatePresence mode="popLayout">
             <motion.div
                 layout
                 key={key}
-                initial={{ x: routerStack.has(key) ? 750 : -750, opacity: 0 }}
-                animate={{ x: 0, opacity: 1 }}
-                exit={{ x: routerStack.has(key) ? -750 : 750, opacity: 0 }}
+                initial={{ scale: 0.9, opacity: 0 }}
+                animate={{ scale: 1, opacity: 1 }}
+                exit={{ scale: 0.9, opacity: 0 }}
                 transition={{ duration: 0.3 }}
                 className={"h-[100%]"}
             >

+ 14 - 15
src/components/Footer/index.tsx

@@ -8,10 +8,9 @@ import { useTranslations } from "next-intl";
 import { ChangeEvent, FC, ReactNode, useEffect } from "react";
 import "./style.scss";
 
-import { getUserDepositApi, getUserMoneyApi } from "@/api/user";
+import { getUserDepositApi } from "@/api/user";
 import { useEventPoint } from "@/hooks/useEventPoint";
 import { useGlobalNoticeStore } from "@/stores/useGlobalNoticeStore";
-import { useWalletStore } from "@/stores/useWalletStore";
 import { useRequest } from "ahooks";
 
 /**
@@ -79,7 +78,7 @@ const Footer: FC = () => {
             promotion_count: state.promotion_count,
         }));
 
-    const setWallet = useWalletStore((state) => state.setWallet);
+    // const setWallet = useWalletStore((state) => state.setWallet);
 
     const { run } = useRequest(getGlobalNoticeApi, {
         pollingInterval: 10000,
@@ -101,17 +100,17 @@ const Footer: FC = () => {
         },
     });
 
-    const { run: walletRun } = useRequest(getUserMoneyApi, {
-        pollingInterval: 5000,
-        pollingErrorRetryCount: 3,
-        staleTime: 5000,
-        manual: true,
-        refreshDeps: [token],
-        onError: (error) => {},
-        onSuccess: (res) => {
-            setWallet(res.data);
-        },
-    });
+    // const { run: walletRun } = useRequest(getUserMoneyApi, {
+    //     pollingInterval: 5000,
+    //     pollingErrorRetryCount: 3,
+    //     staleTime: 5000,
+    //     manual: true,
+    //     refreshDeps: [token],
+    //     onError: (error) => {},
+    //     onSuccess: (res) => {
+    //         setWallet(res.data);
+    //     },
+    // });
     const { run: depositRun } = useRequest(getUserDepositApi, {
         pollingInterval: 10000,
         pollingWhenHidden: true,
@@ -136,7 +135,7 @@ const Footer: FC = () => {
     useEffect(() => {
         if (getToken()) {
             run();
-            walletRun();
+            // walletRun();
             userRun();
             depositRun();
         }

+ 71 - 0
src/stores/usePollingStore.ts

@@ -0,0 +1,71 @@
+import { NoticeRep } from "@/api/home";
+import { SlotType } from "@/api/slots";
+import { DepositsLatestRep, Wallet } from "@/api/user";
+import { create } from "zustand";
+interface SuspensionType {
+    able: boolean;
+}
+export interface PollingState {
+    /**
+     * 免费领取活动信息
+     */
+    activity_give?: SlotType;
+    /**
+     * 红包信息
+     */
+    red_packets?: { [key: string]: any };
+    /**
+     * 系统公告信息
+     */
+    system_notice?: NoticeRep;
+    /**
+     * 系统停服信息
+     */
+    system_suspension?: SuspensionType;
+    /**
+     * 钱包信息
+     */
+    user_info?: Wallet;
+    /**
+     * 用户最近充值信息
+     */
+    user_latest_deposit?: DepositsLatestRep;
+    /**
+     * 站内信消息
+     */
+    user_letter?: NoticeRep;
+    /**
+     * 用户VIP信息
+     */
+    user_vip_info?: { [key: string]: any };
+}
+
+interface Actions {
+    setPollingState: (partialState: Partial<PollingState>) => void;
+    // // setActivity: (values: PollingState["activity_give"]) => void;
+    // reset: () => void;
+}
+
+const initialState: PollingState = {};
+
+// export const usePollingStore = create<PollingState & Actions>()(
+//     immer((set) => ({
+//         ...initialState,
+//         setPollingState: (values) => {
+//             //  todo 数据无变化则不更新。
+//             set((state) => ({ ...state, ...values }));
+//         },
+//     }))
+// );
+
+export const usePollingStore = create<PollingState & Actions>((set, getState) => {
+    return {
+        ...initialState,
+        setPollingState: (values) => {
+            const preValue = JSON.stringify(values);
+            const oldValue = JSON.stringify(getState());
+            //  todo 数据无变化则不更新。
+            set((state) => ({ ...state, ...values }));
+        },
+    };
+});

+ 1 - 1
src/stores/useWalletStore.ts

@@ -7,7 +7,7 @@ interface State {
 }
 
 interface Action {
-    setWallet: (state: Wallet) => void;
+    setWallet: (state?: Wallet) => void;
     setScore: (state: Wallet["score"]) => void;
     reset: () => void;
 }

+ 1 - 1
src/utils/client/axios.ts

@@ -125,7 +125,7 @@ export default class Request {
                         res = transform.responseInterceptor(res);
                     }
 
-                    if (res && res.data && res.data.code === 200) {
+                    if ((res && res.data && res.data.code === 200) || res.data.code === 2000) {
                         resolve(res.data);
                     } else {
                         if (res.data?.code) {