blob: dab0c0f7112697008e0c6e8127cddfc910ea46c9 [file] [log] [blame]
阳菜,放晴!77743f42025-06-06 23:04:08 +08001import React, { useCallback, useEffect,useState,useRef } from 'react';
阳菜,放晴!7e1e3a52025-06-05 23:00:51 +08002import styles from './homepage.module.css';
3import { useApi } from '@/hooks/request';
阳菜,放晴!2f987042025-06-08 14:54:50 +08004import { useAppSelector } from '@/hooks/store';
阳菜,放晴!7e1e3a52025-06-05 23:00:51 +08005import { RootState } from '@/store';
6import { useNavigate } from 'react-router';
阳菜,放晴!2f987042025-06-08 14:54:50 +08007import Logo from '&/assets/logo.png';
阳菜,放晴!77743f42025-06-06 23:04:08 +08008import { getUserMessage } from '@/api/homepage'
9import { getUserDetail } from '@/api/homepage'
阳菜,放晴!7e1e3a52025-06-05 23:00:51 +080010import request from '@/utils/request'
阳菜,放晴!77743f42025-06-06 23:04:08 +080011// import { hotPosts } from '@/api/post';
阳菜,放晴!7e1e3a52025-06-05 23:00:51 +080012import { postUserLogin } from '@/api/auth';
阳菜,放晴!77743f42025-06-06 23:04:08 +080013import { debounce } from 'lodash';
14import { Q } from 'react-router/dist/development/fog-of-war-CGNKxM4z';
阳菜,放晴!2f987042025-06-08 14:54:50 +080015import head from '&/assets/head.jpg'
16import lv_one from '&/assets/pet/lv_one.png'
17import lv_two from '&/assets/pet/lv_two.png'
18import lv_three from '&/assets/pet/lv_three.png'
19import lv_four from '&/assets/pet/lv_four.png'
20import lv_five from '&/assets/pet/lv_five.png'
21import PetGame from '@/components/pet'
22
阳菜,放晴!7e1e3a52025-06-05 23:00:51 +080023
24interface WorkItem {
25 postId: number,
26 userId: number,
27 postTitle: string,
28 postContent: string,
29 createdAt: number,
30 postType: string,
阳菜,放晴!77743f42025-06-06 23:04:08 +080031 isLocked: boolean,
32 lockedReason: string,
33 lockedAt: string,
34 lockedBy: number,
阳菜,放晴!7e1e3a52025-06-05 23:00:51 +080035 viewCount: number,
36 hotScore: number,
37 lastCalculated: number
阳菜,放晴!7e1e3a52025-06-05 23:00:51 +080038}
39
40interface UserStats {
阳菜,放晴!77743f42025-06-06 23:04:08 +080041 username: string;
42 uploadAmount: number;
43 level: string;
阳菜,放晴!7e1e3a52025-06-05 23:00:51 +080044 likes: number;
45 following: number;
46 followers: number;
47 mutualFollows: number;
48}
49
阳菜,放晴!7e1e3a52025-06-05 23:00:51 +080050
51const Homepage: React.FC =() => {
阳菜,放晴!77743f42025-06-06 23:04:08 +080052 const [userStats, setUserStats] = useState<UserStats | null>(null);
53
54 const [works, setWorks] = useState<WorkItem[]>([]);
55 const worksRef = useRef<WorkItem[]>([]);
56
阳菜,放晴!7e1e3a52025-06-05 23:00:51 +080057 const navigate = useNavigate();
阳菜,放晴!2f987042025-06-08 14:54:50 +080058 const userInfo = useAppSelector((state: RootState) => state.user);
阳菜,放晴!77743f42025-06-06 23:04:08 +080059 const userId = userInfo.userId; // 从Redux获取当前用户ID
60
阳菜,放晴!2f987042025-06-08 14:54:50 +080061 const levelImages: { [key: string]: string } = {
62 'lv1': lv_one,
63 'lv2': lv_two,
64 'lv3': lv_three,
65 'lv4': lv_four,
66 'lv5': lv_five
67 };
68
阳菜,放晴!77743f42025-06-06 23:04:08 +080069 const { data:userdata, loading:userloading, error:usererror, refresh: getUserDetailRefresh } = useApi(
阳菜,放晴!2f987042025-06-08 14:54:50 +080070 () => request.get(getUserDetail, {params: {userId}}),
71 false
阳菜,放晴!77743f42025-06-06 23:04:08 +080072 );
73
阳菜,放晴!2f987042025-06-08 14:54:50 +080074 const { data: workdata, loading: workloading, error: workerror, refresh: getUserMessageRefresh } = useApi(
75 () => request.get(`${getUserMessage}/${userId}`), // 注意这里拼接了 userId
阳菜,放晴!77743f42025-06-06 23:04:08 +080076 false
77 );
78
79 const getUserDetails = debounce(async () => {
80 try{
阳菜,放晴!2f987042025-06-08 14:54:50 +080081 // const res = await getUserDetailRefresh({userId});
82 const res = await getUserDetailRefresh();
83 const data_1 = res?.userInfo;
84 const data_2 = res?.statistics;
85 console.log('data', data_1)
86 const formatted: UserStats = {
87 username: data_1.userName,
88 uploadAmount: data_1.uploadAmount,
89 level: data_1.userLevel,
90 likes: data_2.likes,
91 following: data_2.followingCount,
92 followers: data_2.followersCount,
93 mutualFollows: data_2.mutualFollows
94 };
95
96 setUserStats(formatted);
97 console.log('formatted:',formatted)
阳菜,放晴!77743f42025-06-06 23:04:08 +080098 }catch(error){
99 console.error('获取用户信息错误', error);
100 }
101 },1000) as () => void;
102
103
104 const getUserPost = debounce(async () => {
阳菜,放晴!2f987042025-06-08 14:54:50 +0800105 try {
106 const url = `${getUserMessage}/${userId}`; // ✅ 正确的 URL 拼接方式
107 console.log("请求发送:", url);
108
109 // 不需要传 userId 参数了,因为 URL 已包含它
110 const res = await getUserMessageRefresh();
阳菜,放晴!77743f42025-06-06 23:04:08 +0800111 console.log("res", res);
阳菜,放晴!2f987042025-06-08 14:54:50 +0800112
阳菜,放晴!77743f42025-06-06 23:04:08 +0800113 worksRef.current = res;
114 setWorks(res);
阳菜,放晴!2f987042025-06-08 14:54:50 +0800115 } catch (error) {
阳菜,放晴!77743f42025-06-06 23:04:08 +0800116 console.error('获取帖子列表错误', error);
117 }
阳菜,放晴!2f987042025-06-08 14:54:50 +0800118 }, 1000) as () => void;
119
阳菜,放晴!77743f42025-06-06 23:04:08 +0800120
阳菜,放晴!7e1e3a52025-06-05 23:00:51 +0800121 useEffect(() => {
阳菜,放晴!77743f42025-06-06 23:04:08 +0800122 if (!userId) {
123 navigate('/login');
124 }
125 else {
126 getUserDetails();
127 getUserPost();
128 }
129 }, [userId]);
130
131 if (!userId) return null;
132
阳菜,放晴!7e1e3a52025-06-05 23:00:51 +0800133
134 return (
135 <div className={styles.container}>
136
137
138 {/* 用户信息主区域 */}
139 <div className={styles.mainContent}>
140 {/* 左侧用户信息区 */}
141 <div className={styles.userProfile}>
142 <div className={styles.userHeader}>
143 <img
阳菜,放晴!2f987042025-06-08 14:54:50 +0800144 src={head}
阳菜,放晴!7e1e3a52025-06-05 23:00:51 +0800145 alt="用户头像"
146 className={styles.userAvatar}
147 />
148 <div className={styles.userInfo}>
阳菜,放晴!2f987042025-06-08 14:54:50 +0800149 <h2 className={styles.username}>{userStats?.username}</h2>
150 <div className={styles.inviteCode}>邀请码:123456</div>
阳菜,放晴!7e1e3a52025-06-05 23:00:51 +0800151 <button className={styles.editButton}>编辑主页</button>
阳菜,放晴!7e1e3a52025-06-05 23:00:51 +0800152 </div>
153 </div>
154
155 <div className={styles.userStats}>
156 <div className={styles.statItem}>
阳菜,放晴!77743f42025-06-06 23:04:08 +0800157 <div className={styles.statNumber}>{userStats?.likes ?? '--'}</div>
阳菜,放晴!7e1e3a52025-06-05 23:00:51 +0800158 <div className={styles.statLabel}>获赞</div>
159 </div>
160 <div className={styles.statItem}>
阳菜,放晴!77743f42025-06-06 23:04:08 +0800161 <div className={styles.statNumber}>{userStats?.following ?? '--'}</div>
阳菜,放晴!7e1e3a52025-06-05 23:00:51 +0800162 <div className={styles.statLabel}>关注</div>
163 </div>
164 <div className={styles.statItem}>
阳菜,放晴!77743f42025-06-06 23:04:08 +0800165 <div className={styles.statNumber}>{userStats?.followers ?? '--'}</div>
阳菜,放晴!7e1e3a52025-06-05 23:00:51 +0800166 <div className={styles.statLabel}>粉丝</div>
167 </div>
阳菜,放晴!2f987042025-06-08 14:54:50 +0800168 {/* <div className={styles.statItem}>
阳菜,放晴!77743f42025-06-06 23:04:08 +0800169 <div className={styles.statNumber}>{userStats?.mutualFollows ?? '--'}</div>
阳菜,放晴!7e1e3a52025-06-05 23:00:51 +0800170 <div className={styles.statLabel}>互关</div>
阳菜,放晴!2f987042025-06-08 14:54:50 +0800171 </div> */}
阳菜,放晴!7e1e3a52025-06-05 23:00:51 +0800172 </div>
173
174 <div className={styles.userData}>
175 <div className={styles.dataItem}>
176 <span>您的总上传量为:</span>
阳菜,放晴!77743f42025-06-06 23:04:08 +0800177 <strong>{userStats?.uploadAmount ?? '--'}</strong>
阳菜,放晴!7e1e3a52025-06-05 23:00:51 +0800178 </div>
179 <div className={styles.dataItem}>
180 <span>您的用户等级为:</span>
阳菜,放晴!77743f42025-06-06 23:04:08 +0800181 <strong>{userStats?.level ?? '--'}</strong>
阳菜,放晴!7e1e3a52025-06-05 23:00:51 +0800182 </div>
183 </div>
184
185 <div className={styles.worksSection}>
186 <h3 className={styles.sectionTitle}>我的作品</h3>
阳菜,放晴!77743f42025-06-06 23:04:08 +0800187 {workloading && <div className={styles.loading}>加载中...</div>}
188 {workerror && <div className={styles.error}>{workerror.message}</div>}
阳菜,放晴!7e1e3a52025-06-05 23:00:51 +0800189
阳菜,放晴!77743f42025-06-06 23:04:08 +0800190 {works.map(work => (
阳菜,放晴!7e1e3a52025-06-05 23:00:51 +0800191 <div key={work.postId} className={styles.workItem}>
192 <h4 className={styles.workTitle}>{work.postTitle}</h4>
193 <div className={styles.workMeta}>
194 <span>发布时间:{work.createdAt}</span>
195 <span>下载量:{work.viewCount} 做种数:{'待定'}</span>
196 </div>
197 </div>
198 )) }
199 </div>
200 </div>
201
202 {/* 右侧内容区 */}
203 <div className={styles.rightContent}>
204 <div className={styles.petSection}>
205 <h3 className={styles.sectionTitle}>宠物图</h3>
206 <div className={styles.petContainer}>
阳菜,放晴!2f987042025-06-08 14:54:50 +0800207 <img
208 src={levelImages[userStats?.level || 'lv5']} // 默认用 '1' 级
209 alt={`等级${userStats?.level}宠物`}
210 className={styles.petImage}
211 />
阳菜,放晴!7e1e3a52025-06-05 23:00:51 +0800212 </div>
阳菜,放晴!2f987042025-06-08 14:54:50 +0800213 <PetGame/>
阳菜,放晴!7e1e3a52025-06-05 23:00:51 +0800214 </div>
阳菜,放晴!2f987042025-06-08 14:54:50 +0800215
阳菜,放晴!7e1e3a52025-06-05 23:00:51 +0800216 </div>
217 </div>
218 </div>
219 );
220};
221
222export default Homepage;