Merge branch 'feat/liujie'

This commit is contained in:
2025-09-04 20:17:26 +08:00
4 changed files with 137 additions and 89 deletions

View File

@@ -4,11 +4,11 @@ import { Cell, Avatar, Progress, Popover } from '@nutui/nutui-react-taro'
import Taro, { useRouter, useShareAppMessage, useShareTimeline, useDidShow } from '@tarojs/taro'
// 导入API服务
import DetailService from '../../services/detailService'
import { updateUserProfile } from '../../services/loginService'
import { updateUserProfile, get_user_info } from '../../services/loginService'
import { getCurrentLocation } from '../../utils/locationUtils'
import {
useUserStats,
useUserActions
useUserInfo,
useUserActions,
} from '../../store/userStore'
import img from '../../config/images'
import { getTextColorOnImage } from '../../utils'
@@ -25,6 +25,7 @@ function insertDotInTags(tags: string[]) {
return tags.join('-·-').split('-')
}
// 分享弹窗
const SharePopup = forwardRef(({ id, from }: { id: string, from: string }, ref) => {
const [visible, setVisible] = useState(false)
@@ -90,6 +91,39 @@ const SharePopup = forwardRef(({ id, from }: { id: string, from: string }, ref)
)
})
// 底部操作栏
function StickyButton(props) {
const { handleShare, handleJoinGame, detail } = props
const userInfo = useUserInfo()
const { id } = userInfo
const { publisher_id, status } = detail || {}
const role = Number(publisher_id) === id ? 'ownner' : 'visitor'
console.log(status, role)
return (
<View className="sticky-bottom-bar">
<View className="sticky-bottom-bar-share-and-comment">
<View className='sticky-bottom-bar-share' onClick={handleShare}>
<Image className='sticky-bottom-bar-share-icon' src={img.ICON_DETAIL_SHARE} />
<Text className='sticky-bottom-bar-share-text'></Text>
</View>
<View className='sticky-bottom-bar-share-and-comment-separator' />
<View className='sticky-bottom-bar-comment' onClick={() => { Taro.showToast({ title: 'To be continued', icon: 'none' }) }}>
<Image className='sticky-bottom-bar-comment-icon' src={img.ICON_DETAIL_COMMENT_DARK} />
<Text className='sticky-bottom-bar-comment-text'>32</Text>
</View>
</View>
<View className="sticky-bottom-bar-join-game" onClick={handleJoinGame}>
<Text>🎾</Text>
<Text></Text>
<View className='game-price'>
<Text>¥ 65</Text>
</View>
</View>
</View>
)
}
function Index() {
// 使用Zustand store
// const userStats = useUserStats()
@@ -99,7 +133,9 @@ function Index() {
// const [textColor, setTextColor] = useState<string []>([])
const [detail, setDetail] = useState<any>(null)
const { params } = useRouter()
const [currentLocation, setCurrentLocation] = useState([0, 0])
const { id, autoShare, from } = params
const { fetchUserInfo, updateUserInfo } = useUserActions()
console.log('from', from)
@@ -115,6 +151,7 @@ function Index() {
useDidShow(async () => {
await updateLocation()
await fetchUserInfo()
await fetchDetail()
// calcBgMainColors()
})
@@ -122,7 +159,8 @@ function Index() {
const updateLocation = async () => {
try {
const location = await getCurrentLocation()
await updateUserProfile({ latitude: location.latitude, longitude: location.longitude })
setCurrentLocation([location.latitude, location.longitude])
await updateUserInfo({ latitude: location.latitude, longitude: location.longitude })
console.log('用户位置更新成功')
} catch (error) {
console.error('用户位置更新失败', error)
@@ -130,7 +168,7 @@ function Index() {
}
const fetchDetail = async () => {
const res = await DetailService.getDetail(Number(id))
const res = await DetailService.getDetail(242/* Number(id) */)
if (res.code === 0) {
console.log(res.data)
setDetail(res.data)
@@ -156,8 +194,8 @@ function Index() {
const openMap = () => {
Taro.openLocation({
latitude: detail?.latitude, // 纬度(必填)
longitude: detail?.longitude, // 经度(必填)
latitude: detail?.longitude, // 纬度(必填)
longitude: detail?.latitude, // 经度(必填)
name: '上海体育场', // 位置名(可选)
address: '上海市徐汇区肇嘉浜路128号', // 地址详情(可选)
scale: 15, // 地图缩放级别1-28
@@ -188,6 +226,8 @@ function Index() {
const { title, longitude, latitude } = detail || {}
console.log(longitude, latitude, 2222)
const requirements = [{
title: 'NTRP水平要求',
desc: '2.0 - 4.5 之间',
@@ -245,6 +285,7 @@ function Index() {
},
]
console.log('detail', detail)
return (
<View className='detail-page'>
{/* custom navbar */}
@@ -376,15 +417,20 @@ function Index() {
</View>
{/* venue map */}
<View className='location-map'>
<Map
className='location-map-map'
longitude={longitude}
latitude={latitude}
onError={() => {}}
// hide business msg
showLocation
theme='dark'
/>
{longitude && latitude && (
<Map
className='location-map-map'
longitude={latitude}
latitude={longitude}
markers={[{ id: 1, latitude: longitude, longitude: latitude, iconPath: require('@/static/detail/icon-stark.svg'), width: 16, height: 16 }]}
includePoints={[{ latitude: longitude, longitude: latitude }, { latitude: currentLocation[0], longitude: currentLocation[1] }]}
includePadding={{ left: 50, right: 50, top: 50, bottom: 50 }}
onError={() => {}}
// hide business msg
showLocation
theme='dark'
/>
)}
</View>
</View>
</View>
@@ -565,26 +611,7 @@ function Index() {
</View>
</View>
{/* sticky bottom action bar */}
<View className="sticky-bottom-bar">
<View className="sticky-bottom-bar-share-and-comment">
<View className='sticky-bottom-bar-share' onClick={handleShare}>
<Image className='sticky-bottom-bar-share-icon' src={img.ICON_DETAIL_SHARE} />
<Text className='sticky-bottom-bar-share-text'></Text>
</View>
<View className='sticky-bottom-bar-share-and-comment-separator' />
<View className='sticky-bottom-bar-comment' onClick={() => { Taro.showToast({ title: 'To be continued', icon: 'none' }) }}>
<Image className='sticky-bottom-bar-comment-icon' src={img.ICON_DETAIL_COMMENT_DARK} />
<Text className='sticky-bottom-bar-comment-text'>32</Text>
</View>
</View>
<View className="sticky-bottom-bar-join-game" onClick={handleJoinGame}>
<Text>🎾</Text>
<Text></Text>
<View className='game-price'>
<Text>¥ 65</Text>
</View>
</View>
</View>
<StickyButton handleShare={handleShare} handleJoinGame={handleJoinGame} detail={detail} />
{/* share popup */}
<SharePopup ref={sharePopupRef} id={id as string} from={from as string} />
</View>

View File

@@ -1,5 +1,5 @@
import Taro from '@tarojs/taro';
import httpService from './httpService';
import httpService, { ApiResponse } from './httpService';
import tokenManager from '../utils/tokenManager';
// 微信用户信息接口
@@ -34,8 +34,26 @@ export interface VerifyCodeResponse {
token?: string;
user_info?: WechatUserInfo;
}
// 用户详细信息
export interface UserInfoType {
id: number
openid: string
unionid: string
session_key: string
nickname: string
avatar_url: string
gender: string
country: string
province: string
city: string
language: string
phone: string
is_subscribed: string
latitude: number
longitude: number
subscribe_time: string
last_login_time: string
}
// 微信授权登录
@@ -332,8 +350,19 @@ export const refresh_login_status = async (): Promise<boolean> => {
}
};
// 获取用户详细信息
export const fetchUserProfile = async (): Promise<ApiResponse<UserInfoType>> => {
try {
const response = await httpService.post('/user/detail');
return response;
} catch (error) {
console.error('获取用户信息失败:', error);
throw error;
}
};
// 更新用户信息
export const updateUserProfile = async (payload: Partial<WechatUserInfo> & { latitude?: number; longitude?: number; }) => {
export const updateUserProfile = async (payload: Partial<UserInfoType>) => {
try {
const response = await httpService.post('user/update', payload);
return response;

View File

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12" fill="none">
<path d="M2.324 11.4521C2.00189 11.2179 1.82886 10.8309 1.8696 10.4357L2.15096 7.70601L0.287363 5.64062C0.0200831 5.3444 -0.0686262 4.92874 0.054557 4.54977C0.17774 4.17079 0.494164 3.8859 0.88497 3.80209L3.40903 3.26084C3.5459 3.23149 3.6642 3.1461 3.73517 3.02544L5.03312 0.818684C5.23426 0.476709 5.60222 0.266602 6 0.266602C6.39777 0.266602 6.76574 0.476709 6.96688 0.818683L8.26483 3.02544C8.3358 3.1461 8.4541 3.23149 8.59097 3.26084L11.115 3.80209C11.5058 3.8859 11.8223 4.17079 11.9454 4.54977C12.0686 4.92874 11.9799 5.3444 11.7126 5.64062L9.84904 7.70601L10.1304 10.4357C10.1711 10.8309 9.99811 11.2179 9.67599 11.4521C9.35388 11.6862 8.9312 11.7322 8.56599 11.5728L6.19998 10.5403C6.07246 10.4847 5.92753 10.4847 5.80002 10.5403L3.43401 11.5728C3.0688 11.7322 2.64612 11.6862 2.324 11.4521Z" fill="#FFCC00"/>
</svg>

After

Width:  |  Height:  |  Size: 924 B

View File

@@ -1,58 +1,47 @@
import { create } from 'zustand'
import { fetchUserProfile, updateUserProfile, UserInfoType } from '@/services/loginService'
// 用户统计信息
export interface UserStats {
requestCount: number
matchesCreated: number
matchesJoined: number
lastActiveTime: string
export interface UserState {
user: UserInfoType
fetchUserInfo: () => Promise<void>
updateUserInfo: (userInfo: Partial<UserInfoType>) => void
}
// Store 状态接口
interface UserState {
userStats: UserStats
incrementRequestCount: () => void
resetUserStats: () => void
}
// 创建适配 Zustand 4.x 的 store
export const useUserStore = create<UserState>()((set) => ({
// 初始状态
userStats: {
requestCount: 0,
matchesCreated: 0,
matchesJoined: 0,
lastActiveTime: new Date().toISOString()
export const useUser = create<UserState>()((set) => ({
user: {
id: 0,
"openid": "",
"unionid": "",
"session_key": "",
"nickname": "张三",
"avatar_url": "https://example.com/avatar.jpg",
"gender": "",
"country": "",
"province": "",
"city": "",
"language": "",
"phone": "13800138000",
"is_subscribed": "0",
"latitude": 0,
"longitude": 0,
"subscribe_time": "2024-06-15 14:00:00",
"last_login_time": "2024-06-15 14:00:00"
},
// Actions
incrementRequestCount: () => {
console.log('store: incrementRequestCount 被调用')
set((state) => ({
userStats: {
...state.userStats,
requestCount: state.userStats.requestCount + 1,
lastActiveTime: new Date().toISOString()
}
}))
fetchUserInfo: async () => {
const res = await fetchUserProfile()
console.log(res)
set({ user: res.data })
},
resetUserStats: () => {
console.log('store: resetUserStats 被调用')
set({
userStats: {
requestCount: 0,
matchesCreated: 0,
matchesJoined: 0,
lastActiveTime: new Date().toISOString()
}
})
updateUserInfo: async(userInfo: Partial<UserInfoType>) => {
const res = await updateUserProfile(userInfo)
console.log(res)
set({ user: res.data })
}
}))
// 简单的 hooks
export const useUserStats = () => useUserStore((state) => state.userStats)
export const useUserActions = () => useUserStore((state) => ({
incrementRequestCount: state.incrementRequestCount,
resetUserStats: state.resetUserStats
}))
export const useUserInfo = () => useUser((state) => state.user)
export const useUserActions = () => useUser((state) => ({
fetchUserInfo: state.fetchUserInfo,
updateUserInfo: state.updateUserInfo
}))