优化个人页

This commit is contained in:
2025-10-17 16:24:07 +08:00
parent 8f688378e1
commit f3ab0020d3
7 changed files with 549 additions and 429 deletions

View File

@@ -17,6 +17,8 @@ interface PickerOption {
}
interface PickerProps {
minYear?: number;
maxYear?: number;
title?: string;
showHeader?: boolean;
confirmText?: string;
@@ -28,10 +30,12 @@ interface PickerProps {
img?: string;
onConfirm?: (options: PickerOption[], values: (string | number)[]) => void;
onChange?: (value: (string | number)[]) => void;
style?: React.CSSProperties
style?: React.CSSProperties;
}
const PopupPicker = ({
minYear,
maxYear,
confirmText,
title,
showHeader,
@@ -87,7 +91,7 @@ const PopupPicker = ({
if (type === "month") {
setDefaultOptions(renderYearMonth());
} else if (type === "day") {
setDefaultOptions(renderYearMonthDay());
setDefaultOptions(renderYearMonthDay(minYear, maxYear));
} else if (type === "hour") {
setDefaultOptions(renderHourMinute());
} else {

View File

@@ -6,45 +6,47 @@ import "./index.scss";
import { EditModal } from "@/components";
import { UserService, PickerOption } from "@/services/userService";
import { PopupPicker } from "@/components/Picker/index";
import { useUserActions } from "@/store/userStore";
import { UserInfoType } from "@/services/userService";
// 用户信息接口
export interface UserInfo {
id: string | number;
nickname: string;
avatar: string;
join_date: string;
stats: {
following: number;
friends: number;
hosted: number;
participated: number;
};
personal_profile: string;
occupation: string;
ntrp_level: string;
phone?: string;
gender: string;
bio?: string;
latitude?: string;
longitude?: string;
birthday?: string;
is_following?: boolean;
tags?: string[];
ongoing_games?: string[];
country: string;
province: string;
city: string;
}
// export interface UserInfo {
// id: string | number;
// nickname: string;
// avatar: string;
// join_date: string;
// stats: {
// following: number;
// friends: number;
// hosted: number;
// participated: number;
// };
// personal_profile: string;
// occupation: string;
// ntrp_level: string;
// phone?: string;
// gender: string;
// bio?: string;
// latitude?: string;
// longitude?: string;
// birthday?: string;
// is_following?: boolean;
// tags?: string[];
// ongoing_games?: string[];
// country: string;
// province: string;
// city: string;
// }
// 用户信息卡片组件属性
interface UserInfoCardProps {
user_info: UserInfo;
user_info: Partial<UserInfoType>;
is_current_user: boolean;
is_following?: boolean;
on_follow?: () => void;
on_message?: () => void;
on_share?: () => void;
set_user_info?: (info: UserInfo) => void;
set_user_info?: (info: Partial<UserInfoType>) => void;
}
// 处理编辑用户信息
@@ -63,6 +65,7 @@ export const UserInfoCard: React.FC<UserInfoCardProps> = ({
on_share,
set_user_info,
}) => {
const { updateUserInfo } = useUserActions();
console.log("UserInfoCard 用户信息:", user_info);
// 编辑个人简介弹窗状态
const [edit_modal_visible, setEditModalVisible] = useState(false);
@@ -74,7 +77,9 @@ export const UserInfoCard: React.FC<UserInfoCardProps> = ({
useState(false);
// 表单状态
const [form_data, setFormData] = useState<UserInfo>({ ...user_info });
const [form_data, setFormData] = useState<Partial<UserInfoType>>({
...user_info,
});
// 职业数据
const [professions, setProfessions] = useState<PickerOption[]>([]);
@@ -172,15 +177,14 @@ export const UserInfoCard: React.FC<UserInfoCardProps> = ({
field !== null &&
!Array.isArray(field)
) {
await UserService.update_user_info({ ...field });
await updateUserInfo({ ...field });
// 更新本地状态
setFormData((prev) => ({ ...prev, ...field }));
// setUserInfo((prev) => ({ ...prev, ...field }));
} else {
// 调用更新用户信息接口,只传递修改的字段
const update_data = { [field as string]: value };
await UserService.update_user_info(update_data);
await updateUserInfo(update_data);
// 更新本地状态
setFormData((prev) => ({ ...prev, [field as string]: value }));
// setUserInfo((prev) => ({ ...prev, [field as string]: value }));
@@ -259,11 +263,15 @@ export const UserInfoCard: React.FC<UserInfoCardProps> = ({
{/* 头像和基本信息 */}
<View className="basic_info">
<View className="avatar_container">
<Image className="avatar" src={user_info.avatar} mode="aspectFill" />
<Image
className="avatar"
src={user_info.avatar_url || ""}
mode="aspectFill"
/>
</View>
<View className="info_container">
<Text className="nickname">{user_info.nickname}</Text>
<Text className="join_date">{user_info.join_date}</Text>
<Text className="nickname">{user_info.nickname || ""}</Text>
<Text className="join_date">{user_info.join_date || ""}</Text>
</View>
{is_current_user && (
<View className="tag_item" onClick={on_edit}>
@@ -282,22 +290,30 @@ export const UserInfoCard: React.FC<UserInfoCardProps> = ({
className="stat_item clickable"
onClick={() => handle_stats_click("following")}
>
<Text className="stat_number">{user_info.stats.following}</Text>
<Text className="stat_number">
{user_info.stats?.following_count || 0}
</Text>
<Text className="stat_label"></Text>
</View>
<View
className="stat_item clickable"
onClick={() => handle_stats_click("friends")}
>
<Text className="stat_number">{user_info.stats.friends}</Text>
<Text className="stat_number">
{user_info.stats?.followers_count || 0}
</Text>
<Text className="stat_label"></Text>
</View>
<View className="stat_item">
<Text className="stat_number">{user_info.stats.hosted}</Text>
<Text className="stat_number">
{user_info.stats?.hosted_games_count || 0}
</Text>
<Text className="stat_label"></Text>
</View>
<View className="stat_item">
<Text className="stat_number">{user_info.stats.participated}</Text>
<Text className="stat_number">
{user_info.stats?.participated_games_count || 0}
</Text>
<Text className="stat_label"></Text>
</View>
</View>
@@ -455,7 +471,7 @@ export const UserInfoCard: React.FC<UserInfoCardProps> = ({
]}
visible={gender_picker_visible}
setvisible={setGenderPickerVisible}
value={[form_data.gender]}
value={[form_data.gender || ""]}
onChange={handle_gender_change}
/>
)}
@@ -467,7 +483,11 @@ export const UserInfoCard: React.FC<UserInfoCardProps> = ({
options={cities}
visible={location_picker_visible}
setvisible={setLocationPickerVisible}
value={[form_data.country, form_data.province, form_data.city]}
value={[
form_data.country || "",
form_data.province || "",
form_data.city || "",
]}
onChange={handle_location_change}
/>
)}
@@ -488,10 +508,10 @@ export const UserInfoCard: React.FC<UserInfoCardProps> = ({
],
]}
type="ntrp"
img={user_info.avatar}
img={user_info.avatar_url || ""}
visible={ntrp_picker_visible}
setvisible={setNtrpPickerVisible}
value={[form_data.ntrp_level]}
value={[form_data.ntrp_level || ""]}
onChange={handle_ntrp_level_change}
/>
)}
@@ -503,7 +523,7 @@ export const UserInfoCard: React.FC<UserInfoCardProps> = ({
options={professions}
visible={occupation_picker_visible}
setvisible={setOccupationPickerVisible}
value={[...form_data.occupation.split(" ")]}
value={[...(form_data.occupation || "").split(" ")]}
onChange={handle_occupation_change}
/>
)}
@@ -644,8 +664,9 @@ export const GameTabs: React.FC<GameTabsProps> = ({
<Text className="tab_text">{hosted_text}</Text>
</View>
<View
className={`tab_item ${active_tab === "participated" ? "active" : ""
}`}
className={`tab_item ${
active_tab === "participated" ? "active" : ""
}`}
onClick={() => on_tab_change("participated")}
>
<Text className="tab_text">{participated_text}</Text>