|
@@ -4,10 +4,8 @@ import { receiveRedPacketApi } from "@/api/promo";
|
|
import { useRouter } from "@/i18n/routing";
|
|
import { useRouter } from "@/i18n/routing";
|
|
import { getToken } from "@/utils/Cookies";
|
|
import { getToken } from "@/utils/Cookies";
|
|
import { Mask } from "antd-mobile";
|
|
import { Mask } from "antd-mobile";
|
|
-import clsx from "clsx";
|
|
|
|
import { useTranslations } from "next-intl";
|
|
import { useTranslations } from "next-intl";
|
|
import { FC, forwardRef, memo, useEffect, useImperativeHandle, useRef, useState } from "react";
|
|
import { FC, forwardRef, memo, useEffect, useImperativeHandle, useRef, useState } from "react";
|
|
-import styles from "./style.module.scss";
|
|
|
|
const randomX = (len: number) => {
|
|
const randomX = (len: number) => {
|
|
return Math.floor(Math.random() * len);
|
|
return Math.floor(Math.random() * len);
|
|
};
|
|
};
|
|
@@ -37,8 +35,79 @@ type DescProps = {
|
|
onClose: () => void;
|
|
onClose: () => void;
|
|
};
|
|
};
|
|
|
|
|
|
-const HbyInfoDetail = (props: any) => {
|
|
|
|
- const { iconImg, onCloseHby } = props;
|
|
|
|
|
|
+export interface RedPacketTypes {
|
|
|
|
+ countdown: number;
|
|
|
|
+ /**
|
|
|
|
+ * 活动结束时间戳
|
|
|
|
+ */
|
|
|
|
+ end_time: number;
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 活动详情图片
|
|
|
|
+ */
|
|
|
|
+ icon: string;
|
|
|
|
+ /**
|
|
|
|
+ * 活动ID
|
|
|
|
+ */
|
|
|
|
+ id: number;
|
|
|
|
+ /**
|
|
|
|
+ * 红包索引
|
|
|
|
+ */
|
|
|
|
+ index: number;
|
|
|
|
+ /**
|
|
|
|
+ * 是否能领取
|
|
|
|
+ */
|
|
|
|
+ can_receive: boolean;
|
|
|
|
+ /**
|
|
|
|
+ * 是否领取
|
|
|
|
+ */
|
|
|
|
+ is_receive: boolean;
|
|
|
|
+ /**
|
|
|
|
+ * 是否开始
|
|
|
|
+ */
|
|
|
|
+ is_start: boolean;
|
|
|
|
+ /**
|
|
|
|
+ * 红包详情
|
|
|
|
+ */
|
|
|
|
+ rewards: Reward[];
|
|
|
|
+ /**
|
|
|
|
+ * 活动开始时间戳
|
|
|
|
+ */
|
|
|
|
+ start_time: number;
|
|
|
|
+ /**
|
|
|
|
+ * 显示时间
|
|
|
|
+ */
|
|
|
|
+ time_string: string;
|
|
|
|
+ times: string[];
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+export interface Reward {
|
|
|
|
+ /**
|
|
|
|
+ * 红包等级
|
|
|
|
+ */
|
|
|
|
+ level: number;
|
|
|
|
+ max_amount: number;
|
|
|
|
+ max_vip: number;
|
|
|
|
+ min_amount: number;
|
|
|
|
+ min_vip: number;
|
|
|
|
+ multiple: number;
|
|
|
|
+ /**
|
|
|
|
+ * 红包名称
|
|
|
|
+ */
|
|
|
|
+ name: string;
|
|
|
|
+ total: number;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+interface PacketDetailsProps {
|
|
|
|
+ packet: RedPacketTypes;
|
|
|
|
+ iconImg: string;
|
|
|
|
+ onCloseHby: () => void;
|
|
|
|
+ onReciveRed: () => void;
|
|
|
|
+ redAmount: number;
|
|
|
|
+}
|
|
|
|
+/// 红包详情
|
|
|
|
+const PacketEndDetail: FC<Omit<PacketDetailsProps, "onReciveRed" | "redAmount">> = (props) => {
|
|
|
|
+ const { iconImg, onCloseHby, packet } = props;
|
|
const router = useRouter();
|
|
const router = useRouter();
|
|
const token = getToken();
|
|
const token = getToken();
|
|
const handler = () => {
|
|
const handler = () => {
|
|
@@ -47,13 +116,12 @@ const HbyInfoDetail = (props: any) => {
|
|
}
|
|
}
|
|
onCloseHby();
|
|
onCloseHby();
|
|
};
|
|
};
|
|
- const str = "12:00".split("");
|
|
|
|
-
|
|
|
|
|
|
+ const str = packet.time_string.split("");
|
|
return (
|
|
return (
|
|
- <div className={`absolute h-[100%] w-[100%]`} onClick={onCloseHby}>
|
|
|
|
|
|
+ <div className={`absolute h-[100%] w-[100%]`} onClick={handler}>
|
|
<div className={"flex h-[100%] w-[100%] items-center"}>
|
|
<div className={"flex h-[100%] w-[100%] items-center"}>
|
|
<div className={"relative h-[6.2rem] w-[100%]"}>
|
|
<div className={"relative h-[6.2rem] w-[100%]"}>
|
|
- <img className={"h-[6.2rem] w-[100%]"} src="/redpacket/isEndBg.png" alt="" />
|
|
|
|
|
|
+ <img className={"h-[6.2rem] w-[100%]"} src={iconImg} alt="" />
|
|
{/* 下一场开始时间*/}
|
|
{/* 下一场开始时间*/}
|
|
<div className={"absolute top-[27%] w-[100%]"}>
|
|
<div className={"absolute top-[27%] w-[100%]"}>
|
|
<div className={"relative h-[0.4306rem] border-primary-color"}>
|
|
<div className={"relative h-[0.4306rem] border-primary-color"}>
|
|
@@ -77,76 +145,93 @@ const HbyInfoDetail = (props: any) => {
|
|
|
|
|
|
<div
|
|
<div
|
|
className={
|
|
className={
|
|
- "absolute top-[53%] h-[0.6944rem] w-[100%] px-[0.5556rem]" +
|
|
|
|
- " overflow-scroll border-primary-color text-primary-color"
|
|
|
|
|
|
+ "absolute top-[53%] h-[0.6944rem] w-[100%] px-[0.6944rem]" +
|
|
|
|
+ " grid grid-cols-3 overflow-scroll border-primary-color" +
|
|
|
|
+ " text-[18px] text-[red]"
|
|
}
|
|
}
|
|
- ></div>
|
|
|
|
|
|
+ >
|
|
|
|
+ {packet.times.map((time, parentIndex) => {
|
|
|
|
+ return (
|
|
|
|
+ <div key={parentIndex} className={""}>
|
|
|
|
+ {time}
|
|
|
|
+ </div>
|
|
|
|
+ );
|
|
|
|
+ })}
|
|
|
|
+ </div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
);
|
|
};
|
|
};
|
|
|
|
|
|
-const HbyInfo = (props: any) => {
|
|
|
|
- const { iconImg, onCloseHby, onReciveRed } = props;
|
|
|
|
- if (!iconImg) return;
|
|
|
|
|
|
+const PacketStartDetail: FC<Omit<PacketDetailsProps, "redAmount">> = (props) => {
|
|
|
|
+ const { iconImg, onCloseHby, onReciveRed, packet } = props;
|
|
|
|
+ const maxCount = packet.rewards
|
|
|
|
+ .reduce((p, n) => (p > n.max_amount ? p : n.max_amount), 0)
|
|
|
|
+ .toFixed(2);
|
|
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 className={`absolute h-[100%] w-[100%]`} onClick={onCloseHby}>
|
|
|
|
+ <div className={"flex h-[100%] w-[100%]"}>
|
|
|
|
+ <div className={"relative h-[6.25rem] w-[100%] md:mt-[30px]"}>
|
|
|
|
+ <img src="/redpacket/isStartBg.png" alt="" className={"h-[6.25rem] w-[100%]"} />
|
|
|
|
+
|
|
|
|
+ <div
|
|
|
|
+ className={
|
|
|
|
+ "absolute top-[70%] h-[0.6944rem] w-[100%] px-[0.7rem]" +
|
|
|
|
+ " text-center text-[0.16rem] font-bold text-[#019632]" +
|
|
|
|
+ " [text-shadow:1px_1px_#fff]"
|
|
|
|
+ }
|
|
|
|
+ >
|
|
|
|
+ <p>Valor máximo de queda em</p>
|
|
|
|
+ <p>
|
|
|
|
+ dinheiro: <span className={"text-primary-color"}>R${maxCount}</span>
|
|
|
|
+ </p>
|
|
|
|
+ </div>
|
|
|
|
+ <div
|
|
|
|
+ className={
|
|
|
|
+ "absolute bottom-[10%] left-[50%] h-[65px] w-[250px] " +
|
|
|
|
+ " -translate-x-1/2"
|
|
|
|
+ }
|
|
|
|
+ onClick={(e) => {
|
|
|
|
+ e.stopPropagation();
|
|
|
|
+ onReciveRed();
|
|
|
|
+ }}
|
|
|
|
+ ></div>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
</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 PacketReceiveDetail: FC<Omit<PacketDetailsProps, "onReciveRed" | "packet">> = (props) => {
|
|
const { iconImg, onCloseHby, redAmount } = props;
|
|
const { iconImg, onCloseHby, redAmount } = props;
|
|
- const hbyInfoClass = clsx(
|
|
|
|
- `${styles.redopen} absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 bg-no-repeat bg-cover`
|
|
|
|
- );
|
|
|
|
|
|
+
|
|
const t = useTranslations("packetsPopup");
|
|
const t = useTranslations("packetsPopup");
|
|
return (
|
|
return (
|
|
- <div
|
|
|
|
- className={hbyInfoClass}
|
|
|
|
- style={{ background: `url(${iconImg})`, backgroundSize: "100% 100%" }}
|
|
|
|
- >
|
|
|
|
- <img
|
|
|
|
- src={"/hby/close.png"}
|
|
|
|
- alt={"close"}
|
|
|
|
- width={30}
|
|
|
|
- height={30}
|
|
|
|
- onClick={onCloseHby}
|
|
|
|
- className={styles.closeIcon}
|
|
|
|
- />
|
|
|
|
-
|
|
|
|
- <div className={styles.title}>{t("title")}</div>
|
|
|
|
- <div className={styles.cash}>{redAmount}</div>
|
|
|
|
- <div className={styles.tips}>
|
|
|
|
- {redAmount > 0 ? t("receiveSuccess") : t("receiveWarring")}
|
|
|
|
|
|
+ <div className={`absolute h-[100%] w-[100%]`} onClick={onCloseHby}>
|
|
|
|
+ <div className={"flex h-[100%] w-[100%]"}>
|
|
|
|
+ <div className={"relative h-[6.25rem] w-[100%] md:mt-[30px]"}>
|
|
|
|
+ <img src={iconImg} alt="" className={"h-[6.25rem] w-[100%]"} />
|
|
|
|
+ <div
|
|
|
|
+ className={
|
|
|
|
+ "absolute top-[28%] w-[100%] text-center font-black" +
|
|
|
|
+ " text-[0.4167rem] text-[#1fa62e]"
|
|
|
|
+ }
|
|
|
|
+ >
|
|
|
|
+ <p>R$</p>
|
|
|
|
+ <p className={"-mt-[0.0694rem]"}>{redAmount.toFixed(2)}</p>
|
|
|
|
+ </div>
|
|
|
|
+
|
|
|
|
+ <div
|
|
|
|
+ className={
|
|
|
|
+ "absolute bottom-[15%] h-[1.1rem] px-[0.8333rem]" + " text-[#ff9000]"
|
|
|
|
+ }
|
|
|
|
+ >
|
|
|
|
+ <div className={"text-center text-[0.1667rem] font-bold"}>
|
|
|
|
+ {redAmount > 0 ? t("receiveSuccess") : t("receiveWarring")}
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
);
|
|
@@ -177,6 +262,7 @@ enum Status {
|
|
interface Snowflake {
|
|
interface Snowflake {
|
|
x: number; // 水平位置
|
|
x: number; // 水平位置
|
|
y: number; // 垂直位置
|
|
y: number; // 垂直位置
|
|
|
|
+ opacity: number; // 透明度
|
|
scale: number; // 缩放比例
|
|
scale: number; // 缩放比例
|
|
speedX: number; // 水平移动速度
|
|
speedX: number; // 水平移动速度
|
|
speedY: number; // 垂直下落速度
|
|
speedY: number; // 垂直下落速度
|
|
@@ -208,6 +294,7 @@ const Snowfall: FC<SnowfallProps> = ({ images, snowflakeCount = 80, onClose = ()
|
|
speedY: Math.random() * 5 + 1,
|
|
speedY: Math.random() * 5 + 1,
|
|
rotate: Math.random() * 180,
|
|
rotate: Math.random() * 180,
|
|
rotateSpeed: Math.random() * 2 - 1,
|
|
rotateSpeed: Math.random() * 2 - 1,
|
|
|
|
+ opacity: Math.random() * (1.2 - 0.5) + 0.5,
|
|
image: imageElements.current[Math.floor(Math.random() * imageElements.current.length)],
|
|
image: imageElements.current[Math.floor(Math.random() * imageElements.current.length)],
|
|
}));
|
|
}));
|
|
};
|
|
};
|
|
@@ -252,7 +339,7 @@ const Snowfall: FC<SnowfallProps> = ({ images, snowflakeCount = 80, onClose = ()
|
|
}
|
|
}
|
|
|
|
|
|
ctx.save();
|
|
ctx.save();
|
|
- ctx.globalAlpha = 1;
|
|
|
|
|
|
+ ctx.globalAlpha = flake.opacity;
|
|
ctx.translate(
|
|
ctx.translate(
|
|
flake.x + (imgHeight * flake.scale) / 2,
|
|
flake.x + (imgHeight * flake.scale) / 2,
|
|
flake.y + (imgWidth * flake.scale) / 2
|
|
flake.y + (imgWidth * flake.scale) / 2
|
|
@@ -295,13 +382,13 @@ const Snowfall: FC<SnowfallProps> = ({ images, snowflakeCount = 80, onClose = ()
|
|
const RedPacketModal = forwardRef<RedPacketModalProps, Props>(function RedPacketModal(props, ref) {
|
|
const RedPacketModal = forwardRef<RedPacketModalProps, Props>(function RedPacketModal(props, ref) {
|
|
const { onAfterHandler } = props;
|
|
const { onAfterHandler } = props;
|
|
const [visible, setVisible] = useState(false);
|
|
const [visible, setVisible] = useState(false);
|
|
- const [iconLists, setIconLists] = useState<any>([]);
|
|
|
|
|
|
+ const [iconLists, setIconLists] = useState<string[]>([]);
|
|
// 初始状态为is_end, 展示活动详情页
|
|
// 初始状态为is_end, 展示活动详情页
|
|
const [status, setStatus] = useState<Status>(Status.is_end);
|
|
const [status, setStatus] = useState<Status>(Status.is_end);
|
|
- const packetCurrent = useRef<any>({});
|
|
|
|
- const packets = useRef<any[]>([]);
|
|
|
|
|
|
+ const packetCurrent = useRef<RedPacketTypes | null>(null);
|
|
|
|
+ const packets = useRef<RedPacketTypes[]>([]);
|
|
|
|
|
|
- const [redAmount, setRedAmount] = useState<any>(1);
|
|
|
|
|
|
+ const [redAmount, setRedAmount] = useState<number>(1);
|
|
const activeIndex = useRef<number>(0);
|
|
const activeIndex = useRef<number>(0);
|
|
const token = getToken();
|
|
const token = getToken();
|
|
const element = useRef<HTMLElement | null>(null);
|
|
const element = useRef<HTMLElement | null>(null);
|
|
@@ -326,10 +413,10 @@ const RedPacketModal = forwardRef<RedPacketModalProps, Props>(function RedPacket
|
|
let actList = packets.current;
|
|
let actList = packets.current;
|
|
// 是否有已开始但是没领过的红包
|
|
// 是否有已开始但是没领过的红包
|
|
let packetsFilter = actList
|
|
let packetsFilter = actList
|
|
- .filter((aItem: any) => {
|
|
|
|
|
|
+ .filter((aItem) => {
|
|
return aItem.can_receive && aItem.is_start && !aItem.is_receive;
|
|
return aItem.can_receive && aItem.is_start && !aItem.is_receive;
|
|
})
|
|
})
|
|
- .sort((pre: any, next: any) => pre.end_time - next.end_time);
|
|
|
|
|
|
+ .sort((pre, next) => pre.end_time - next.end_time);
|
|
|
|
|
|
// 有可领取红包
|
|
// 有可领取红包
|
|
if (packetsFilter.length > 0) {
|
|
if (packetsFilter.length > 0) {
|
|
@@ -347,7 +434,7 @@ const RedPacketModal = forwardRef<RedPacketModalProps, Props>(function RedPacket
|
|
} else {
|
|
} else {
|
|
// 无可领取红包
|
|
// 无可领取红包
|
|
// 展示最近可领红包详情
|
|
// 展示最近可领红包详情
|
|
- let packets = actList.sort((pre: any, next: any) => pre.end_time - next.end_time);
|
|
|
|
|
|
+ let packets = actList.sort((pre, next) => pre.end_time - next.end_time);
|
|
packetCurrent.current = packets[0];
|
|
packetCurrent.current = packets[0];
|
|
setIconLists(JSON.parse(packets[0].icon));
|
|
setIconLists(JSON.parse(packets[0].icon));
|
|
// 无可领取红包展示详情
|
|
// 无可领取红包展示详情
|
|
@@ -361,8 +448,8 @@ const RedPacketModal = forwardRef<RedPacketModalProps, Props>(function RedPacket
|
|
const onReciveRed = async () => {
|
|
const onReciveRed = async () => {
|
|
try {
|
|
try {
|
|
let paramsData = {
|
|
let paramsData = {
|
|
- id: packetCurrent.current?.id,
|
|
|
|
- index: packetCurrent.current?.index,
|
|
|
|
|
|
+ id: packetCurrent.current?.id!,
|
|
|
|
+ index: packetCurrent.current?.index!,
|
|
};
|
|
};
|
|
let receiveRedPacketInfo = await receiveRedPacketApi(paramsData);
|
|
let receiveRedPacketInfo = await receiveRedPacketApi(paramsData);
|
|
let redNum = receiveRedPacketInfo.data;
|
|
let redNum = receiveRedPacketInfo.data;
|
|
@@ -388,19 +475,24 @@ const RedPacketModal = forwardRef<RedPacketModalProps, Props>(function RedPacket
|
|
<Snowfall images={ImagesData} onClose={() => setVisible(false)} />
|
|
<Snowfall images={ImagesData} onClose={() => setVisible(false)} />
|
|
|
|
|
|
{status === Status.is_start ? (
|
|
{status === Status.is_start ? (
|
|
- <HbyInfo
|
|
|
|
|
|
+ <PacketStartDetail
|
|
onCloseHby={() => setVisible(false)}
|
|
onCloseHby={() => setVisible(false)}
|
|
onReciveRed={onReciveRed}
|
|
onReciveRed={onReciveRed}
|
|
iconImg={iconLists[1]}
|
|
iconImg={iconLists[1]}
|
|
|
|
+ packet={packetCurrent.current!}
|
|
/>
|
|
/>
|
|
) : status === Status.is_receive ? (
|
|
) : status === Status.is_receive ? (
|
|
- <HbyInfo2
|
|
|
|
|
|
+ <PacketReceiveDetail
|
|
onCloseHby={() => setVisible(false)}
|
|
onCloseHby={() => setVisible(false)}
|
|
redAmount={redAmount}
|
|
redAmount={redAmount}
|
|
iconImg={iconLists[2]}
|
|
iconImg={iconLists[2]}
|
|
/>
|
|
/>
|
|
) : (
|
|
) : (
|
|
- <HbyInfoDetail onCloseHby={() => setVisible(false)} iconImg={iconLists[0]} />
|
|
|
|
|
|
+ <PacketEndDetail
|
|
|
|
+ onCloseHby={() => setVisible(false)}
|
|
|
|
+ iconImg={iconLists[0]}
|
|
|
|
+ packet={packetCurrent.current!}
|
|
|
|
+ />
|
|
)}
|
|
)}
|
|
</Mask>
|
|
</Mask>
|
|
);
|
|
);
|