This commit is contained in:
张成
2025-09-12 22:34:12 +08:00
parent 471244ee5d
commit 30d16946d2
30 changed files with 104 additions and 65 deletions

View File

@@ -0,0 +1,4 @@
export default definePageConfig({
navigationBarTitleText: '用户主页',
navigationStyle: 'custom'
})

View File

@@ -0,0 +1,490 @@
// 他人用户页面样式
.other_user_page {
min-height: 100vh;
background: radial-gradient(circle at 50% 0%, rgba(238, 255, 220, 1) 0%, rgba(255, 255, 255, 1) 37%);
position: relative;
overflow: hidden;
box-sizing: border-box;
}
// 主要内容区域
.main_content {
position: relative;
z-index: 5;
flex: 1;
margin-top: 0;
box-sizing: border-box;
overflow-y: auto;
padding: 15px 15px 15px;
// 用户信息区域
.user_info_section {
display: flex;
flex-direction: column;
gap: 16px;
margin-bottom: 16px;
// 基本信息
.basic_info {
display: flex;
align-items: center;
gap: 16px;
.avatar_container {
width: 64px;
height: 64px;
border-radius: 50%;
overflow: hidden;
box-shadow: 0px 8px 20px 0px rgba(0, 0, 0, 0.12), 0px 0px 1px 0px rgba(0, 0, 0, 0.2);
.avatar {
width: 100%;
height: 100%;
object-fit: cover;
}
}
.info_container {
flex: 1;
display: flex;
flex-direction: column;
gap: 4px;
.nickname {
font-family: 'PingFang SC';
font-weight: 600;
font-size: 20px;
line-height: 1.4em;
letter-spacing: 1.9%;
color: #000000;
}
.join_date {
font-family: 'PingFang SC';
font-weight: 400;
font-size: 14px;
line-height: 1.4em;
letter-spacing: 2.7%;
color: rgba(0, 0, 0, 0.35);
}
}
}
// 统计数据
.stats_section {
display: flex;
justify-content: space-between;
align-items: center;
gap: 24px;
.stats_container {
display: flex;
align-items: center;
gap: 20px;
.stat_item {
display: flex;
flex-direction: column;
align-items: center;
.stat_number {
font-family: 'PingFang SC';
font-weight: 600;
font-size: 18px;
line-height: 1.4em;
letter-spacing: 2.1%;
color: rgba(0, 0, 0, 0.85);
}
.stat_label {
font-family: 'PingFang SC';
font-weight: 500;
font-size: 12px;
line-height: 1.4em;
letter-spacing: 3.2%;
color: rgba(0, 0, 0, 0.35);
}
}
}
.action_buttons {
display: flex;
align-items: center;
gap: 12px;
.follow_button {
display: flex;
align-items: center;
gap: 4px;
padding: 12px 16px 12px 12px;
height: 40px;
background: #000000;
border: 0.5px solid rgba(0, 0, 0, 0.06);
border-radius: 999px;
cursor: pointer;
transition: all 0.3s ease;
&.following {
background: #FFFFFF;
color: #000000;
}
.button_icon {
width: 20px;
height: 20px;
}
.button_text {
font-family: 'PingFang SC';
font-weight: 600;
font-size: 14px;
line-height: 1.4em;
color: #FFFFFF;
.following & {
color: #000000;
}
}
}
.message_button {
width: 40px;
height: 40px;
background: #FFFFFF;
border: 0.5px solid rgba(0, 0, 0, 0.12);
border-radius: 999px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: all 0.3s ease;
.button_icon {
width: 18px;
height: 18px;
}
}
}
}
// 标签和简介
.tags_bio_section {
display: flex;
flex-direction: column;
gap: 10px;
.tags_container {
display: flex;
gap: 8px;
flex-wrap: wrap;
.tag_item {
display: flex;
align-items: center;
gap: 4px;
padding: 6px 8px;
height: 20px;
background: #FFFFFF;
border: 0.5px solid rgba(0, 0, 0, 0.16);
border-radius: 999px;
.tag_icon {
width: 12px;
height: 12px;
}
.tag_text {
font-family: 'PingFang SC';
font-weight: 500;
font-size: 11px;
line-height: 1.8em;
letter-spacing: -2.1%;
color: #000000;
}
}
}
.bio_text {
font-family: 'PingFang SC';
font-weight: 400;
font-size: 14px;
line-height: 1.571em;
color: rgba(0, 0, 0, 0.65);
white-space: pre-line;
}
}
}
// 球局类型标签页
.game_tabs_section {
margin-bottom: 16px;
.tab_container {
display: flex;
gap: 16px;
padding: 12px 15px;
.tab_item {
padding: 12px 0;
cursor: pointer;
transition: all 0.3s ease;
.tab_text {
font-family: 'PingFang SC';
font-weight: 600;
font-size: 20px;
line-height: 1.4em;
letter-spacing: 1.9%;
color: rgba(0, 0, 0, 0.85);
transition: color 0.3s ease;
}
&.active {
.tab_text {
color: #000000;
}
}
&:not(.active) {
.tab_text {
color: rgba(0, 0, 0, 0.2);
}
}
}
}
}
// 球局列表区域
.game_list_section {
.date_header {
display: flex;
align-items: center;
gap: 4px;
padding: 10px 15px;
margin-bottom: 16px;
.date_text {
font-family: 'PingFang SC';
font-weight: 600;
font-size: 14px;
line-height: 1.4em;
letter-spacing: 2.71%;
color: rgba(0, 0, 0, 0.85);
}
.separator {
font-family: 'PingFang SC';
font-weight: 400;
font-size: 18px;
line-height: 1.4em;
letter-spacing: 2.11%;
color: rgba(0, 0, 0, 0.35);
}
.weekday_text {
font-family: 'PingFang SC';
font-weight: 600;
font-size: 14px;
line-height: 1.4em;
letter-spacing: 2.71%;
color: rgba(0, 0, 0, 0.85);
}
}
// 球局卡片
.game_cards {
display: flex;
flex-direction: column;
gap: 5px;
padding: 0 5px 15px;
.game_card {
background: #FFFFFF;
border: 0.5px solid rgba(0, 0, 0, 0.08);
border-radius: 20px;
padding: 0 0 12px;
box-shadow: 0px 4px 36px 0px rgba(0, 0, 0, 0.06);
cursor: pointer;
transition: all 0.3s ease;
position: relative;
&:active {
transform: scale(0.98);
}
// 球局标题和类型
.game_header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 12px 15px 0;
.game_title {
font-family: 'PingFang SC';
font-weight: 600;
font-size: 16px;
line-height: 1.5em;
color: #000000;
}
.game_type_icon {
width: 16px;
height: 16px;
.type_icon {
width: 100%;
height: 100%;
}
}
}
// 球局时间
.game_time {
padding: 6px 15px 0;
.time_text {
font-family: 'PingFang SC';
font-weight: 400;
font-size: 12px;
line-height: 1.5em;
color: rgba(60, 60, 67, 0.6);
}
}
// 球局地点和类型
.game_location {
display: flex;
align-items: center;
gap: 2px;
padding: 4px 15px 0;
.location_text,
.type_text,
.distance_text {
font-family: 'PingFang SC';
font-weight: 400;
font-size: 12px;
line-height: 1.5em;
color: rgba(60, 60, 67, 0.6);
}
.separator {
font-family: 'PingFang SC';
font-weight: 400;
font-size: 14px;
line-height: 1.3em;
color: rgba(60, 60, 67, 0.3);
}
}
// 球局图片
.game_images {
position: absolute;
top: 11px;
right: 5px;
width: 100px;
height: 100px;
box-shadow: 0px 4px 24px 0px rgba(0, 0, 0, 0.2);
.game_image {
position: absolute;
width: 56.44px;
height: 56.44px;
border-radius: 9px;
border: 1.5px solid #FFFFFF;
&:nth-child(1) {
top: 4.18px;
left: 19.18px;
}
&:nth-child(2) {
top: 26.5px;
left: 38px;
width: 61.86px;
height: 61.86px;
}
&:nth-child(3) {
top: 32.5px;
left: 0;
width: 62.04px;
height: 62.04px;
}
}
}
// 球局信息标签
.game_tags {
display: flex;
flex-direction: row;
gap: 6px;
padding: 8px 15px 0;
.participants_info {
display: flex;
gap: 4px;
.avatars {
display: flex;
align-items: center;
gap: -8px;
.participant_avatar {
width: 20px;
height: 20px;
border-radius: 50%;
border: 1px solid #FFFFFF;
}
}
.participants_count {
background: #FFFFFF;
border: 0.5px solid rgba(0, 0, 0, 0.16);
border-radius: 999px;
padding: 6px;
height: 20px;
display: flex;
align-items: center;
justify-content: center;
.count_text {
font-family: 'PingFang SC';
font-weight: 500;
font-size: 11px;
line-height: 1.8em;
letter-spacing: -2.1%;
color: #000000;
}
}
}
.game_info_tags {
display: flex;
gap: 4px;
.info_tag {
background: #FFFFFF;
border: 0.5px solid rgba(0, 0, 0, 0.16);
border-radius: 999px;
padding: 6px 8px;
height: 20px;
display: flex;
align-items: center;
justify-content: center;
.tag_text {
font-family: 'PingFang SC';
font-weight: 500;
font-size: 11px;
line-height: 1.8em;
letter-spacing: -2.1%;
color: #000000;
}
}
}
}
}
}
}
}

View File

@@ -0,0 +1,159 @@
import React, { useState, useEffect } from "react";
import { View, Text, ScrollView } from "@tarojs/components";
import Taro from "@tarojs/taro";
import "./index.scss";
import GuideBar from "@/components/GuideBar";
import {
UserInfoCard,
GameCard,
GameTabs,
UserInfo,
GameRecord,
} from "@/components/UserInfo";
import { UserService } from "@/services/userService";
const OtherUserPage: React.FC = () => {
// 获取页面参数
const instance = Taro.getCurrentInstance();
const user_id = instance.router?.params?.userid;
// 模拟用户数据
const [user_info, setUserInfo] = useState<UserInfo>({
id: user_id || "1",
nickname: "网球爱好者",
avatar: require("@/static/userInfo/default_avatar.svg"),
join_date: "2024年3月加入",
stats: {
following: 89,
friends: 15,
hosted: 12,
participated: 35,
},
tags: ["北京朝阳", "金融从业者", "NTRP 3.5"],
bio: "热爱网球的金融从业者,周末喜欢约球\n技术还在提升中欢迎一起切磋\n平时在朝阳公园附近活动",
location: "北京朝阳",
occupation: "金融从业者",
ntrp_level: "NTRP 3.5",
});
// 模拟球局数据
const [game_records, setGameRecords] = useState<GameRecord[]>([]);
// 关注状态
const [is_following, setIsFollowing] = useState(false);
// 当前激活的标签页
const [active_tab, setActiveTab] = useState<"hosted" | "participated">(
"hosted",
);
// 页面加载时获取用户信息
useEffect(() => {
const load_user_data = async () => {
if (user_id) {
try {
const user_data = await UserService.get_user_info(user_id);
setUserInfo(user_data);
const games_data = await UserService.get_user_games(
user_id,
active_tab,
);
setGameRecords(games_data);
} catch (error) {
console.error("加载用户数据失败:", error);
Taro.showToast({
title: "加载失败",
icon: "none",
});
}
}
};
load_user_data();
}, [user_id, active_tab]);
// 处理关注/取消关注
const handle_follow = async () => {
try {
const new_follow_status = await UserService.toggle_follow(
user_info.id,
is_following,
);
setIsFollowing(new_follow_status);
Taro.showToast({
title: new_follow_status ? "关注成功" : "已取消关注",
icon: "success",
duration: 1500,
});
} catch (error) {
console.error("关注操作失败:", error);
Taro.showToast({
title: "操作失败",
icon: "none",
});
}
};
// 处理发送消息
const handle_send_message = () => {
Taro.navigateTo({
url: `/mode_user/message/chat/index?user_id=${user_info.id}&nickname=${user_info.nickname}`,
});
};
// 处理球局详情
const handle_game_detail = (game_id: string) => {
Taro.navigateTo({
url: `/game_pages/detail/index?id=${game_id}&from=personal`,
});
};
return (
<View className="other_user_page">
{/* 主要内容 */}
<View className="main_content">
{/* 用户信息区域 */}
<View className="user_info_section">
<UserInfoCard
user_info={user_info}
is_current_user={false}
is_following={is_following}
on_follow={handle_follow}
on_message={handle_send_message}
/>
</View>
{/* 球局类型标签页 */}
<GameTabs
active_tab={active_tab}
on_tab_change={setActiveTab}
is_current_user={false}
/>
{/* 球局列表 */}
<View className="game_list_section">
<View className="date_header">
<Text className="date_text">529</Text>
<Text className="separator">/</Text>
<Text className="weekday_text"></Text>
</View>
{/* 球局卡片 */}
<View className="game_cards">
{game_records.map((game) => (
<GameCard
key={game.id}
game={game}
on_click={handle_game_detail}
/>
))}
</View>
</View>
</View>
<GuideBar currentPage="personal" />
</View>
);
};
export default OtherUserPage;