|
@@ -0,0 +1,176 @@
|
|
|
+"use client";
|
|
|
+import { PromotionRep } from "@/api/home";
|
|
|
+import Box from "@/components/Box";
|
|
|
+import { server } from "@/utils/client";
|
|
|
+import { Mask } from "antd-mobile";
|
|
|
+import { FC, MouseEvent, useEffect, useState } from "react";
|
|
|
+import dialogManage from "../manager";
|
|
|
+
|
|
|
+const getPromotions = async () => {
|
|
|
+ return server
|
|
|
+ .request<PromotionRep[], { summery: { showType: 1 | 2 } }>({
|
|
|
+ url: "/v1/api/front/pop_list",
|
|
|
+ method: "POST",
|
|
|
+ })
|
|
|
+ .then((res) => {
|
|
|
+ if (res.code === 200) return res;
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+import dayjs from "dayjs";
|
|
|
+import { Pagination } from "swiper/modules";
|
|
|
+import { Swiper, SwiperSlide } from "swiper/react";
|
|
|
+interface Props {
|
|
|
+ data?: PromotionRep[];
|
|
|
+ type?: 1 | 2; // 每天只弹一次 / 每次登录都弹
|
|
|
+}
|
|
|
+
|
|
|
+const HomePromotion: FC<Props> = () => {
|
|
|
+ const [data, setData] = useState<PromotionRep[]>([]);
|
|
|
+ const [type, setType] = useState<1 | 2>(1);
|
|
|
+ const [visible, setVisible] = useState(false);
|
|
|
+ const [flag, setFlag] = useState(false);
|
|
|
+ const [actIdx, setActIdx] = useState(0);
|
|
|
+ const keyName = "HomePromotion";
|
|
|
+ // 如果 type 为 1 && 有isNow为true 表示已经弹出,
|
|
|
+ const shouldShowPromotion = () => {
|
|
|
+ const isClosePromotion = sessionStorage.getItem("isClosePromotion");
|
|
|
+ // 如果不等于1而数据又是时间,清除
|
|
|
+ if (type !== 1 && dayjs().isSame(isClosePromotion, "days")) {
|
|
|
+ sessionStorage.removeItem("isClosePromotion");
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ if (type === 1) {
|
|
|
+ return !dayjs().isSame(isClosePromotion, "days");
|
|
|
+ } else if (type === 2) {
|
|
|
+ return !isClosePromotion;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ };
|
|
|
+ const dialogHandle = {
|
|
|
+ key: keyName,
|
|
|
+ show: () => {
|
|
|
+ let flag = shouldShowPromotion();
|
|
|
+ console.log("flag", flag);
|
|
|
+ if (flag) {
|
|
|
+ setVisible(true);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ return "close";
|
|
|
+ },
|
|
|
+ };
|
|
|
+ useEffect(() => {
|
|
|
+ dialogManage.registerDialog(dialogHandle);
|
|
|
+ // eslint-disable-next-line react-hooks/exhaustive-deps
|
|
|
+ }, [type]);
|
|
|
+ useEffect(() => {
|
|
|
+ getData();
|
|
|
+ // eslint-disable-next-line react-hooks/exhaustive-deps
|
|
|
+ }, []);
|
|
|
+
|
|
|
+ useEffect(() => {
|
|
|
+ if (data.length === 0 && visible) {
|
|
|
+ dialogManage.hideDialog(keyName);
|
|
|
+ }
|
|
|
+ }, [data, visible]);
|
|
|
+
|
|
|
+ const getData = async () => {
|
|
|
+ const res = await getPromotions();
|
|
|
+ if (res?.code === 200) {
|
|
|
+ setData(res.data);
|
|
|
+ setType(res.summery.showType);
|
|
|
+ }
|
|
|
+ let flag = shouldShowPromotion();
|
|
|
+ setFlag(flag);
|
|
|
+ };
|
|
|
+
|
|
|
+ const closeHandler = (e: MouseEvent<HTMLElement>) => {
|
|
|
+ e.stopPropagation();
|
|
|
+ setData((idata) => {
|
|
|
+ idata.splice(actIdx, 1);
|
|
|
+ return [...idata];
|
|
|
+ });
|
|
|
+
|
|
|
+ if (type === 1) {
|
|
|
+ sessionStorage.setItem("isClosePromotion", dayjs().format("YYYY-MM-DD"));
|
|
|
+ }
|
|
|
+
|
|
|
+ if (type === 2) {
|
|
|
+ sessionStorage.setItem("isClosePromotion", "true");
|
|
|
+ }
|
|
|
+ };
|
|
|
+ if (data && data.length === 0) return null;
|
|
|
+
|
|
|
+ return (
|
|
|
+ <div>
|
|
|
+ <Mask visible={visible} onMaskClick={(e) => closeHandler(e)} opacity={"thick"}>
|
|
|
+ <div
|
|
|
+ className={
|
|
|
+ "promotion-swiper absolute left-1/2 top-[18%] max-w-[3.139rem]" +
|
|
|
+ " -translate-x-1/2"
|
|
|
+ }
|
|
|
+ >
|
|
|
+ <Swiper
|
|
|
+ loop
|
|
|
+ pagination={{ clickable: true }}
|
|
|
+ spaceBetween={10}
|
|
|
+ scrollbar={{ draggable: true }}
|
|
|
+ modules={[Pagination]}
|
|
|
+ slidesPerView={1}
|
|
|
+ grabCursor={true}
|
|
|
+ navigation={true}
|
|
|
+ className={"min-h-[3.8rem]"}
|
|
|
+ onSlideChange={(swiper) => {
|
|
|
+ setActIdx(swiper.activeIndex);
|
|
|
+ // console.log('当前 active 的 slide 索引:', swiper.activeIndex);
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ {data?.map((promotion, index) => (
|
|
|
+ <SwiperSlide key={index}>
|
|
|
+ <Box
|
|
|
+ action={promotion.action_type}
|
|
|
+ actionData={promotion.action_params}
|
|
|
+ >
|
|
|
+ <div
|
|
|
+ className={
|
|
|
+ "relative h-[3.4722rem] w-[100%] rounded-[0.1389rem]"
|
|
|
+ }
|
|
|
+ >
|
|
|
+ <div
|
|
|
+ style={{
|
|
|
+ clipPath: "polygon(26% 0, 100% 69%, 100% 0)",
|
|
|
+ background: "rgba(0,0,0,0.5)",
|
|
|
+ }}
|
|
|
+ className={
|
|
|
+ "absolute -top-[0.2px] right-0 z-[10]" +
|
|
|
+ " h-[0.5556rem] w-[0.5556rem]" +
|
|
|
+ " rounded-tr-[0.1389rem]"
|
|
|
+ }
|
|
|
+ onClick={(e) => closeHandler(e)}
|
|
|
+ >
|
|
|
+ <i
|
|
|
+ className={
|
|
|
+ "iconfont icon-guanbi absolute right-[16%]" +
|
|
|
+ " top-[5%] text-[0.1111rem]"
|
|
|
+ }
|
|
|
+ ></i>
|
|
|
+ </div>
|
|
|
+ <img
|
|
|
+ width={400}
|
|
|
+ height={400}
|
|
|
+ className={"h-[100%] w-[100%] rounded-[0.1389rem]"}
|
|
|
+ src={promotion.content.image!}
|
|
|
+ alt={promotion.content.title!}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </Box>
|
|
|
+ </SwiperSlide>
|
|
|
+ ))}
|
|
|
+ </Swiper>
|
|
|
+ </div>
|
|
|
+ </Mask>
|
|
|
+ </div>
|
|
|
+ );
|
|
|
+};
|
|
|
+
|
|
|
+export default HomePromotion;
|