diff --git a/src/app.config.ts b/src/app.config.ts index 7b1fcad..7520adf 100644 --- a/src/app.config.ts +++ b/src/app.config.ts @@ -1,10 +1,13 @@ export default defineAppConfig({ pages: [ - 'pages/list/index', + 'pages/list/index', 'pages/publishBall/index', + // 'pages/userInfo/myself/index', // 'pages/login/index/index', // 'pages/login/verification/index', // 'pages/login/terms/index', + + // 'pages/mapDisplay/index', // 'pages/index/index' ], diff --git a/src/pages/userInfo/myself/index.config.ts b/src/pages/userInfo/myself/index.config.ts new file mode 100644 index 0000000..eb44728 --- /dev/null +++ b/src/pages/userInfo/myself/index.config.ts @@ -0,0 +1,9 @@ +export default { + navigationBarTitleText: '个人主页', + navigationBarBackgroundColor: '#FFFFFF', + navigationBarTextStyle: 'black', + backgroundColor: '#FAFAFA', + enablePullDownRefresh: false, + disableScroll: false, + navigationStyle: 'custom' +} \ No newline at end of file diff --git a/src/pages/userInfo/myself/index.scss b/src/pages/userInfo/myself/index.scss new file mode 100644 index 0000000..2aa9ace --- /dev/null +++ b/src/pages/userInfo/myself/index.scss @@ -0,0 +1,600 @@ +// 个人页面样式 +.myself_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; + } + } + + .edit_button { + min-width: 60px; + 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; + padding: 0 12px; + + .button_text { + font-family: 'PingFang SC'; + font-weight: 500; + font-size: 14px; + line-height: 1.4em; + color: #000000; + } + } + + .share_button { + min-width: 60px; + 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; + padding: 0 12px; + margin: 0px !important; + + .button_text { + font-family: 'PingFang SC'; + font-weight: 500; + font-size: 14px; + line-height: 1.4em; + color: #000000; + } + } + } + } + + // 标签和简介 + .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; + } + } + + // 球局订单和收藏功能 + .quick_actions_section { + margin-bottom: 16px; + + .action_card { + display: flex; + align-items: center; + background: #FFFFFF; + border: 1px solid rgba(0, 0, 0, 0.06); + border-radius: 12px; + box-shadow: 0px 4px 36px 0px rgba(0, 0, 0, 0.06); + overflow: hidden; + + .action_content { + flex: 1; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 8px; + padding: 20px 0; + cursor: pointer; + transition: background-color 0.3s ease; + + &:hover { + background-color: rgba(0, 0, 0, 0.02); + } + + .action_icon { + width: 20px; + height: 20px; + } + + .action_text { + font-family: 'PingFang SC'; + font-weight: 600; + font-size: 15px; + line-height: 1.4em; + color: #000000; + } + } + + .action_divider { + width: 1px; + height: 16px; + background: rgba(0, 0, 0, 0.06); + } + } + } + } + + // 球局类型标签页 + .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; + } + } + } + } + } + } + } +} + +// 底部指示器 +.home_indicator { + position: absolute; + bottom: 21px; + left: 50%; + transform: translateX(-50%); + width: 140px; + height: 5px; + background: #000000; + border-radius: 2.5px; + z-index: 10; +} \ No newline at end of file diff --git a/src/pages/userInfo/myself/index.tsx b/src/pages/userInfo/myself/index.tsx new file mode 100644 index 0000000..d4ca486 --- /dev/null +++ b/src/pages/userInfo/myself/index.tsx @@ -0,0 +1,377 @@ +import React, { useState, useEffect } from 'react'; +import { View, Text, Image, ScrollView, Button } from '@tarojs/components'; +import Taro from '@tarojs/taro'; +import './index.scss'; + +// 用户信息接口 +interface UserInfo { + id: string; + nickname: string; + avatar: string; + join_date: string; + stats: { + following: number; + friends: number; + hosted: number; + participated: number; + }; + tags: string[]; + bio: string; + location: string; + occupation: string; + ntrp_level: string; +} + +// 球局记录接口 +interface GameRecord { + id: string; + title: string; + date: string; + time: string; + duration: string; + location: string; + type: string; + distance: string; + participants: { + avatar: string; + nickname: string; + }[]; + max_participants: number; + current_participants: number; + level_range: string; + game_type: string; + images: string[]; +} + +const MyselfPage: React.FC = () => { + // 获取页面参数 + const instance = Taro.getCurrentInstance(); + const user_id = instance.router?.params?.userid; + + // 判断是否为当前用户 + const is_current_user = !user_id; + + // 模拟用户数据 + const [user_info] = useState({ + id: '1', + nickname: '188的王晨', + avatar: require('../../../static/userInfo/default_avatar.svg'), + join_date: '2025年9月加入', + stats: { + following: 124, + friends: 24, + hosted: 7, + participated: 24 + }, + tags: ['上海黄浦', '互联网从业者', 'NTRP 4.0'], + bio: '网球入坑两年,偏好双打,正手进攻型选手\n平时在张江、世纪公园附近活动,欢迎约球!\n不卷分数,但认真对待每一拍,每一场球都想打得开心。有时候也会带相机来拍点照片📸', + location: '上海黄浦', + occupation: '互联网从业者', + ntrp_level: 'NTRP 4.0' + }); + + // 模拟球局数据 + const [game_records] = useState([ + { + id: '1', + title: '女生轻松双打', + date: '明天(周五)', + time: '下午5点', + duration: '2小时', + location: '仁恒河滨花园网球场', + type: '室外', + distance: '3.5km', + participants: [ + { avatar: require('../../../static/userInfo/user1.svg'), nickname: '用户1' }, + { avatar: require('../../../static/userInfo/user2.svg'), nickname: '用户2' } + ], + max_participants: 4, + current_participants: 2, + level_range: '2.0 至 2.5', + game_type: '双打', + images: [ + require('../../../static/userInfo/game1.svg'), + require('../../../static/userInfo/game2.svg'), + require('../../../static/userInfo/game3.svg') + ] + } + ]); + + // 关注状态 + const [is_following, setIsFollowing] = useState(false); + + // 当前激活的标签页 + const [active_tab, setActiveTab] = useState<'hosted' | 'participated'>('hosted'); + + // 处理关注/取消关注 + const handle_follow = () => { + setIsFollowing(!is_following); + Taro.showToast({ + title: is_following ? '已取消关注' : '关注成功', + icon: 'success', + duration: 1500 + }); + }; + + // 处理分享 + const handle_share = () => { + Taro.showShareMenu({ + withShareTicket: true + }); + }; + + // 处理返回 + const handle_back = () => { + Taro.navigateBack(); + }; + + // 处理编辑资料 + const handle_edit_profile = () => { + Taro.navigateTo({ + url: '/pages/userInfo/edit/index' + }); + }; + + // 处理球局详情 + const handle_game_detail = (game_id: string) => { + Taro.navigateTo({ + url: `/pages/game/detail/index?id=${game_id}` + }); + }; + + // 处理球局订单 + const handle_game_orders = () => { + Taro.navigateTo({ + url: '/pages/game/orders/index' + }); + }; + + // 处理收藏 + const handle_favorites = () => { + Taro.navigateTo({ + url: '/pages/game/favorites/index' + }); + }; + + return ( + + {/* 主要内容 */} + + {/* 用户信息区域 */} + + {/* 头像和基本信息 */} + + + + + + {user_info.nickname} + {user_info.join_date} + + + + {/* 统计数据 */} + + + + {user_info.stats.following} + 关注 + + + {user_info.stats.friends} + 球友 + + + {user_info.stats.hosted} + 主办 + + + {user_info.stats.participated} + 参加 + + + + {/* 只有非当前用户才显示关注按钮 */} + {!is_current_user && ( + + )} + {/* 只有非当前用户才显示消息按钮 */} + {!is_current_user && ( + + )} + {/* 只有当前用户才显示编辑按钮 */} + {is_current_user && ( + + )} + {/* 只有当前用户才显示分享按钮 */} + {is_current_user && ( + + )} + + + + {/* 标签和简介 */} + + + + + {user_info.location} + + + {user_info.occupation} + + + {user_info.ntrp_level} + + + {user_info.bio} + + + {/* 球局订单和收藏功能 */} + + + + + 球局订单 + + + + + 收藏 + + + + + + {/* 球局类型标签页 */} + + + setActiveTab('hosted')}> + 我主办的 + + setActiveTab('participated')}> + 我参与的 + + + + + {/* 球局列表 */} + + + 5月28日 + / + 星期三 + + + {/* 球局卡片 */} + + {game_records.map((game) => ( + handle_game_detail(game.id)} + > + {/* 球局标题和类型 */} + + {game.title} + + + + + + {/* 球局时间 */} + + + {game.date} {game.time} {game.duration} + + + + {/* 球局地点和类型 */} + + {game.location} + · + {game.type} + · + {game.distance} + + + {/* 球局图片 */} + + {game.images.map((image, index) => ( + + ))} + + + {/* 球局信息标签 */} + + + + {game.participants.map((participant, index) => ( + + ))} + + + + 报名人数 {game.current_participants}/{game.max_participants} + + + + + + {game.level_range} + + + {game.game_type} + + + + + ))} + + + + + ); +}; + +export default MyselfPage; diff --git a/src/static/userInfo/default_avatar.svg b/src/static/userInfo/default_avatar.svg new file mode 100644 index 0000000..5cf5917 --- /dev/null +++ b/src/static/userInfo/default_avatar.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src/static/userInfo/game1.svg b/src/static/userInfo/game1.svg new file mode 100644 index 0000000..ca4f985 --- /dev/null +++ b/src/static/userInfo/game1.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/static/userInfo/game2.svg b/src/static/userInfo/game2.svg new file mode 100644 index 0000000..ab7fe76 --- /dev/null +++ b/src/static/userInfo/game2.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/static/userInfo/game3.svg b/src/static/userInfo/game3.svg new file mode 100644 index 0000000..875bdaa --- /dev/null +++ b/src/static/userInfo/game3.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/static/userInfo/location.svg b/src/static/userInfo/location.svg new file mode 100644 index 0000000..a1c89f9 --- /dev/null +++ b/src/static/userInfo/location.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src/static/userInfo/message.svg b/src/static/userInfo/message.svg new file mode 100644 index 0000000..f22ed89 --- /dev/null +++ b/src/static/userInfo/message.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/static/userInfo/plus.svg b/src/static/userInfo/plus.svg new file mode 100644 index 0000000..a4e5876 --- /dev/null +++ b/src/static/userInfo/plus.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/static/userInfo/tennis.svg b/src/static/userInfo/tennis.svg new file mode 100644 index 0000000..2405eb1 --- /dev/null +++ b/src/static/userInfo/tennis.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/src/static/userInfo/user1.svg b/src/static/userInfo/user1.svg new file mode 100644 index 0000000..605867e --- /dev/null +++ b/src/static/userInfo/user1.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src/static/userInfo/user2.svg b/src/static/userInfo/user2.svg new file mode 100644 index 0000000..86e660b --- /dev/null +++ b/src/static/userInfo/user2.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file