feat: get user detail info
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
|
||||
3
src/static/detail/icon-stark.svg
Normal file
3
src/static/detail/icon-stark.svg
Normal 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 |
@@ -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
|
||||
}))
|
||||
|
||||
Reference in New Issue
Block a user