|
@@ -1,90 +1,176 @@
|
|
|
-// src/components/CouponList.tsx
|
|
|
|
|
-import React, { useState } from 'react';
|
|
|
|
|
-import { useInfiniteScroll } from "./UseInfiniteScroll";
|
|
|
|
|
|
|
+"use client";
|
|
|
|
|
|
|
|
-// 优惠券数据类型
|
|
|
|
|
|
|
+import { useState,useEffect } from "react";
|
|
|
|
|
+import { useInfiniteScroll } from "./UseInfiniteScroll";
|
|
|
|
|
+import { clientFetch } from "@/lib/restApiClient";
|
|
|
interface CouponItem {
|
|
interface CouponItem {
|
|
|
id: number;
|
|
id: number;
|
|
|
- discount: string; // 优惠金额(如 $15 OFF)
|
|
|
|
|
- desc: string; // 优惠描述
|
|
|
|
|
- valid: string; // 有效期
|
|
|
|
|
|
|
+ code: string;
|
|
|
|
|
+ cart_rule_id: number;
|
|
|
|
|
+ rule_name: string;
|
|
|
|
|
+ rule_description: string;
|
|
|
|
|
+ discount_text: string;
|
|
|
|
|
+ status: string;
|
|
|
|
|
+ expired_at: string;
|
|
|
|
|
+ starts_from: string;
|
|
|
|
|
+ ends_till: string;
|
|
|
|
|
+ created_at: string;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-const CouponList: React.FC = () => {
|
|
|
|
|
- // 初始化优惠券数据
|
|
|
|
|
|
|
+const CouponList = () => {
|
|
|
const [coupons, setCoupons] = useState<CouponItem[]>([
|
|
const [coupons, setCoupons] = useState<CouponItem[]>([
|
|
|
- { id: 1, discount: '$15 OFF', desc: 'For All Products', valid: 'Valid:6/2/2026-12/31/2026' },
|
|
|
|
|
- { id: 2, discount: '$10 OFF', desc: 'For All Products', valid: 'Valid:6/2/2026-12/31/2026' },
|
|
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 103,
|
|
|
|
|
+ code: "UFP73XEZ",
|
|
|
|
|
+ cart_rule_id: 1,
|
|
|
|
|
+ rule_name: "测试优惠券",
|
|
|
|
|
+ rule_description: "For All Products",
|
|
|
|
|
+ discount_text: "$20 OFF",
|
|
|
|
|
+ status: "available",
|
|
|
|
|
+ expired_at: "2027-03-01",
|
|
|
|
|
+ starts_from: "",
|
|
|
|
|
+ ends_till: "",
|
|
|
|
|
+ created_at: "",
|
|
|
|
|
+ },
|
|
|
]);
|
|
]);
|
|
|
- const [hasMore, setHasMore] = useState(true); // 模拟:初始有更多数据,加载2次后无更多
|
|
|
|
|
|
|
|
|
|
- // 加载更多优惠券(模拟异步请求)
|
|
|
|
|
|
|
+ const [hasMore, setHasMore] = useState(true);
|
|
|
|
|
+
|
|
|
const loadMoreCoupons = async () => {
|
|
const loadMoreCoupons = async () => {
|
|
|
- return new Promise<void>((resolve) => {
|
|
|
|
|
- setTimeout(() => {
|
|
|
|
|
- if (coupons.length >= 6) { // 模拟最多加载6条
|
|
|
|
|
- setHasMore(false);
|
|
|
|
|
- resolve();
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
- // 模拟新增数据
|
|
|
|
|
- const newCoupons = [
|
|
|
|
|
- {
|
|
|
|
|
- id: coupons.length + 1,
|
|
|
|
|
- discount: `$${5 * (coupons.length + 1)} OFF`,
|
|
|
|
|
- desc: 'For All Products',
|
|
|
|
|
- valid: 'Valid:6/2/2026-12/31/2026'
|
|
|
|
|
- },
|
|
|
|
|
- ];
|
|
|
|
|
- setCoupons(prev => [...prev, ...newCoupons]);
|
|
|
|
|
- resolve();
|
|
|
|
|
- }, 800);
|
|
|
|
|
- });
|
|
|
|
|
|
|
+ return;
|
|
|
};
|
|
};
|
|
|
|
|
+ useEffect(() => {
|
|
|
|
|
+ const load = async () => {
|
|
|
|
|
+ const resp = await clientFetch("/api/customer/coupons");
|
|
|
|
|
+ console.log("resp------------------------:",resp);
|
|
|
|
|
+ if(resp.success){
|
|
|
|
|
+ const dataObj = resp.data||[];
|
|
|
|
|
+ setCoupons((prev) => [...prev, ...dataObj]);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // console.log("完整返回:", dataObj);
|
|
|
|
|
+ };
|
|
|
|
|
|
|
|
- // 复用懒加载Hook
|
|
|
|
|
|
|
+ load();
|
|
|
|
|
+ }, []);
|
|
|
const { containerRef, isLoading } = useInfiniteScroll({
|
|
const { containerRef, isLoading } = useInfiniteScroll({
|
|
|
loadMore: loadMoreCoupons,
|
|
loadMore: loadMoreCoupons,
|
|
|
hasMore,
|
|
hasMore,
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
return (
|
|
return (
|
|
|
- <div
|
|
|
|
|
|
|
+ <div
|
|
|
ref={containerRef}
|
|
ref={containerRef}
|
|
|
- className="h-[calc(100vh-80px)] overflow-auto px-2 py-4"
|
|
|
|
|
|
|
+ className="
|
|
|
|
|
+ max-h-[420px]
|
|
|
|
|
+ mb-9
|
|
|
|
|
+ "
|
|
|
>
|
|
>
|
|
|
- {/* 优惠券列表 */}
|
|
|
|
|
- <div className="space-y-4">
|
|
|
|
|
|
|
+ <div
|
|
|
|
|
+ className="
|
|
|
|
|
+ flex
|
|
|
|
|
+ flex-col
|
|
|
|
|
+ gap-4
|
|
|
|
|
+ "
|
|
|
|
|
+ >
|
|
|
{coupons.map((item) => (
|
|
{coupons.map((item) => (
|
|
|
- <div
|
|
|
|
|
|
|
+ <div
|
|
|
key={item.id}
|
|
key={item.id}
|
|
|
- className="flex items-center bg-pink-100 rounded-lg overflow-hidden"
|
|
|
|
|
|
|
+ className="
|
|
|
|
|
+ flex
|
|
|
|
|
+ items-center
|
|
|
|
|
+ bg-[url('/image/account/couponBg.png')]
|
|
|
|
|
+ bg-cover
|
|
|
|
|
+ bg-center
|
|
|
|
|
+ w-[358px]
|
|
|
|
|
+ h-[88px]
|
|
|
|
|
+ overflow-hidden
|
|
|
|
|
+ "
|
|
|
>
|
|
>
|
|
|
- {/* 优惠信息区 */}
|
|
|
|
|
- <div className="flex-1 p-4 text-pink-600">
|
|
|
|
|
- <h3 className="text-2xl font-bold">{item.discount}</h3>
|
|
|
|
|
- <p className="text-sm mt-1">{item.desc}</p>
|
|
|
|
|
- <p className="text-xs mt-2 text-pink-500">{item.valid}</p>
|
|
|
|
|
- </div>
|
|
|
|
|
- {/* 分割线 */}
|
|
|
|
|
- <div className="w-0.5 bg-pink-300 h-16 relative">
|
|
|
|
|
- <div className="absolute top-0 left-[-4px] w-2 h-2 bg-white border border-pink-300 rounded-full"></div>
|
|
|
|
|
- <div className="absolute bottom-0 left-[-4px] w-2 h-2 bg-white border border-pink-300 rounded-full"></div>
|
|
|
|
|
|
|
+ {/* 左侧优惠信息 */}
|
|
|
|
|
+ <div
|
|
|
|
|
+ className="
|
|
|
|
|
+ flex-1
|
|
|
|
|
+ pl-6
|
|
|
|
|
+ pt-2
|
|
|
|
|
+ "
|
|
|
|
|
+ >
|
|
|
|
|
+ <div
|
|
|
|
|
+ className="
|
|
|
|
|
+ text-[40px]
|
|
|
|
|
+ leading-none
|
|
|
|
|
+ font-bold
|
|
|
|
|
+ text-[#036141]
|
|
|
|
|
+
|
|
|
|
|
+ "
|
|
|
|
|
+ >
|
|
|
|
|
+ {item.discount_text}
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <div
|
|
|
|
|
+ className="
|
|
|
|
|
+ mt-1
|
|
|
|
|
+ text-ly-12
|
|
|
|
|
+ font-normal
|
|
|
|
|
+ text-black
|
|
|
|
|
+ "
|
|
|
|
|
+ >
|
|
|
|
|
+ {item.rule_description || "For All Products"}
|
|
|
|
|
+ </div>
|
|
|
</div>
|
|
</div>
|
|
|
- {/* 使用按钮区 */}
|
|
|
|
|
- <div className="px-6 py-4 font-bold text-black">
|
|
|
|
|
- Use Now
|
|
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ {/* 右侧按钮和日期 */}
|
|
|
|
|
+ <div
|
|
|
|
|
+ className="
|
|
|
|
|
+ flex
|
|
|
|
|
+ w-[150px]
|
|
|
|
|
+ flex-col
|
|
|
|
|
+ items-center
|
|
|
|
|
+ justify-center
|
|
|
|
|
+ "
|
|
|
|
|
+ >
|
|
|
|
|
+ <button
|
|
|
|
|
+ className="
|
|
|
|
|
+ h-[32px]
|
|
|
|
|
+ w-[100px]
|
|
|
|
|
+ rounded-full
|
|
|
|
|
+ bg-[#008052]
|
|
|
|
|
+ text-ly-14
|
|
|
|
|
+ font-medium
|
|
|
|
|
+ text-white
|
|
|
|
|
+ "
|
|
|
|
|
+ >
|
|
|
|
|
+ Use Now
|
|
|
|
|
+ </button>
|
|
|
|
|
+
|
|
|
|
|
+ <div
|
|
|
|
|
+ className="
|
|
|
|
|
+ mt-2
|
|
|
|
|
+ text-ly-12
|
|
|
|
|
+ text-black
|
|
|
|
|
+ "
|
|
|
|
|
+ >
|
|
|
|
|
+ Expire In {item.expired_at}
|
|
|
|
|
+ </div>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
))}
|
|
))}
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
- {/* 加载状态/无更多提示 */}
|
|
|
|
|
- <div className="text-center mt-4 text-gray-400 text-sm">
|
|
|
|
|
- {isLoading ? 'Loading...' : hasMore ? '' : 'No More Data'}
|
|
|
|
|
- </div>
|
|
|
|
|
|
|
+ {isLoading && (
|
|
|
|
|
+ <div
|
|
|
|
|
+ className="
|
|
|
|
|
+ mt-4
|
|
|
|
|
+ text-center
|
|
|
|
|
+ text-gray-400
|
|
|
|
|
+ "
|
|
|
|
|
+ >
|
|
|
|
|
+ Loading...
|
|
|
|
|
+ </div>
|
|
|
|
|
+ )}
|
|
|
</div>
|
|
</div>
|
|
|
);
|
|
);
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
-export default CouponList;
|
|
|
|
|
|
|
+export default CouponList;
|