123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518 |
- "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: (index?: number) => void;
- };
- /**
- * @description 红包的三种状态
- * is_start 可领取 展示红包领取组件
- * is_receive 已领取 展示领取详情组件
- * is_end 可展示 展示详情界面
- */
- enum Status {
- is_start,
- is_receive,
- is_end,
- }
- 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 activeIndex = useRef<number | null>(null);
- const token = getToken();
- useImperativeHandle(ref, () => {
- return {
- onClose: () => setVisible(false),
- onOpen: (index?: number) => {
- if (index !== null && index !== undefined) {
- activeIndex.current = index;
- }
- 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 packets = actList.filter((aItem: any) => {
- return !!aItem.is_start && !aItem.is_receive;
- });
- let current = null;
- if (activeIndex.current !== null && activeIndex.current !== undefined) {
- current = packets[activeIndex.current];
- } else {
- current = findCurrentActivity(packets);
- }
- let isShowRed = packets.length > 0;
- let isShowRedDetail = packets.length === 0;
- //
- // let redInfo = isShowRed ? isHasStartAct[0] : {};
- // if (activeIndex.current !== undefined && activeIndex.current !== null) {
- // redInfo = isHasStartAct[activeIndex.current];
- // }
- // let curAct = isShowRedDetail ? findCurrentActivity(actList) : actList[0];
- let iconList = JSON.parse(current.icon);
- setIconLists(iconList);
- setRedPacketInfo(current);
- setIsShowRed(isShowRed);
- setIsShowRedDetail(isShowRedDetail);
- } 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;
|