|
@@ -7,7 +7,7 @@ import {
|
|
|
} from "@/types/products/review";
|
|
} from "@/types/products/review";
|
|
|
import ReviewImageGalleryModal from "./ReviewImageGalleryModal";
|
|
import ReviewImageGalleryModal from "./ReviewImageGalleryModal";
|
|
|
import Image from "next/image";
|
|
import Image from "next/image";
|
|
|
-
|
|
|
|
|
|
|
+import { clientFetch } from "@/lib/restApiClient";
|
|
|
// 分页常量
|
|
// 分页常量
|
|
|
const PAGE_SIZE = 10;
|
|
const PAGE_SIZE = 10;
|
|
|
|
|
|
|
@@ -32,74 +32,83 @@ async function fetchReviewApi(
|
|
|
// total: 100,
|
|
// total: 100,
|
|
|
// };
|
|
// };
|
|
|
// 全局固定100条模拟评论总数据
|
|
// 全局固定100条模拟评论总数据
|
|
|
- const mockTotal = 100;
|
|
|
|
|
- const fullMockData: ProductReviewList = [];
|
|
|
|
|
-
|
|
|
|
|
- for (let i = 1; i <= mockTotal; i++) {
|
|
|
|
|
- // 30条带图片评论,70条无图
|
|
|
|
|
- const hasImage = i <= 30;
|
|
|
|
|
- // 带图评论随机1~3张图片
|
|
|
|
|
- const imgCount = hasImage ? Math.floor(Math.random() * 3) + 1 : 0;
|
|
|
|
|
- const attachments: string[] = [];
|
|
|
|
|
- for (let j = 1; j <= imgCount; j++) {
|
|
|
|
|
- attachments.push(
|
|
|
|
|
- `https://cdn.alipearlhair.com/media/reviewimages/cache/6/image/150x/040ec09b1e35df139433887a97daa66f/reviewimages/7O_A6W92AW3D_87N5PR8CO.png`,
|
|
|
|
|
- );
|
|
|
|
|
|
|
+ // 2. 服务端 fetch 请求我们自己的 Next.js API
|
|
|
|
|
+ let has_images =0;
|
|
|
|
|
+ if(tab =='photos'){
|
|
|
|
|
+ has_images =1 ;
|
|
|
}
|
|
}
|
|
|
|
|
+ const res = await clientFetch(`/api/shop/products/${pid}/reviews?page=${pageNum}&per_page=${PAGE_SIZE}&has_images=${has_images}&sort=${tab}`);
|
|
|
|
|
+ console.log("弹窗内res-=---------------------------------aa:",res?.data?.data);
|
|
|
|
|
+
|
|
|
|
|
+ // const mockTotal = 100;
|
|
|
|
|
+ // const fullMockData: ProductReviewList = [];
|
|
|
|
|
|
|
|
- // 随机星级1-5
|
|
|
|
|
- const randomRating = Math.floor(Math.random() * 5) + 1;
|
|
|
|
|
- // 随机标签
|
|
|
|
|
- const tagArr: ("influencer" | "verified" | "")[] = [
|
|
|
|
|
- "",
|
|
|
|
|
- "verified",
|
|
|
|
|
- "influencer",
|
|
|
|
|
- ];
|
|
|
|
|
- const randomTag = tagArr[Math.floor(Math.random() * tagArr.length)];
|
|
|
|
|
- // 随机时间,用于Newest排序
|
|
|
|
|
- const randomDayOffset = Math.floor(Math.random() * 90);
|
|
|
|
|
- const createDate = new Date();
|
|
|
|
|
- createDate.setDate(createDate.getDate() - randomDayOffset);
|
|
|
|
|
|
|
+ // for (let i = 1; i <= mockTotal; i++) {
|
|
|
|
|
+ // // 30条带图片评论,70条无图
|
|
|
|
|
+ // const hasImage = i <= 30;
|
|
|
|
|
+ // // 带图评论随机1~3张图片
|
|
|
|
|
+ // const imgCount = hasImage ? Math.floor(Math.random() * 3) + 1 : 0;
|
|
|
|
|
+ // const attachments: string[] = [];
|
|
|
|
|
+ // for (let j = 1; j <= imgCount; j++) {
|
|
|
|
|
+ // attachments.push(
|
|
|
|
|
+ // `https://cdn.alipearlhair.com/media/reviewimages/cache/6/image/150x/040ec09b1e35df139433887a97daa66f/reviewimages/7O_A6W92AW3D_87N5PR8CO.png`,
|
|
|
|
|
+ // );
|
|
|
|
|
+ // }
|
|
|
|
|
|
|
|
- fullMockData.push({
|
|
|
|
|
- __typename: "ProductReviewEdge",
|
|
|
|
|
- node: {
|
|
|
|
|
- name: `D****${i}`,
|
|
|
|
|
- title: `${16 + Math.floor(Math.random() * 3)}`,
|
|
|
|
|
- rating: randomRating,
|
|
|
|
|
- comment:
|
|
|
|
|
- "This lady is so sweetly gorgeous. I love the curl pattern, the side part makes it worth every penny spent. Hair is soft and natural, I bleached it the day she arrived.",
|
|
|
|
|
- createdAt: createDate.toISOString(),
|
|
|
|
|
- attachments,
|
|
|
|
|
- isVip: true,
|
|
|
|
|
- tag: randomTag,
|
|
|
|
|
- likeCount: 1000 + Math.floor(Math.random() * 500),
|
|
|
|
|
- },
|
|
|
|
|
- });
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ // // 随机星级1-5
|
|
|
|
|
+ // const randomRating = Math.floor(Math.random() * 5) + 1;
|
|
|
|
|
+ // // 随机标签
|
|
|
|
|
+ // const tagArr: ("influencer" | "verified" | "")[] = [
|
|
|
|
|
+ // "",
|
|
|
|
|
+ // "verified",
|
|
|
|
|
+ // "influencer",
|
|
|
|
|
+ // ];
|
|
|
|
|
+ // const randomTag = tagArr[Math.floor(Math.random() * tagArr.length)];
|
|
|
|
|
+ // // 随机时间,用于Newest排序
|
|
|
|
|
+ // const randomDayOffset = Math.floor(Math.random() * 90);
|
|
|
|
|
+ // const createDate = new Date();
|
|
|
|
|
+ // createDate.setDate(createDate.getDate() - randomDayOffset);
|
|
|
|
|
+
|
|
|
|
|
+ // fullMockData.push({
|
|
|
|
|
+ // __typename: "ProductReviewEdge",
|
|
|
|
|
+ // node: {
|
|
|
|
|
+ // name: `D****${i}`,
|
|
|
|
|
+ // title: `${16 + Math.floor(Math.random() * 3)}`,
|
|
|
|
|
+ // rating: randomRating,
|
|
|
|
|
+ // comment:
|
|
|
|
|
+ // "This lady is so sweetly gorgeous. I love the curl pattern, the side part makes it worth every penny spent. Hair is soft and natural, I bleached it the day she arrived.",
|
|
|
|
|
+ // createdAt: createDate.toISOString(),
|
|
|
|
|
+ // attachments,
|
|
|
|
|
+ // isVip: true,
|
|
|
|
|
+ // tag: randomTag,
|
|
|
|
|
+ // likeCount: 1000 + Math.floor(Math.random() * 500),
|
|
|
|
|
+ // },
|
|
|
|
|
+ // });
|
|
|
|
|
+ // }
|
|
|
// 根据tab筛选数据
|
|
// 根据tab筛选数据
|
|
|
- let filteredList = [...fullMockData];
|
|
|
|
|
- if (tab === "newest") {
|
|
|
|
|
- // 最新:创建时间倒序
|
|
|
|
|
- filteredList.sort(
|
|
|
|
|
- (a, b) =>
|
|
|
|
|
- new Date(b.node.createdAt).getTime() -
|
|
|
|
|
- new Date(a.node.createdAt).getTime(),
|
|
|
|
|
- );
|
|
|
|
|
- } else if (tab === "photos") {
|
|
|
|
|
- // 仅保留带图片评论
|
|
|
|
|
- filteredList = filteredList.filter(
|
|
|
|
|
- (item) => item.node.attachments.length > 0,
|
|
|
|
|
- );
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ let filteredList = [...res?.data?.data];
|
|
|
|
|
+ let totalReview = res?.pagination?.total;
|
|
|
|
|
+ // if (tab === "newest") {
|
|
|
|
|
+ // // 最新:创建时间倒序
|
|
|
|
|
+ // filteredList.sort(
|
|
|
|
|
+ // (a, b) =>
|
|
|
|
|
+ // new Date(b.node.createdAt).getTime() -
|
|
|
|
|
+ // new Date(a.node.createdAt).getTime(),
|
|
|
|
|
+ // );
|
|
|
|
|
+ // } else if (tab === "photos") {
|
|
|
|
|
+ // // 仅保留带图片评论
|
|
|
|
|
+ // filteredList = filteredList.filter(
|
|
|
|
|
+ // (item) => item.node.attachments.length > 0,
|
|
|
|
|
+ // );
|
|
|
|
|
+ // }
|
|
|
|
|
|
|
|
// 分页切片
|
|
// 分页切片
|
|
|
- const startIndex = (pageNum - 1) * PAGE_SIZE;
|
|
|
|
|
- const pageData = filteredList.slice(startIndex, startIndex + PAGE_SIZE);
|
|
|
|
|
|
|
+ // const startIndex = (pageNum - 1) * PAGE_SIZE;
|
|
|
|
|
+ // const pageData = filteredList.slice(startIndex, startIndex + PAGE_SIZE);
|
|
|
|
|
|
|
|
return {
|
|
return {
|
|
|
- list: pageData,
|
|
|
|
|
- total: filteredList.length,
|
|
|
|
|
|
|
+ list: filteredList,
|
|
|
|
|
+ total: totalReview,
|
|
|
};
|
|
};
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -166,30 +175,31 @@ const ReviewModal: React.FC<ReviewModalProps> = React.memo(
|
|
|
// 筛选当前Tab展示的评论
|
|
// 筛选当前Tab展示的评论
|
|
|
const filterReviewList = useCallback(() => {
|
|
const filterReviewList = useCallback(() => {
|
|
|
let list = [...fullReviewList];
|
|
let list = [...fullReviewList];
|
|
|
- if (activeTab === "newest") {
|
|
|
|
|
- list.sort(
|
|
|
|
|
- (a, b) =>
|
|
|
|
|
- new Date(b.node.createdAt).getTime() -
|
|
|
|
|
- new Date(a.node.createdAt).getTime(),
|
|
|
|
|
- );
|
|
|
|
|
- } else if (activeTab === "photos") {
|
|
|
|
|
- list = list.filter((item) => item.node.attachments.length > 0);
|
|
|
|
|
- }
|
|
|
|
|
- return list;
|
|
|
|
|
|
|
+ // if (activeTab === "newest") {
|
|
|
|
|
+ // list.sort(
|
|
|
|
|
+ // (a, b) =>
|
|
|
|
|
+ // new Date(b.node.createdAt).getTime() -
|
|
|
|
|
+ // new Date(a.node.createdAt).getTime(),
|
|
|
|
|
+ // );
|
|
|
|
|
+ // } else if (activeTab === "photos") {
|
|
|
|
|
+ // list = list.filter((item) => item.node.attachments.length > 0);
|
|
|
|
|
+ // }
|
|
|
|
|
+ // console.log("list----------------------------",list);
|
|
|
|
|
+ return list;
|
|
|
}, [activeTab, fullReviewList]);
|
|
}, [activeTab, fullReviewList]);
|
|
|
|
|
|
|
|
// 当前分页渲染数据
|
|
// 当前分页渲染数据
|
|
|
- const displayList = filterReviewList().slice(0, page * PAGE_SIZE);
|
|
|
|
|
|
|
+ const displayList = filterReviewList();//.slice(0, page * PAGE_SIZE)
|
|
|
|
|
|
|
|
// 生成图库一维图片数组
|
|
// 生成图库一维图片数组
|
|
|
const buildGalleryList = useCallback((): GalleryItem[] => {
|
|
const buildGalleryList = useCallback((): GalleryItem[] => {
|
|
|
const allGallery: GalleryItem[] = [];
|
|
const allGallery: GalleryItem[] = [];
|
|
|
filterReviewList().forEach((edge, reviewIdx) => {
|
|
filterReviewList().forEach((edge, reviewIdx) => {
|
|
|
- edge.node.attachments.forEach((imgUrl) => {
|
|
|
|
|
|
|
+ edge.attachments.forEach((imgUrl) => {
|
|
|
allGallery.push({
|
|
allGallery.push({
|
|
|
reviewIndex: reviewIdx,
|
|
reviewIndex: reviewIdx,
|
|
|
imageUrl: imgUrl,
|
|
imageUrl: imgUrl,
|
|
|
- review: edge.node,
|
|
|
|
|
|
|
+ review: edge,
|
|
|
});
|
|
});
|
|
|
});
|
|
});
|
|
|
});
|
|
});
|
|
@@ -222,11 +232,10 @@ const ReviewModal: React.FC<ReviewModalProps> = React.memo(
|
|
|
|
|
|
|
|
const galleryAll = buildGalleryList();
|
|
const galleryAll = buildGalleryList();
|
|
|
const targetReview = filterReviewList()[clickReviewIndex];
|
|
const targetReview = filterReviewList()[clickReviewIndex];
|
|
|
- const targetImg = targetReview.node.attachments[clickImgIndex];
|
|
|
|
|
|
|
+ const targetImg = targetReview.attachments[clickImgIndex];
|
|
|
const targetSlide = galleryAll.findIndex(
|
|
const targetSlide = galleryAll.findIndex(
|
|
|
(g) => g.reviewIndex === clickReviewIndex && g.imageUrl === targetImg,
|
|
(g) => g.reviewIndex === clickReviewIndex && g.imageUrl === targetImg,
|
|
|
);
|
|
);
|
|
|
- debugger;
|
|
|
|
|
setGalleryData({ galleryList: galleryAll, initialSlide: targetSlide });
|
|
setGalleryData({ galleryList: galleryAll, initialSlide: targetSlide });
|
|
|
setGalleryOpen(true);
|
|
setGalleryOpen(true);
|
|
|
};
|
|
};
|
|
@@ -291,8 +300,8 @@ const ReviewModal: React.FC<ReviewModalProps> = React.memo(
|
|
|
) : displayList.length === 0 ? (
|
|
) : displayList.length === 0 ? (
|
|
|
<p className="text-center text-gray-500 py-10">No reviews</p>
|
|
<p className="text-center text-gray-500 py-10">No reviews</p>
|
|
|
) : (
|
|
) : (
|
|
|
- displayList.map((edge, reviewIdx) => {
|
|
|
|
|
- const item = edge.node;
|
|
|
|
|
|
|
+ displayList.map((item, reviewIdx) => {
|
|
|
|
|
+ // const item = edge.node;
|
|
|
return (
|
|
return (
|
|
|
<div
|
|
<div
|
|
|
key={reviewIdx}
|
|
key={reviewIdx}
|