|
|
@@ -1,4 +1,4 @@
|
|
|
-import { Text, View } from "@tarojs/components";
|
|
|
+import { Text, View, ScrollView } from "@tarojs/components";
|
|
|
import { Heart, HeartFill, Plus } from "@nutui/icons-react-taro";
|
|
|
import { Message } from "@nutui/icons-react-taro";
|
|
|
import {
|
|
|
@@ -7,10 +7,11 @@ import {
|
|
|
Image,
|
|
|
ImagePreview,
|
|
|
Toast,
|
|
|
+ PullToRefresh,
|
|
|
} from "@nutui/nutui-react-taro";
|
|
|
import MoreButton from "../fllower-button";
|
|
|
import { circlePostListApi } from "../../api/post";
|
|
|
-import { useEffect, useState } from "react";
|
|
|
+import { useEffect, useState, useCallback } from "react";
|
|
|
import { strSlice } from "../../utils/index";
|
|
|
import { followApi, interactionApi, unfollowApi } from "../../api/interaction";
|
|
|
import { Dialog } from "@nutui/nutui-react-taro";
|
|
|
@@ -21,14 +22,69 @@ const PostList = () => {
|
|
|
const [showPreview, setShowPreview] = useState(false);
|
|
|
const [init, setInit] = useState(0);
|
|
|
const [mediaUrl, setMediaUrl] = useState<any[]>([]);
|
|
|
- const getPostList = () => {
|
|
|
- circlePostListApi({ circleId: 1 }).then((res: any) => {
|
|
|
- if (res.code === 200) {
|
|
|
- setPostList(res.data.list);
|
|
|
- console.log(res.data.list);
|
|
|
+
|
|
|
+ // 分页相关状态
|
|
|
+ const [currentPage, setCurrentPage] = useState(1);
|
|
|
+ const [hasMore, setHasMore] = useState(true);
|
|
|
+ const [loading, setLoading] = useState(false);
|
|
|
+ const pageSize = 10;
|
|
|
+
|
|
|
+ const getPostList = useCallback(
|
|
|
+ async (page = 1, isRefresh = false) => {
|
|
|
+ setLoading(true);
|
|
|
+ try {
|
|
|
+ const res: any = await circlePostListApi({
|
|
|
+ circleId: 1,
|
|
|
+ page,
|
|
|
+ pageSize: pageSize,
|
|
|
+ });
|
|
|
+
|
|
|
+ if (res.code === 200) {
|
|
|
+ const newList = res.data.list || [];
|
|
|
+ console.log("API Response:", {
|
|
|
+ page,
|
|
|
+ newListLength: newList.length,
|
|
|
+ hasMore: res.data.has_more,
|
|
|
+ isRefresh,
|
|
|
+ });
|
|
|
+
|
|
|
+ if (isRefresh || page === 1) {
|
|
|
+ setPostList(newList);
|
|
|
+ } else {
|
|
|
+ setPostList((prev) => [...prev, ...newList]);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 判断是否还有更多数据
|
|
|
+ setHasMore(res.data.has_more);
|
|
|
+ setCurrentPage(page);
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error("获取帖子列表失败:", error);
|
|
|
+ Toast.show("load_error", {
|
|
|
+ content: "加载失败,请重试",
|
|
|
+ duration: 2,
|
|
|
+ });
|
|
|
+ } finally {
|
|
|
+ setLoading(false);
|
|
|
}
|
|
|
- });
|
|
|
- };
|
|
|
+ },
|
|
|
+ [pageSize]
|
|
|
+ );
|
|
|
+
|
|
|
+ // 下拉刷新
|
|
|
+ const handleRefresh = useCallback(async () => {
|
|
|
+ await getPostList(1, true);
|
|
|
+ }, [getPostList]);
|
|
|
+
|
|
|
+ // 上拉加载更多
|
|
|
+ const handleLoadMore = useCallback(async () => {
|
|
|
+ console.log("handleLoadMore called", { hasMore, currentPage, loading });
|
|
|
+ if (hasMore && !loading) {
|
|
|
+ console.log("Loading next page:", currentPage + 1);
|
|
|
+ await getPostList(currentPage + 1, false);
|
|
|
+ }
|
|
|
+ }, [hasMore, currentPage, getPostList, loading]);
|
|
|
+
|
|
|
const handleMoreClick = (postIndex: number) => {
|
|
|
const data = [...postList];
|
|
|
data.splice(postIndex, 1);
|
|
|
@@ -100,151 +156,186 @@ const PostList = () => {
|
|
|
}
|
|
|
};
|
|
|
useEffect(() => {
|
|
|
- getPostList();
|
|
|
+ getPostList(1, true);
|
|
|
}, []);
|
|
|
+
|
|
|
return (
|
|
|
- <View className="post-list bg-[#f8f8f8]">
|
|
|
- {postList.map((item: any, index: number) => {
|
|
|
- return (
|
|
|
- <View
|
|
|
- key={item.id}
|
|
|
- className="post-list-item bg-[#fff] p-[10px] mb-[10px]"
|
|
|
- >
|
|
|
- <View className="flex items-center justify-between">
|
|
|
- <View className="flex items-center">
|
|
|
- <View
|
|
|
- className="w-[40px] h-[40px] rounded-[50%] bg-[#000] overflow-hidden bg-cover bg-center"
|
|
|
- style={{
|
|
|
- backgroundImage: item.user.avatar_url
|
|
|
- ? `url('${item.user.avatar_url}')`
|
|
|
- : "none",
|
|
|
- }}
|
|
|
- ></View>
|
|
|
- <View className="ml-[5px]">
|
|
|
- <View className="text-[14px] font-[800] text-[#9c9dee]">
|
|
|
- {item.user.nickname || item.user.username || "微信用户"}
|
|
|
+ <ScrollView
|
|
|
+ scrollY
|
|
|
+ className="post-list-scroll"
|
|
|
+ style={{ height: "100%" }}
|
|
|
+ onScrollToLower={handleLoadMore}
|
|
|
+ lowerThreshold={100}
|
|
|
+ >
|
|
|
+ <PullToRefresh onRefresh={handleRefresh}>
|
|
|
+ <View className="post-list bg-[#f8f8f8]">
|
|
|
+ {postList.map((item: any, index: number) => {
|
|
|
+ return (
|
|
|
+ <View
|
|
|
+ key={item.id}
|
|
|
+ className="post-list-item bg-[#fff] p-[10px] mb-[10px]"
|
|
|
+ >
|
|
|
+ <View className="flex items-center justify-between">
|
|
|
+ <View className="flex items-center">
|
|
|
+ <View
|
|
|
+ className="w-[40px] h-[40px] rounded-[50%] bg-[#000] overflow-hidden bg-cover bg-center"
|
|
|
+ style={{
|
|
|
+ backgroundImage: item.user.avatar_url
|
|
|
+ ? `url('${item.user.avatar_url}')`
|
|
|
+ : "none",
|
|
|
+ }}
|
|
|
+ ></View>
|
|
|
+ <View className="ml-[5px]">
|
|
|
+ <View className="text-[14px] font-[800] text-[#9c9dee]">
|
|
|
+ {item.user.nickname || item.user.username || "微信用户"}
|
|
|
+ </View>
|
|
|
+ {item.user.is_official ? (
|
|
|
+ <View className="text-[12px] text-[#949494]">
|
|
|
+ 《心动女友》官方账号
|
|
|
+ </View>
|
|
|
+ ) : (
|
|
|
+ <></>
|
|
|
+ )}
|
|
|
+ </View>
|
|
|
</View>
|
|
|
- {item.user.is_official ? (
|
|
|
- <View className="text-[12px] text-[#949494]">
|
|
|
- 《心动女友》官方账号
|
|
|
+ <View className="flex items-center">
|
|
|
+ <View
|
|
|
+ className="flex items-center justify-center mr-[12px] text-[12px] bg-[#f8f8f8] text-[#949494] rounded-[20px] h-[25px] w-[60px] text-center"
|
|
|
+ onClick={(e) => {
|
|
|
+ e.stopPropagation();
|
|
|
+ handleFollowClick(item.user_id, item.is_followed);
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ {item.is_followed ? <></> : <Plus color="#1874d0" />}
|
|
|
+ <Text>{item.is_followed ? "已关注" : "关注"}</Text>
|
|
|
</View>
|
|
|
- ) : (
|
|
|
- <></>
|
|
|
- )}
|
|
|
+ {item.user.is_official ? (
|
|
|
+ <></>
|
|
|
+ ) : (
|
|
|
+ <MoreButton
|
|
|
+ postIndex={index}
|
|
|
+ followeeId={item.user_id}
|
|
|
+ postId={item.id}
|
|
|
+ postItem={item}
|
|
|
+ onClick={handleMoreClick}
|
|
|
+ />
|
|
|
+ )}
|
|
|
+ </View>
|
|
|
</View>
|
|
|
- </View>
|
|
|
- <View className="flex items-center">
|
|
|
<View
|
|
|
- className="flex items-center justify-center mr-[12px] text-[12px] bg-[#f8f8f8] text-[#949494] rounded-[20px] h-[25px] w-[60px] text-center"
|
|
|
- onClick={(e) => {
|
|
|
- e.stopPropagation();
|
|
|
- handleFollowClick(item.user_id, item.is_followed);
|
|
|
- }}
|
|
|
- >
|
|
|
- {item.is_followed ? <></> : <Plus color="#1874d0" />}
|
|
|
- <Text>{item.is_followed ? "已关注" : "关注"}</Text>
|
|
|
- </View>
|
|
|
- {item.user.is_official ? (
|
|
|
- <></>
|
|
|
- ) : (
|
|
|
- <MoreButton
|
|
|
- postIndex={index}
|
|
|
- followeeId={item.user_id}
|
|
|
- postId={item.id}
|
|
|
- postItem={item}
|
|
|
- onClick={handleMoreClick}
|
|
|
- />
|
|
|
- )}
|
|
|
- </View>
|
|
|
- </View>
|
|
|
- <View
|
|
|
- onClick={() =>
|
|
|
- navigateTo({ url: `/pages/detail/index?id=${item.id}` })
|
|
|
- }
|
|
|
- >
|
|
|
- <View className="text-[14px] text-[#333] pt-[20px]">
|
|
|
- {strSlice(item.content, 100)}
|
|
|
- {item.content.length > 100 && (
|
|
|
- <Text className="text-[#1874d0]">全文</Text>
|
|
|
- )}
|
|
|
- </View>
|
|
|
- <View className="mt-[10px]">
|
|
|
- <Grid
|
|
|
- columns={item.media_url.length < 3 ? 2 : 3} // 这里,如果图片小于3张,则columns为2,如果图片大于等于3张,则columns为3
|
|
|
- gap={7}
|
|
|
- style={
|
|
|
- {
|
|
|
- "--nutui-grid-item-content-padding": "0px",
|
|
|
- "--nutui-grid-item-content-margin": "0px",
|
|
|
- "--nutui-grid-border-color": "transparent",
|
|
|
- } as any
|
|
|
+ onClick={() =>
|
|
|
+ navigateTo({ url: `/pages/detail/index?id=${item.id}` })
|
|
|
}
|
|
|
>
|
|
|
- {item.media_url.map((ite: any, index: number) => {
|
|
|
- return (
|
|
|
- <GridItem>
|
|
|
- <Image
|
|
|
- width="100%"
|
|
|
- height="100px"
|
|
|
- src={ite.src}
|
|
|
- mode="widthFix"
|
|
|
- onClick={(e) => {
|
|
|
- e.preventDefault();
|
|
|
- e.stopPropagation();
|
|
|
- setMediaUrl(item.media_url);
|
|
|
- setInit(index + 1);
|
|
|
-
|
|
|
- setShowPreview(true);
|
|
|
- }}
|
|
|
- />
|
|
|
- </GridItem>
|
|
|
- );
|
|
|
- })}
|
|
|
- </Grid>
|
|
|
- </View>
|
|
|
- <View className="mt-[10px] pl-[20px] pr-[20px] flex items-center justify-between">
|
|
|
- <View className="flex items-center">
|
|
|
- <Message size={16} color="#949494" />
|
|
|
- <Text className="ml-[5px] text-[16px] text-[#949494]">
|
|
|
- {item.comment_count}
|
|
|
- </Text>
|
|
|
- </View>
|
|
|
- <View
|
|
|
- className="flex items-center"
|
|
|
- onClick={(e) => {
|
|
|
- e.stopPropagation();
|
|
|
- handleInteraction(
|
|
|
- item.id,
|
|
|
- item.interaction_type === "praise"
|
|
|
- ? "dispraise"
|
|
|
- : "praise"
|
|
|
- );
|
|
|
- }}
|
|
|
- >
|
|
|
- {item.interaction_type === "praise" ? (
|
|
|
- <HeartFill size={16} color="#ec4342" />
|
|
|
- ) : (
|
|
|
- <Heart size={16} color="#949494" />
|
|
|
- )}
|
|
|
- <Text className="ml-[5px] text-[16px] text-[#949494]">
|
|
|
- {item.like_count}
|
|
|
- </Text>
|
|
|
+ <View className="text-[14px] text-[#333] pt-[20px]">
|
|
|
+ {strSlice(item.content, 100)}
|
|
|
+ {item.content.length > 100 && (
|
|
|
+ <Text className="text-[#1874d0]">全文</Text>
|
|
|
+ )}
|
|
|
+ </View>
|
|
|
+ <View className="mt-[10px]">
|
|
|
+ <Grid
|
|
|
+ columns={item.media_url.length < 3 ? 2 : 3} // 这里,如果图片小于3张,则columns为2,如果图片大于等于3张,则columns为3
|
|
|
+ gap={7}
|
|
|
+ style={
|
|
|
+ {
|
|
|
+ "--nutui-grid-item-content-padding": "0px",
|
|
|
+ "--nutui-grid-item-content-margin": "0px",
|
|
|
+ "--nutui-grid-border-color": "transparent",
|
|
|
+ } as any
|
|
|
+ }
|
|
|
+ >
|
|
|
+ {item.media_url.map((ite: any, index: number) => {
|
|
|
+ return (
|
|
|
+ <GridItem>
|
|
|
+ <Image
|
|
|
+ width="100%"
|
|
|
+ height="100px"
|
|
|
+ src={ite.src}
|
|
|
+ mode="widthFix"
|
|
|
+ onClick={(e) => {
|
|
|
+ e.preventDefault();
|
|
|
+ e.stopPropagation();
|
|
|
+ setMediaUrl(item.media_url);
|
|
|
+ setInit(index + 1);
|
|
|
+
|
|
|
+ setShowPreview(true);
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ </GridItem>
|
|
|
+ );
|
|
|
+ })}
|
|
|
+ </Grid>
|
|
|
+ </View>
|
|
|
+ <View className="mt-[10px] pl-[20px] pr-[20px] flex items-center justify-between">
|
|
|
+ <View className="flex items-center">
|
|
|
+ <Message size={16} color="#949494" />
|
|
|
+ <Text className="ml-[5px] text-[16px] text-[#949494]">
|
|
|
+ {item.comment_count}
|
|
|
+ </Text>
|
|
|
+ </View>
|
|
|
+ <View
|
|
|
+ className="flex items-center"
|
|
|
+ onClick={(e) => {
|
|
|
+ e.stopPropagation();
|
|
|
+ handleInteraction(
|
|
|
+ item.id,
|
|
|
+ item.interaction_type === "praise"
|
|
|
+ ? "dispraise"
|
|
|
+ : "praise"
|
|
|
+ );
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ {item.interaction_type === "praise" ? (
|
|
|
+ <HeartFill size={16} color="#ec4342" />
|
|
|
+ ) : (
|
|
|
+ <Heart size={16} color="#949494" />
|
|
|
+ )}
|
|
|
+ <Text className="ml-[5px] text-[16px] text-[#949494]">
|
|
|
+ {item.like_count}
|
|
|
+ </Text>
|
|
|
+ </View>
|
|
|
+ </View>
|
|
|
</View>
|
|
|
</View>
|
|
|
+ );
|
|
|
+ })}
|
|
|
+
|
|
|
+ {/* 空状态提示 */}
|
|
|
+ {postList.length === 0 && !loading && (
|
|
|
+ <View className="flex flex-col items-center justify-center py-[50px]">
|
|
|
+ <Text className="text-[#999] text-[14px]">暂无帖子</Text>
|
|
|
</View>
|
|
|
- </View>
|
|
|
- );
|
|
|
- })}
|
|
|
- <ImagePreview
|
|
|
- images={mediaUrl}
|
|
|
- visible={showPreview}
|
|
|
- defaultValue={init}
|
|
|
- onClose={() => setShowPreview(false)}
|
|
|
- indicator
|
|
|
- />
|
|
|
- <Toast id="follow_success" />
|
|
|
- <Dialog id="followed_dialog" />
|
|
|
- </View>
|
|
|
+ )}
|
|
|
+
|
|
|
+ {/* 加载更多提示 */}
|
|
|
+ {hasMore && (
|
|
|
+ <View className="p-[20px] text-center">
|
|
|
+ <Text className="text-[14px] text-[#999]">
|
|
|
+ {loading ? "加载中..." : "上拉加载更多"}
|
|
|
+ </Text>
|
|
|
+ </View>
|
|
|
+ )}
|
|
|
+
|
|
|
+ {!hasMore && postList.length > 0 && (
|
|
|
+ <View className="p-[20px] text-center">
|
|
|
+ <Text className="text-[14px] text-[#999]">没有更多了</Text>
|
|
|
+ </View>
|
|
|
+ )}
|
|
|
+
|
|
|
+ <ImagePreview
|
|
|
+ images={mediaUrl}
|
|
|
+ visible={showPreview}
|
|
|
+ defaultValue={init}
|
|
|
+ onClose={() => setShowPreview(false)}
|
|
|
+ indicator
|
|
|
+ />
|
|
|
+ <Toast id="follow_success" />
|
|
|
+ <Toast id="load_error" />
|
|
|
+ <Dialog id="followed_dialog" />
|
|
|
+ </View>
|
|
|
+ </PullToRefresh>
|
|
|
+ </ScrollView>
|
|
|
);
|
|
|
};
|
|
|
|