|
|
@@ -0,0 +1,372 @@
|
|
|
+import { ScrollView, Text, View } from "@tarojs/components";
|
|
|
+import {
|
|
|
+ Heart,
|
|
|
+ HeartFill,
|
|
|
+ Message,
|
|
|
+ Notice,
|
|
|
+ Plus,
|
|
|
+} from "@nutui/icons-react-taro";
|
|
|
+import {
|
|
|
+ Badge,
|
|
|
+ Grid,
|
|
|
+ GridItem,
|
|
|
+ Image,
|
|
|
+ ImagePreview,
|
|
|
+ Tabs,
|
|
|
+} from "@nutui/nutui-react-taro";
|
|
|
+import { navigateTo, getSystemInfoSync } from "@tarojs/taro";
|
|
|
+import "./index.scss";
|
|
|
+import { useState, useEffect, useCallback } from "react";
|
|
|
+import { strSlice } from "../../utils";
|
|
|
+import { interactionApi } from "../../api/interaction";
|
|
|
+import { getUserPostListApi } from "../../api/post";
|
|
|
+import { getUserInfoApi } from "../../api/user";
|
|
|
+const Self = () => {
|
|
|
+ const [tab1value, setTab1value] = useState<string | number>("0");
|
|
|
+ const [scrollHeight, setScrollHeight] = useState<number>(0);
|
|
|
+ const [postList, setPostList] = useState<any[]>([]);
|
|
|
+ const [loading, setLoading] = useState<boolean>(false);
|
|
|
+ const [refreshing, setRefreshing] = useState<boolean>(false);
|
|
|
+ const [loadingMore, setLoadingMore] = useState<boolean>(false);
|
|
|
+ const [hasMore, setHasMore] = useState<boolean>(true);
|
|
|
+ const [error, setError] = useState<string>("");
|
|
|
+ const [mediaUrl, setMediaUrl] = useState<any[]>([]);
|
|
|
+ const [showPreview, setShowPreview] = useState(false);
|
|
|
+ const [init, setInit] = useState(0);
|
|
|
+ const [userInfo, setUserInfo] = useState<any>({});
|
|
|
+ const [pageConfig, setPageConfig] = useState({
|
|
|
+ page: 1,
|
|
|
+ page_size: 10,
|
|
|
+ count: 0,
|
|
|
+ has_more: false,
|
|
|
+ });
|
|
|
+
|
|
|
+ // 计算滚动区域高度
|
|
|
+ useEffect(() => {
|
|
|
+ const systemInfo = getSystemInfoSync();
|
|
|
+ // 屏幕高度 - 状态栏 - 导航栏 - 用户信息区域 - 标签栏
|
|
|
+ const height = systemInfo.windowHeight - 44 - 50 - 100;
|
|
|
+ setScrollHeight(height);
|
|
|
+ }, []);
|
|
|
+
|
|
|
+ // 点赞
|
|
|
+ const handleInteraction = async (postId: number, type) => {
|
|
|
+ const res: any = await interactionApi({
|
|
|
+ target_type: "post",
|
|
|
+ target_id: postId,
|
|
|
+ interaction_type: type,
|
|
|
+ });
|
|
|
+ if (res.code === 200) {
|
|
|
+ const data = [...postList];
|
|
|
+ data.forEach((item: any) => {
|
|
|
+ if (item.id === postId) {
|
|
|
+ item.interaction_type = type;
|
|
|
+ item.like_count =
|
|
|
+ type === "praise" ? item.like_count + 1 : item.like_count - 1;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ setPostList(data);
|
|
|
+ }
|
|
|
+ };
|
|
|
+ // 获取用户信息
|
|
|
+ const getUserInfo = async () => {
|
|
|
+ const res: any = await getUserInfoApi();
|
|
|
+ if (res.code === 200) {
|
|
|
+ setUserInfo(res.data);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ // 获取帖子列表
|
|
|
+ const getPostList = async (
|
|
|
+ isRefresh: boolean = false,
|
|
|
+ isLoadMore: boolean = false
|
|
|
+ ) => {
|
|
|
+ try {
|
|
|
+ // 设置对应的加载状态
|
|
|
+ if (isRefresh) {
|
|
|
+ setRefreshing(true);
|
|
|
+ } else if (isLoadMore) {
|
|
|
+ setLoadingMore(true);
|
|
|
+ } else {
|
|
|
+ setLoading(true);
|
|
|
+ }
|
|
|
+
|
|
|
+ setError(""); // 清除错误信息
|
|
|
+
|
|
|
+ const currentPage = isRefresh ? 1 : pageConfig.page;
|
|
|
+ const requestParams = {
|
|
|
+ ...pageConfig,
|
|
|
+ page: currentPage,
|
|
|
+ };
|
|
|
+
|
|
|
+ const res: any = await getUserPostListApi(null, requestParams);
|
|
|
+
|
|
|
+ if (res.code === 200) {
|
|
|
+ const newData = res.data.list || [];
|
|
|
+
|
|
|
+ setPageConfig({
|
|
|
+ page: res.data.page,
|
|
|
+ page_size: res.data.page_size,
|
|
|
+ count: res.data.count,
|
|
|
+ has_more: res.data.has_more,
|
|
|
+ });
|
|
|
+
|
|
|
+ // 根据操作类型更新帖子列表
|
|
|
+ if (isRefresh || currentPage === 1) {
|
|
|
+ setPostList(newData);
|
|
|
+ } else if (isLoadMore) {
|
|
|
+ setPostList((prev) => [...prev, ...newData]);
|
|
|
+ } else {
|
|
|
+ setPostList(newData);
|
|
|
+ }
|
|
|
+
|
|
|
+ setHasMore(res.data.has_more);
|
|
|
+ } else {
|
|
|
+ setError(res.message || "获取帖子列表失败");
|
|
|
+ }
|
|
|
+ } catch (err: any) {
|
|
|
+ console.error("获取帖子列表失败:", err);
|
|
|
+ setError(err.message || "网络错误,请稍后重试");
|
|
|
+ } finally {
|
|
|
+ // 清除所有加载状态
|
|
|
+ setLoading(false);
|
|
|
+ setRefreshing(false);
|
|
|
+ setLoadingMore(false);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ // 初始加载
|
|
|
+ useEffect(() => {
|
|
|
+ getPostList();
|
|
|
+ getUserInfo();
|
|
|
+ }, []);
|
|
|
+
|
|
|
+ // 加载更多
|
|
|
+ const loadMore = useCallback(() => {
|
|
|
+ if (hasMore && !loadingMore && !loading && !refreshing) {
|
|
|
+ getPostList(false, true);
|
|
|
+ }
|
|
|
+ }, [hasMore, loadingMore, loading, refreshing]);
|
|
|
+
|
|
|
+ // 下拉刷新
|
|
|
+ const onRefresh = useCallback(() => {
|
|
|
+ getPostList(true, false);
|
|
|
+ }, []);
|
|
|
+ return (
|
|
|
+ <View className="min-h-screen bg-[#f7f8fa]">
|
|
|
+ <View className="p-[10px] bg-[#fff]">
|
|
|
+ <View className="flex items-center justify-between">
|
|
|
+ <View className="flex items-center">
|
|
|
+ <View className="w-[50px] h-[50px] bg-[#1874d0] rounded-[50%] overflow-hidden">
|
|
|
+ {userInfo.avatar_url ? (
|
|
|
+ <Image src={userInfo.avatar_url} mode="aspectFill" />
|
|
|
+ ) : (
|
|
|
+ <Image src={userInfo.avatar_url} mode="aspectFill" />
|
|
|
+ )}
|
|
|
+ </View>
|
|
|
+ <View className="flex-1 ml-[10px]">
|
|
|
+ <View className="text-[16px] font-bold">
|
|
|
+ {userInfo.nickname || userInfo.username}
|
|
|
+ </View>
|
|
|
+ </View>
|
|
|
+ </View>
|
|
|
+ <Badge top="2" right="8" value={userInfo.notification_count}>
|
|
|
+ <Notice
|
|
|
+ onClick={() => {
|
|
|
+ navigateTo({ url: "/pages/message/index" });
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ </Badge>
|
|
|
+ </View>
|
|
|
+ <View className="flex items-center justify-between text-[14px] mt-[10px]">
|
|
|
+ <View className="flex">
|
|
|
+ <View className="flex">
|
|
|
+ <Text className="text-[#949494]">关注我</Text>
|
|
|
+ <Text className="ml-[5px]">{userInfo.follow_count}</Text>
|
|
|
+ </View>
|
|
|
+ <View className="flex ml-[20px]">
|
|
|
+ <Text className="text-[#949494]">获得互动</Text>
|
|
|
+ <Text className="ml-[5px]">{userInfo.interaction_count}</Text>
|
|
|
+ </View>
|
|
|
+ </View>
|
|
|
+ <View
|
|
|
+ className="bg-[#f7f7f7] w-[70px] h-[30px] rounded-[15px] flex items-center justify-around"
|
|
|
+ onClick={() => {
|
|
|
+ navigateTo({ url: "/pages/publish/index" });
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <View className="flex items-center">
|
|
|
+ <Plus />
|
|
|
+ <Text>发布</Text>
|
|
|
+ </View>
|
|
|
+ </View>
|
|
|
+ </View>
|
|
|
+ </View>
|
|
|
+ <View className="mt-[10px]">
|
|
|
+ <Tabs
|
|
|
+ className="tabs-self"
|
|
|
+ align="left"
|
|
|
+ value={tab1value}
|
|
|
+ onChange={(value) => {
|
|
|
+ setTab1value(value);
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <Tabs.TabPane title="帖子">
|
|
|
+ <ScrollView
|
|
|
+ scrollY
|
|
|
+ style={{ height: `${scrollHeight}px` }}
|
|
|
+ onScrollToLower={loadMore}
|
|
|
+ refresherEnabled
|
|
|
+ refresherTriggered={refreshing}
|
|
|
+ onRefresherRefresh={onRefresh}
|
|
|
+ lowerThreshold={50}
|
|
|
+ className="bg-[#f7f8fa]"
|
|
|
+ >
|
|
|
+ {postList.map((item) => (
|
|
|
+ <View
|
|
|
+ className="post-list-item bg-[#fff] p-[10px] mt-[10px]"
|
|
|
+ onClick={() =>
|
|
|
+ navigateTo({ url: `/pages/detail/index?id=${item.id}` })
|
|
|
+ }
|
|
|
+ >
|
|
|
+ <View className="flex items-center justify-between">
|
|
|
+ <View className="flex items-center">
|
|
|
+ <View className="w-[80rpx] h-[80rpx] rounded-[50%] bg-[#000] overflow-hidden bg-[url('https://m.360buyimg.com/mobilecms/s750x366_jfs/t1/26597/30/4870/174583/5c35c5d2Ed55eedc6/50e27870c25e7a82.png')] bg-cover bg-center"></View>
|
|
|
+ <View className="ml-[10rpx]">
|
|
|
+ <View className="text-[14px] font-[800] text-[#9c9dee]">
|
|
|
+ {item.user.nickname || "微信用户"}
|
|
|
+ </View>
|
|
|
+ {item.user.is_official ? (
|
|
|
+ <View className="text-[12px] text-[#949494]">
|
|
|
+ 《心动女友》官方账号
|
|
|
+ </View>
|
|
|
+ ) : (
|
|
|
+ <></>
|
|
|
+ )}
|
|
|
+ </View>
|
|
|
+ </View>
|
|
|
+ </View>
|
|
|
+ <View className="text-[14px] text-[#333] pt-[10px]">
|
|
|
+ {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",
|
|
|
+ } as any
|
|
|
+ }
|
|
|
+ >
|
|
|
+ {item.media_url.map((ite: any, index: number) => {
|
|
|
+ return (
|
|
|
+ <GridItem>
|
|
|
+ <Image
|
|
|
+ src={ite.src}
|
|
|
+ mode="aspectFill"
|
|
|
+ height="100"
|
|
|
+ onClick={(e) => {
|
|
|
+ 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={() => {
|
|
|
+ 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>
|
|
|
+ ))}
|
|
|
+
|
|
|
+ {/* 错误状态 */}
|
|
|
+ {error && (
|
|
|
+ <View className="p-[20px] text-center">
|
|
|
+ <View className="text-[#ff4d4f] mb-[10px]">{error}</View>
|
|
|
+ <View
|
|
|
+ className="text-[#1874d0] underline cursor-pointer"
|
|
|
+ onClick={() => getPostList()}
|
|
|
+ >
|
|
|
+ 点击重试
|
|
|
+ </View>
|
|
|
+ </View>
|
|
|
+ )}
|
|
|
+
|
|
|
+ {/* 加载更多状态 */}
|
|
|
+ {loadingMore && (
|
|
|
+ <View className="p-[20px] text-center text-[#999]">
|
|
|
+ 加载更多...
|
|
|
+ </View>
|
|
|
+ )}
|
|
|
+
|
|
|
+ {/* 没有更多数据 */}
|
|
|
+ {!hasMore && postList.length > 0 && !loading && !refreshing && (
|
|
|
+ <View className="p-[20px] text-center text-[#999]">
|
|
|
+ 没有更多内容了
|
|
|
+ </View>
|
|
|
+ )}
|
|
|
+
|
|
|
+ {/* 空状态 */}
|
|
|
+ {!loading && !refreshing && postList.length === 0 && !error && (
|
|
|
+ <View className="p-[40px] text-center text-[#999]">
|
|
|
+ 暂无帖子
|
|
|
+ </View>
|
|
|
+ )}
|
|
|
+
|
|
|
+ {/* 初始加载状态 */}
|
|
|
+ {loading && postList.length === 0 && (
|
|
|
+ <View className="p-[40px] text-center text-[#999]">
|
|
|
+ 加载中...
|
|
|
+ </View>
|
|
|
+ )}
|
|
|
+ </ScrollView>
|
|
|
+ </Tabs.TabPane>
|
|
|
+ </Tabs>
|
|
|
+ </View>
|
|
|
+ <ImagePreview
|
|
|
+ images={mediaUrl}
|
|
|
+ visible={showPreview}
|
|
|
+ defaultValue={init}
|
|
|
+ onClose={() => setShowPreview(false)}
|
|
|
+ indicator
|
|
|
+ />
|
|
|
+ </View>
|
|
|
+ );
|
|
|
+};
|
|
|
+
|
|
|
+export default Self;
|