瀏覽代碼

fix: 更新红包雨组件

Before 8 月之前
父節點
當前提交
be283dcbd9

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

@@ -1,6 +1,7 @@
 "use client";
 import { ServiceTypes } from "@/api/customservice";
 import { lredPacketApi, redPacketApi } from "@/api/promo";
+import RedPacketModal, { RedPacketModalProps } from "@/components/Box/RedPacketModal";
 import { Link } from "@/i18n";
 import { useGlobalNoticeStore } from "@/stores/useGlobalNoticeStore";
 import { useSocialStore } from "@/stores/useSocials";
@@ -8,8 +9,7 @@ import { getToken } from "@/utils/Cookies";
 import { useRequest } from "ahooks";
 import { Badge } from "antd-mobile";
 import { useTranslations } from "next-intl";
-import { FC, useEffect, useState } from "react";
-import PopupHby from "../../promo/PopupHby";
+import { FC, useEffect, useRef, useState } from "react";
 
 interface Props {
     services: ServiceTypes[];
@@ -17,13 +17,13 @@ interface Props {
 }
 const ServiceWidget: FC<Props> = (props) => {
     const token = getToken();
-    const [isShowRedPacket, setIsShowRedPacket] = useState<any>(false);
     const [isShowRedIcon, setIsShowRedIcon] = useState(false);
     const { services, socials } = props;
     const defaultService = services.find((item) => item.is_suspend === 1);
 
     const newServices = services.filter((item) => item.is_suspend !== 1);
     const setSocials = useSocialStore((state) => state.setSocials);
+    const RedPacketModalRef = useRef<RedPacketModalProps>(null);
     useEffect(() => {
         // 数据存储,侧边栏使用
         setSocials(socials);
@@ -45,13 +45,13 @@ const ServiceWidget: FC<Props> = (props) => {
                 redPacketInfo = await redPacketApi();
                 actList = redPacketInfo.data || [];
             }
-            console.log(`🚀🚀🚀🚀🚀-> in Service.tsx on 48`, actList);
 
             // 是否有已开始但是没领过的红包
             let isHasStartAct = actList.filter((aItem: any) => {
-                return !!aItem.is_start && !aItem.is_receive;
+                return aItem.is_start && !aItem.is_receive;
             });
             let isShowRed = isHasStartAct.length > 0;
+            console.log(`🚀🚀🚀🚀🚀-> in Service.tsx on 54`, isShowRed);
             setIsShowRedIcon(isShowRed);
         } catch (error) {
             console.log("redPacketInfo===>error:", error);
@@ -81,20 +81,21 @@ const ServiceWidget: FC<Props> = (props) => {
                         className={"h-[0.3889rem] w-[0.3889rem]"}
                         src="/hby/red-icon.png"
                         onClick={() => {
-                            setIsShowRedPacket(true);
+                            RedPacketModalRef.current?.onOpen();
                         }}
                     />
                 </div>
             )}
 
             {/* 红包弹窗 */}
-            {isShowRedPacket && (
-                <PopupHby
-                    onClose={() => {
-                        setIsShowRedPacket(false);
-                    }}
-                />
-            )}
+            {/*{isShowRedPacket && (*/}
+            {/*    <PopupHby*/}
+            {/*        onClose={() => {*/}
+            {/*            setIsShowRedPacket(false);*/}
+            {/*        }}*/}
+            {/*    />*/}
+            {/*)}*/}
+            <RedPacketModal ref={RedPacketModalRef} />
 
             {defaultService && (
                 <Link

+ 489 - 0
src/components/Box/RedPacketModal.tsx

@@ -0,0 +1,489 @@
+"use client";
+
+import { lredPacketApi, receiveRedPacketApi, redPacketApi } from "@/api/promo";
+import { getToken } from "@/utils/Cookies";
+import { Mask } from "antd-mobile";
+import Image from "next/image";
+import { forwardRef, Fragment, useEffect, useImperativeHandle, useRef, useState } from "react";
+import styles from "./redpacked.module.scss";
+
+const randomX = (len: number) => {
+    return Math.floor(Math.random() * len);
+};
+const mockData = Array(500)
+    .fill(0)
+    .map((item) => {
+        return {
+            phone: `55****${(randomX(99) + "").padEnd(2, "0")}`,
+            num: `${(Math.random() * 20).toFixed(2)}`,
+            time: "11:00",
+        };
+    });
+function getRandom(min: number, max: number) {
+    const floatRandom = Math.random();
+
+    const difference = max - min;
+
+    // 介于 0 和差值之间的随机数
+    const random = Math.round(difference * floatRandom);
+
+    return random + min;
+}
+/**
+ * @description 描述
+ */
+type DescProps = {
+    onClose: () => void;
+};
+const Desc = (props: DescProps) => {
+    const { onClose } = props;
+    const [activeTab, setActiveTab] = useState(0);
+    const tabs = [{ text: "Vezes de evento participado" }, { text: "Consulta de registo levado" }];
+    return (
+        <div className={"absolute top-[30%] w-[100%]"}>
+            <div className={"absolute -top-[1.3rem] left-1/2 w-[3.3rem] -translate-x-1/2"}>
+                <img src="/9f/red-header.png" alt="" />
+                <div
+                    className={
+                        "h-[0.2rem] w-[0.2rem] " + " absolute bottom-[20px] right-[30px]" + " "
+                    }
+                    onClick={onClose}
+                >
+                    <Image src={"/9f/close.png"} alt={"close"} width={25} height={25} />
+                </div>
+            </div>
+            <div
+                className={"mx-auto w-[2.9rem] bg-[#ff9417] px-[0.16rem] pb-[0.12rem] pt-[0.44rem]"}
+            >
+                <img src="/9f/red-title.png" alt="" className={"mx-auto w-[90%]"} />
+                <div className={"mt-[0.0694rem] rounded-[3px] bg-primary-color"}>
+                    <div className={"flex h-[0.54rem] justify-between text-center text-[0.15rem]"}>
+                        {tabs.map((item, index) => {
+                            return (
+                                <Fragment key={index}>
+                                    <span
+                                        onClick={() => setActiveTab(index)}
+                                        className={`flex h-[100%] items-center ${index === activeTab ? "bg-[#8b3500] text-[#5f2600]" : ""}`}
+                                    >
+                                        {item.text}
+                                    </span>
+                                </Fragment>
+                            );
+                        })}
+                    </div>
+                    {/*  动态内容 */}
+                    <div className={"h-[3rem] overflow-y-scroll p-[0.1rem]"}>
+                        <div
+                            className={
+                                "flex items-center rounded-[0.1rem] bg-[#d45300] p-[10px] font-bold"
+                            }
+                        >
+                            <Image
+                                className={"h-[0.43rem] w-[0.7rem]"}
+                                width={80}
+                                height={40}
+                                src="/9f/wallet.png"
+                                alt=""
+                            />
+                            <div className={"text-center"}>
+                                <h2> Tempo regressivo </h2>
+                                <p className={"text-[#fe0]"}>Começa amanhã às 11:00</p>
+                            </div>
+                        </div>
+
+                        {!activeTab ? (
+                            <>
+                                <Image
+                                    src={"/9f/6xtime.png"}
+                                    className={"mt-[0.1rem] h-[0.7rem] w-[100%] rounded-[0.1rem]"}
+                                    width={600}
+                                    height={100}
+                                    alt={"time"}
+                                ></Image>
+
+                                <Image
+                                    src={"/9f/3xtime.png"}
+                                    className={"mt-[0.1rem] h-[0.55rem] w-[100%] rounded-[0.1rem]"}
+                                    width={600}
+                                    height={80}
+                                    alt={"time"}
+                                ></Image>
+                            </>
+                        ) : (
+                            <>
+                                <div
+                                    className={"mt-[0.1rem] rounded-[0.1rem] bg-[#d45300] p-[10px]"}
+                                >
+                                    <p className={"text-[#fe0]"}>Registro persoal</p>
+                                    <div
+                                        className={
+                                            "grid grid-cols-3 text-center" +
+                                            " items-center text-[0.1rem]"
+                                        }
+                                    >
+                                        <span>Nome do jogo</span>
+                                        <span>Coleta cumulativa</span>
+                                        <span>Participação total</span>
+                                    </div>
+
+                                    <div
+                                        className={
+                                            "grid grid-cols-3 text-center" +
+                                            " items-center text-[0.12rem] font-bold"
+                                        }
+                                    >
+                                        <span>55****26</span>
+                                        <span>R$ 100.00</span>
+                                        <span>1</span>
+                                    </div>
+                                </div>
+                                <div
+                                    className={"mt-[0.1rem] rounded-[0.1rem] bg-[#d45300] p-[10px]"}
+                                >
+                                    <p className={"text-[#fe0]"}>Lista dos vencedores</p>
+                                    <div
+                                        className={
+                                            "grid grid-cols-3 text-center" +
+                                            " items-center text-[0.1rem]"
+                                        }
+                                    >
+                                        <span>ID do papel</span>
+                                        <span>Valor obtido</span>
+                                        <span>Hora obtida</span>
+                                    </div>
+                                    <div className={`h-[1rem] overflow-hidden`}>
+                                        {mockData.map((item, index) => {
+                                            return (
+                                                <div
+                                                    key={index}
+                                                    className={`grid grid-cols-3 items-center text-center text-[0.12rem] font-bold ${styles.scrollAnimation}`}
+                                                >
+                                                    <span>{item.phone}</span>
+                                                    <span>R$ {item.num}</span>
+                                                    <span>{item.time}</span>
+                                                </div>
+                                            );
+                                        })}
+                                    </div>
+                                </div>
+                            </>
+                        )}
+
+                        <ul className={"mt-[0.1rem] text-[0.1rem]"}>
+                            <li>
+                                ·Cada sessão de chuva de dinheiro é distribuída gratuitamente por
+                                R$100.000.
+                            </li>
+                            <li>
+                                ·Valor máximo de queda em dinheiro: Cada sessão de chuva de dinheiro
+                                é distribuída gratuitamente.
+                            </li>
+                            <li>·Membros recarregados podem reivindicar gratuitamente.</li>
+                            <li>
+                                ·O dinheiro recebido pode ser utilizado para jogar ou sacar
+                                diretamente.
+                            </li>
+                            <li>
+                                ·Quanto for maior o nível de associação VIP, será maior o valor
+                                recebido.
+                            </li>
+                        </ul>
+                    </div>
+                </div>
+            </div>
+        </div>
+    );
+};
+
+const FallAnimation = (props: any) => {
+    const { onClose } = props;
+    const fallContentRef = useRef<HTMLDivElement>(null);
+
+    const totalPackets = 200;
+    const timer = useRef<NodeJS.Timer>(null);
+    const total = useRef(0);
+    const createPacket = (xPoint: number) => {
+        const packetWrapperEl = document.createElement("div");
+        packetWrapperEl.classList.add(styles.packetWrapper);
+        packetWrapperEl.style.left = xPoint + "px";
+        packetWrapperEl.style.width = `77px`;
+        packetWrapperEl.style.height = `44px`;
+        packetWrapperEl.style.transform = `scale(0.8) `;
+
+        const packetEl = document.createElement("img");
+        packetEl.classList.add(styles.packet);
+
+        packetEl.style.width = `${getRandom(44, 77)}`;
+        packetEl.style.height = `${getRandom(44, 77)}`;
+
+        packetEl.src = `/9f/money${Math.floor(Math.random() * 3) + 1}.png`;
+
+        setInterval(() => {
+            packetEl.style.transform = `rotate(${getRandom(0, 180)}deg) translateX(${Math.random() > 0.5 ? getRandom(0, 180) : -getRandom(0, 180)}px) scale(${getRandom(0.4, 1.2)}) `;
+        }, 1000);
+
+        packetWrapperEl.appendChild(packetEl);
+        fallContentRef.current?.appendChild(packetWrapperEl);
+    };
+
+    useEffect(() => {
+        // @ts-ignore
+        timer.current = setInterval(() => {
+            if (total.current >= totalPackets - 1) {
+                clearInterval(Number(timer.current));
+                return;
+            }
+            total.current += 1;
+            createPacket(Math.random() * fallContentRef.current?.clientWidth! || 500);
+        }, 200);
+        return () => {
+            clearInterval(Number(timer.current));
+        };
+    }, []);
+    return (
+        <div
+            ref={fallContentRef}
+            style={{ height: "100dvh" }}
+            className={"h-dvh overflow-hidden"}
+            onClick={onClose}
+        ></div>
+    );
+};
+
+const HbyInfoDetail = (props: any) => {
+    const { iconImg, onCloseHby } = props;
+    return (
+        <div
+            className={`absolute left-1/2 top-[50%] w-[90%] -translate-x-1/2 -translate-y-1/2 ${styles.promoRules}`}
+        >
+            {/* <Image src={"/hby/close.png"} alt={"close"} width={25} height={25} onClick={onCloseHby} className={styles.closeIcon}/> */}
+            <div onClick={onCloseHby} className={styles.closeIcon}></div>
+            <Image src={iconImg} alt={"detail"} width={672} height={1044} />
+            {/* <div className={`h-[0.15rem] text-[#ffd800] text-[0.20rem] text-center ${styles.promoTitle}`}>Dinheiro como chuva</div>
+      <div className={styles.titleWrap}>
+          <span>R$200.00</span>
+          <span> por vez, </span>
+          <span>Máx queda </span>
+          <span>R$7.777</span>
+      </div>
+      <div className={styles.tips}>
+        <img src="/hby/tip-icon.png" alt="tips"  className={styles.tipsIcon}/>
+        <div className={styles.tipsTime}>Começa às 23:00</div>
+      </div>
+      <div className={styles.times1}>
+        <img src="/hby/time1.png"/>
+      </div>
+      <div className={styles.times2}>
+        <img src="/hby/time2.png"/>
+      </div>
+      <ul className={styles.rulelist}>
+        <li className={styles.ruleItem}>
+          Cada sessão de chuva de dinheiro é distribuída gratuitamente com <span>R$200.000</span>
+        </li>
+        <li className={styles.ruleItem}>
+          Valor máximo de queda em dinheiro:Cada sessäo de chuva de dinheiro é distribuida gratuitamente com
+        </li>
+        <li className={styles.ruleItem}>
+          Membros recarregados podem reivindicar gratuitamente
+        </li>
+        <li className={styles.ruleItem}>
+          O dinheiro recebido pode ser utilizado para jogar ou sacado diretamente
+        </li>
+        <li className={styles.ruleItem}>
+          Quanto maior o nivel de associacäo VP, maior o valor recebido
+        </li>
+      </ul> */}
+        </div>
+    );
+};
+
+const HbyInfo = (props: any) => {
+    const { iconImg, onCloseHby, onReciveRed } = props;
+    if (!iconImg) return;
+    return (
+        <div
+            className={`absolute left-1/2 top-[50%] -translate-x-1/2 -translate-y-1/2 ${styles.redclose}`}
+        >
+            {/* <Image src={"/hby/close.png"} alt={"close"} width={20} height={20} onClick={onCloseHby} className={styles.closeIcon}/> */}
+            <div onClick={onCloseHby} className={styles.closeIcon}></div>
+            <img
+                src={iconImg}
+                alt={"icon"}
+                width={559}
+                height={687}
+                onClick={onReciveRed}
+                className={styles.redIcon}
+            />
+            {/* <div className={styles.title}>Chuva de dinheiro</div>
+      <div className={styles.desc}>
+        <ul className={styles.desclist}>
+          <li className={styles.descitem}>  Membros recarregados podem reivindicar gratuitamente. </li>
+          <div className={styles.line}></div>
+          <li className={styles.descitem}> Valor máximo de queda em dinheiro: R$7.777 </li>
+        </ul>
+      </div>
+      <div className={styles.openBtn} onClick={onReciveRed}>AGARRAR</div> */}
+        </div>
+        // <div data-v-f333135e="" className={`absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 ${styles.redopen}`}>
+        //   <Image src={"/hby/close.png"} alt={"close"} width={20} height={20} onClick={onCloseHby} className={styles.closeIcon}/>
+        //   <div className={styles.title}>Chuva de dinheiro</div>
+        //   <div className={styles.cash}>1.96</div>
+        //   <div className={styles.tips}>Valor máximo de queda em dinheiro:Cada sessäo de chuva de dinheiro é </div>
+        // </div>
+    );
+};
+
+const HbyInfo2 = (props: any) => {
+    const { iconImg, onCloseHby, redAmount } = props;
+    console.log(`🚀🚀🚀🚀🚀-> in PopupHby.tsx on 364`, iconImg);
+    return (
+        <div
+            className={`absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 ${styles.redopen}`}
+        >
+            <Image
+                src={"/hby/close.png"}
+                alt={"close"}
+                width={30}
+                height={30}
+                onClick={onCloseHby}
+                className={styles.closeIcon}
+            />
+            {/* <div onClick={onCloseHby} className={styles.closeIcon}></div> */}
+            <Image src={iconImg} alt={"icon"} width={559} height={687} />
+            <div className={styles.cash}>{redAmount}</div>
+            {/* <div className={styles.title}>Chuva de dinheiro</div>
+      <div className={styles.cash}>{redAmount}</div>
+      <div className={styles.tips}>Valor máximo de queda em dinheiro:Cada sessäo de chuva de dinheiro é </div> */}
+        </div>
+    );
+};
+
+type Props = {};
+export type RedPacketModalProps = {
+    onClose: () => void;
+    onOpen: () => void;
+};
+const RedPacketModal = forwardRef<RedPacketModalProps, Props>(function RedPacketModal(props, ref) {
+    const [visible, setVisible] = useState(false);
+
+    const [iconLists, setIconLists] = useState<any>([]);
+    const [isShowRed, setIsShowRed] = useState(false);
+    const [isShowReciveRed, setIsShowReciveRed] = useState(false);
+    const [isShowRedDetail, setIsShowRedDetail] = useState(false);
+    const [redPacketInfo, setRedPacketInfo] = useState<any>({});
+    const [redAmount, setRedAmount] = useState<any>(0);
+    const token = getToken();
+    useImperativeHandle(ref, () => {
+        return {
+            onClose: () => setVisible(false),
+            onOpen: () => {
+                getRedPacketInfo().then((res) => {
+                    setVisible(true);
+                });
+            },
+        };
+    });
+    useEffect(() => {
+        // getRedPacketInfo();
+    }, []);
+
+    const getRedPacketInfo = async () => {
+        try {
+            let actList: any = [];
+            if (token) {
+                let redPacketInfo = await lredPacketApi();
+                actList = redPacketInfo.data?.red_packets || [];
+            } else {
+                let redPacketInfo = await redPacketApi();
+                actList = redPacketInfo.data;
+            }
+            // 是否有已开始但是没领过的红包
+            let isHasStartAct = actList.filter((aItem: any) => {
+                return !!aItem.is_start && !aItem.is_receive;
+            });
+            console.log(`🚀🚀🚀🚀🚀-> in RedPacketModal.tsx on 427`, actList);
+
+            let isShowRed = isHasStartAct.length > 0;
+            let isShowRedDetail = isHasStartAct.length === 0;
+            let redInfo = isShowRed ? isHasStartAct[0] : {};
+            let curAct = !!isShowRedDetail ? findCurrentActivity(actList) : actList[0];
+            let iconList = JSON.parse(curAct.icon);
+
+            setIconLists(iconList);
+            setIsShowRed(isShowRed);
+            setIsShowRedDetail(isShowRedDetail);
+            setRedPacketInfo(redInfo);
+        } catch (error) {
+            console.log("redPacketInfo===>error:", error);
+        }
+    };
+
+    // 筛选出离当前时间最近的活动
+    const findCurrentActivity = (activities: any) => {
+        const now = Math.floor(Date.now() / 1000); // 获取当前时间的时间戳(单位:秒)
+        let closestActivity = null;
+        let isInRange = false;
+
+        // 遍历活动数据
+        for (let i = 0; i < activities.length; i++) {
+            const activity = activities[i];
+
+            // 检查当前时间是否在活动的时间范围内
+            if (now >= activity.start_time && now <= activity.end_time) {
+                isInRange = true;
+                return activity; // 如果在范围内,直接返回当前活动
+            }
+
+            // 如果不在范围内,记录离当前时间最近的活动
+            if (
+                !closestActivity ||
+                Math.abs(now - activity.end_time) < Math.abs(now - closestActivity.end_time)
+            ) {
+                closestActivity = activity;
+            }
+        }
+
+        // 如果不在任何活动范围内,返回离当前时间最近的活动
+        return closestActivity;
+    };
+
+    const onReciveRed = async () => {
+        try {
+            let paramsData = {
+                id: redPacketInfo?.id,
+                index: redPacketInfo?.index,
+            };
+            let receiveRedPacketInfo = await receiveRedPacketApi(paramsData);
+            let redNum = receiveRedPacketInfo.data;
+            setIsShowRed(false);
+            setIsShowReciveRed(true);
+            setRedAmount(redNum?.amount);
+        } catch (error) {
+            console.log("redPacketInfo===>error:", error);
+        }
+    };
+    return (
+        <Mask visible={visible} destroyOnClose={true}>
+            <FallAnimation onClose={() => setVisible(false)} />
+            {isShowRedDetail && (
+                <HbyInfoDetail onCloseHby={() => setVisible(false)} iconImg={iconLists[0]} />
+            )}
+            {isShowRed && (
+                <HbyInfo
+                    onCloseHby={() => setVisible(false)}
+                    onReciveRed={onReciveRed}
+                    iconImg={iconLists[1]}
+                />
+            )}
+            {isShowReciveRed && (
+                <HbyInfo2
+                    onCloseHby={() => setVisible(false)}
+                    redAmount={redAmount}
+                    iconImg={iconLists[2]}
+                />
+            )}
+        </Mask>
+    );
+});
+
+export default RedPacketModal;

+ 7 - 2
src/components/Box/index.tsx

@@ -1,10 +1,11 @@
 "use client";
 import { ActionType } from "@/api/home";
+import RedPacketModal, { RedPacketModalProps } from "@/components/Box/RedPacketModal";
 import { useRouter } from "@/i18n";
 import { isHttpUrl } from "@/utils";
 import { Toast } from "antd-mobile";
 import clsx from "clsx";
-import { CSSProperties, FC, PropsWithChildren } from "react";
+import { CSSProperties, FC, PropsWithChildren, useRef } from "react";
 import { twMerge } from "tailwind-merge";
 interface Props {
     pt?: boolean;
@@ -46,6 +47,8 @@ enum ModalEnum {
 }
 const Box: FC<PropsWithChildren<Props>> = (props) => {
     const router = useRouter();
+
+    const RedPacketModalRef = useRef<RedPacketModalProps>(null);
     const {
         className,
         children,
@@ -83,7 +86,7 @@ const Box: FC<PropsWithChildren<Props>> = (props) => {
                 break;
             case 4:
                 if (actionData === ModalEnum.red_packet) {
-                    console.log(`🎯🎯🎯🎯🎯-> in index.tsx on 59`, actionData);
+                    RedPacketModalRef.current?.onOpen();
                 }
                 break;
             case 5:
@@ -104,6 +107,8 @@ const Box: FC<PropsWithChildren<Props>> = (props) => {
             <Tag className={twMerge(cls)} style={style} onClick={handler}>
                 {children}
             </Tag>
+
+            <RedPacketModal ref={RedPacketModalRef} />
         </>
     );
 };

+ 296 - 0
src/components/Box/redpacked.module.scss

@@ -0,0 +1,296 @@
+@keyframes smoothscroll {
+  0% {
+    transform: translateY(0);
+  }
+
+  100% {
+    transform: translateY(-20rem);
+  }
+}
+
+.scrollAnimation {
+  padding: 3px 0;
+  animation: smoothscroll 30s linear infinite;
+}
+
+
+/* From Uiverse.io by vamsidevendrakumar */
+.card {
+  width: 300px;
+  height: 200px;
+  perspective: 1000px;
+}
+
+.cardInner {
+  width: 100%;
+  height: 100%;
+  position: relative;
+  transform-style: preserve-3d;
+  transition: transform 0.999s;
+}
+
+.card:hover .cardInner {
+  transform: rotateY(180deg);
+}
+
+.cardFront,
+.cardBack {
+  position: absolute;
+  width: 100%;
+  height: 100%;
+  backface-visibility: hidden;
+}
+
+.cardFront {
+  background-color: #6A2C70;
+  color: #fff;
+  display: flex;
+  align-items: center;
+  border: 10px solid #6A2C70;
+  border-radius: 10px;
+  justify-content: center;
+  font-size: 24px;
+  transform: rotateY(0deg);
+}
+
+.cardBack {
+  background-color: #F08A5D;
+  color: #fff;
+  display: flex;
+  align-items: center;
+  border: 10px solid #F08A5D;
+  border-radius: 10px;
+  justify-content: center;
+  font-size: 24px;
+  transform: rotateY(180deg);
+}
+
+.packetWrapper {
+  position: absolute;
+  top: 0;
+  left: 0;
+  transform: translateY(-100%);
+  animation: down 8s linear infinite;
+  font-size: 0;
+}
+
+.packet{
+  width: 100%;
+  height: 100%;
+  position: relative;
+  transition: all 3s ease;
+  transform: rotate(0);
+}
+
+@keyframes down {
+  0% {
+    transform: translateY(-100%);
+  }
+
+  100% {
+    transform: translateY(100vh);
+  }
+}
+
+
+.promoRules{
+  // background:url('/hby/hby_bg.png') no-repeat;
+  background-size: 100% 100%;
+
+  .promoTitle{
+    font-weight:400;
+    font-weight:700;
+  }
+  .titleWrap{
+    font-size:.18rem;
+    text-align: center;
+    color:#ffdf7f;
+    margin:0.1rem 0;
+  }
+  .tips{
+    margin:0 auto;
+    width:2.5rem;
+    height:0.6rem;
+    background: url('/hby/tip-bg.png') no-repeat;
+    background-size: 100% auto;
+    display: flex;
+    justify-content: center;
+    line-height:0.48rem;
+    .tipsIcon{
+      display: inline-block;
+      width:0.40rem;
+      height:0.25rem;
+      margin:0.11rem 0 0;
+    }
+    .tipsTime{
+      color:#3ab54c;
+      font-size:.18rem;
+      font-weight:700;
+      margin:0 0 0 0.1rem;
+    }
+  }
+
+  .times1{
+    margin:0.14rem auto;
+  }
+
+  .rulelist{
+    width:90%;
+    font-family: 'Arial-BoldMT, Arial';
+    color:#fff8bb;
+    font-size:0.1rem;
+    line-height:0.14rem;
+    list-style-type: disc;
+    transform: scale(0.96);
+    margin:0.08rem 0 0 .1rem;
+    .ruleItem{
+      list-style: disc;
+    }
+  }
+  .closeIcon{
+    position: absolute;
+    width: 30px;
+    height:30px;
+    right:0.12rem;
+    top:0.1rem;
+    cursor: pointer;
+  }
+}
+
+
+.redclose{
+  display: flex;
+  -webkit-box-pack: start;
+  -ms-flex-pack: start;
+  justify-content: flex-start;
+  -webkit-box-align: center;
+  -ms-flex-align: center;
+  align-items: center;
+  -webkit-box-orient: vertical;
+  -webkit-box-direction: normal;
+  -ms-flex-direction: column;
+  flex-direction: column;
+
+  width: 2.09rem;
+  height: 2.575rem;
+  // background: url('/hby/red-bg1.png') no-repeat;
+  // background-size: 2.09rem 2.575rem;
+  z-index: 120;
+  .closeIcon{
+    position: absolute;
+    right:0;
+    top:0;
+    width:40px;
+    height:40px;
+    cursor: pointer;
+  }
+  .redIcon{
+    cursor: pointer;
+  }
+  .title{
+    color: #ffd800;
+    font-size: .18rem;
+    text-align: center;
+    font-family:' Arial-BoldMT,Arial';
+    font-weight: 700;
+    width: 1.8rem;
+    height: .25rem;
+    margin-top: .24rem
+  }
+
+  .desc{
+    color: #fff;
+    font-size: .13rem;
+    font-family: 'Arial-BoldMT,Arial';
+    width: 1.6rem;
+    height: 1rem;
+    margin-left: .22rem;
+    .desclist{
+      list-style-type: disc;
+      font-size:0.1rem;
+      transform: scale(0.96);
+      font-weight: 400;
+      .line{
+        margin-top: .09rem;
+        margin-left: -.14rem;
+        width: 1.6rem;
+        height: .005rem;
+        background: hsla(0,0%,100%,.2)
+      }
+      li{
+        margin-top: .08rem;
+        list-style: disc;
+      }
+    }
+  }
+
+  .openBtn {
+    cursor: pointer;
+    margin: .06rem auto 0;
+    width: 1rem;
+    height: .3rem;
+    line-height: .3rem;
+    font-family: 'Arial-BoldMT,Arial';
+    color: #613e00;
+    font-size: .115rem;
+    font-weight: 700;
+    text-align: center
+  }
+
+}
+
+.redopen{
+  display: flex;
+  -webkit-box-pack: start;
+  -ms-flex-pack: start;
+  justify-content: flex-start;
+  -webkit-box-align: center;
+  -ms-flex-align: center;
+  align-items: center;
+  -webkit-box-orient: vertical;
+  -webkit-box-direction: normal;
+  -ms-flex-direction: column;
+  flex-direction: column;
+
+  width: 2.11rem;
+  height: 2.555rem;
+  // background: url('/hby/red-bg2.png') no-repeat;
+  // background-size: 2.11rem 2.555rem;
+  z-index: 120;
+  .closeIcon{
+    position: absolute;
+    right:0;
+    top:0;
+    cursor: pointer;
+  }
+  .title{
+    color: #925c00;
+    font-size: .16rem;
+    text-align: center;
+    font-family: 'Arial-BoldMT,Arial';
+    width: 1.595rem;
+    margin-top: .4rem
+  }
+  .cash{
+    position:absolute;
+    top:40%;
+    color: #8c0c04;
+    text-align: center;
+    font-family: "Arial-BoldMT,Arial";
+    font-weight: 700;
+    font-size: .55rem
+  }
+  .tips{
+    margin-top: .3rem;
+    width: 1.545rem;
+    color: #ffd800;
+    text-align: center;
+    font-family:" Arial-BoldMT,Arial";
+    font-size: .1rem;
+    line-height:.12rem;
+    transform: scale(0.96);
+  }
+
+}
+
+