Merge branch 'feat/liujie'
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'
|
import Taro, { useRouter, useShareAppMessage, useShareTimeline, useDidShow } from '@tarojs/taro'
|
||||||
// 导入API服务
|
// 导入API服务
|
||||||
import DetailService from '../../services/detailService'
|
import DetailService from '../../services/detailService'
|
||||||
import { updateUserProfile } from '../../services/loginService'
|
import { updateUserProfile, get_user_info } from '../../services/loginService'
|
||||||
import { getCurrentLocation } from '../../utils/locationUtils'
|
import { getCurrentLocation } from '../../utils/locationUtils'
|
||||||
import {
|
import {
|
||||||
useUserStats,
|
useUserInfo,
|
||||||
useUserActions
|
useUserActions,
|
||||||
} from '../../store/userStore'
|
} from '../../store/userStore'
|
||||||
import img from '../../config/images'
|
import img from '../../config/images'
|
||||||
import { getTextColorOnImage } from '../../utils'
|
import { getTextColorOnImage } from '../../utils'
|
||||||
@@ -25,6 +25,7 @@ function insertDotInTags(tags: string[]) {
|
|||||||
return tags.join('-·-').split('-')
|
return tags.join('-·-').split('-')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 分享弹窗
|
||||||
const SharePopup = forwardRef(({ id, from }: { id: string, from: string }, ref) => {
|
const SharePopup = forwardRef(({ id, from }: { id: string, from: string }, ref) => {
|
||||||
const [visible, setVisible] = useState(false)
|
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() {
|
function Index() {
|
||||||
// 使用Zustand store
|
// 使用Zustand store
|
||||||
// const userStats = useUserStats()
|
// const userStats = useUserStats()
|
||||||
@@ -99,7 +133,9 @@ function Index() {
|
|||||||
// const [textColor, setTextColor] = useState<string []>([])
|
// const [textColor, setTextColor] = useState<string []>([])
|
||||||
const [detail, setDetail] = useState<any>(null)
|
const [detail, setDetail] = useState<any>(null)
|
||||||
const { params } = useRouter()
|
const { params } = useRouter()
|
||||||
|
const [currentLocation, setCurrentLocation] = useState([0, 0])
|
||||||
const { id, autoShare, from } = params
|
const { id, autoShare, from } = params
|
||||||
|
const { fetchUserInfo, updateUserInfo } = useUserActions()
|
||||||
|
|
||||||
console.log('from', from)
|
console.log('from', from)
|
||||||
|
|
||||||
@@ -115,6 +151,7 @@ function Index() {
|
|||||||
|
|
||||||
useDidShow(async () => {
|
useDidShow(async () => {
|
||||||
await updateLocation()
|
await updateLocation()
|
||||||
|
await fetchUserInfo()
|
||||||
await fetchDetail()
|
await fetchDetail()
|
||||||
// calcBgMainColors()
|
// calcBgMainColors()
|
||||||
})
|
})
|
||||||
@@ -122,7 +159,8 @@ function Index() {
|
|||||||
const updateLocation = async () => {
|
const updateLocation = async () => {
|
||||||
try {
|
try {
|
||||||
const location = await getCurrentLocation()
|
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('用户位置更新成功')
|
console.log('用户位置更新成功')
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('用户位置更新失败', error)
|
console.error('用户位置更新失败', error)
|
||||||
@@ -130,7 +168,7 @@ function Index() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const fetchDetail = async () => {
|
const fetchDetail = async () => {
|
||||||
const res = await DetailService.getDetail(Number(id))
|
const res = await DetailService.getDetail(242/* Number(id) */)
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
console.log(res.data)
|
console.log(res.data)
|
||||||
setDetail(res.data)
|
setDetail(res.data)
|
||||||
@@ -156,8 +194,8 @@ function Index() {
|
|||||||
|
|
||||||
const openMap = () => {
|
const openMap = () => {
|
||||||
Taro.openLocation({
|
Taro.openLocation({
|
||||||
latitude: detail?.latitude, // 纬度(必填)
|
latitude: detail?.longitude, // 纬度(必填)
|
||||||
longitude: detail?.longitude, // 经度(必填)
|
longitude: detail?.latitude, // 经度(必填)
|
||||||
name: '上海体育场', // 位置名(可选)
|
name: '上海体育场', // 位置名(可选)
|
||||||
address: '上海市徐汇区肇嘉浜路128号', // 地址详情(可选)
|
address: '上海市徐汇区肇嘉浜路128号', // 地址详情(可选)
|
||||||
scale: 15, // 地图缩放级别(1-28)
|
scale: 15, // 地图缩放级别(1-28)
|
||||||
@@ -188,6 +226,8 @@ function Index() {
|
|||||||
|
|
||||||
const { title, longitude, latitude } = detail || {}
|
const { title, longitude, latitude } = detail || {}
|
||||||
|
|
||||||
|
console.log(longitude, latitude, 2222)
|
||||||
|
|
||||||
const requirements = [{
|
const requirements = [{
|
||||||
title: 'NTRP水平要求',
|
title: 'NTRP水平要求',
|
||||||
desc: '2.0 - 4.5 之间',
|
desc: '2.0 - 4.5 之间',
|
||||||
@@ -245,6 +285,7 @@ function Index() {
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
console.log('detail', detail)
|
||||||
return (
|
return (
|
||||||
<View className='detail-page'>
|
<View className='detail-page'>
|
||||||
{/* custom navbar */}
|
{/* custom navbar */}
|
||||||
@@ -376,15 +417,20 @@ function Index() {
|
|||||||
</View>
|
</View>
|
||||||
{/* venue map */}
|
{/* venue map */}
|
||||||
<View className='location-map'>
|
<View className='location-map'>
|
||||||
|
{longitude && latitude && (
|
||||||
<Map
|
<Map
|
||||||
className='location-map-map'
|
className='location-map-map'
|
||||||
longitude={longitude}
|
longitude={latitude}
|
||||||
latitude={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={() => {}}
|
onError={() => {}}
|
||||||
// hide business msg
|
// hide business msg
|
||||||
showLocation
|
showLocation
|
||||||
theme='dark'
|
theme='dark'
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
@@ -565,26 +611,7 @@ function Index() {
|
|||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
{/* sticky bottom action bar */}
|
{/* sticky bottom action bar */}
|
||||||
<View className="sticky-bottom-bar">
|
<StickyButton handleShare={handleShare} handleJoinGame={handleJoinGame} detail={detail} />
|
||||||
<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>
|
|
||||||
{/* share popup */}
|
{/* share popup */}
|
||||||
<SharePopup ref={sharePopupRef} id={id as string} from={from as string} />
|
<SharePopup ref={sharePopupRef} id={id as string} from={from as string} />
|
||||||
</View>
|
</View>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import Taro from '@tarojs/taro';
|
import Taro from '@tarojs/taro';
|
||||||
import httpService from './httpService';
|
import httpService, { ApiResponse } from './httpService';
|
||||||
import tokenManager from '../utils/tokenManager';
|
import tokenManager from '../utils/tokenManager';
|
||||||
|
|
||||||
// 微信用户信息接口
|
// 微信用户信息接口
|
||||||
@@ -34,8 +34,26 @@ export interface VerifyCodeResponse {
|
|||||||
token?: string;
|
token?: string;
|
||||||
user_info?: WechatUserInfo;
|
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 {
|
try {
|
||||||
const response = await httpService.post('user/update', payload);
|
const response = await httpService.post('user/update', payload);
|
||||||
return response;
|
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 { create } from 'zustand'
|
||||||
|
import { fetchUserProfile, updateUserProfile, UserInfoType } from '@/services/loginService'
|
||||||
|
|
||||||
// 用户统计信息
|
export interface UserState {
|
||||||
export interface UserStats {
|
user: UserInfoType
|
||||||
requestCount: number
|
fetchUserInfo: () => Promise<void>
|
||||||
matchesCreated: number
|
updateUserInfo: (userInfo: Partial<UserInfoType>) => void
|
||||||
matchesJoined: number
|
|
||||||
lastActiveTime: string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store 状态接口
|
export const useUser = create<UserState>()((set) => ({
|
||||||
interface UserState {
|
user: {
|
||||||
userStats: UserStats
|
id: 0,
|
||||||
incrementRequestCount: () => void
|
"openid": "",
|
||||||
resetUserStats: () => void
|
"unionid": "",
|
||||||
}
|
"session_key": "",
|
||||||
|
"nickname": "张三",
|
||||||
// 创建适配 Zustand 4.x 的 store
|
"avatar_url": "https://example.com/avatar.jpg",
|
||||||
export const useUserStore = create<UserState>()((set) => ({
|
"gender": "",
|
||||||
// 初始状态
|
"country": "",
|
||||||
userStats: {
|
"province": "",
|
||||||
requestCount: 0,
|
"city": "",
|
||||||
matchesCreated: 0,
|
"language": "",
|
||||||
matchesJoined: 0,
|
"phone": "13800138000",
|
||||||
lastActiveTime: new Date().toISOString()
|
"is_subscribed": "0",
|
||||||
|
"latitude": 0,
|
||||||
|
"longitude": 0,
|
||||||
|
"subscribe_time": "2024-06-15 14:00:00",
|
||||||
|
"last_login_time": "2024-06-15 14:00:00"
|
||||||
},
|
},
|
||||||
|
fetchUserInfo: async () => {
|
||||||
// Actions
|
const res = await fetchUserProfile()
|
||||||
incrementRequestCount: () => {
|
console.log(res)
|
||||||
console.log('store: incrementRequestCount 被调用')
|
set({ user: res.data })
|
||||||
set((state) => ({
|
|
||||||
userStats: {
|
|
||||||
...state.userStats,
|
|
||||||
requestCount: state.userStats.requestCount + 1,
|
|
||||||
lastActiveTime: new Date().toISOString()
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
},
|
},
|
||||||
|
updateUserInfo: async(userInfo: Partial<UserInfoType>) => {
|
||||||
resetUserStats: () => {
|
const res = await updateUserProfile(userInfo)
|
||||||
console.log('store: resetUserStats 被调用')
|
console.log(res)
|
||||||
set({
|
set({ user: res.data })
|
||||||
userStats: {
|
|
||||||
requestCount: 0,
|
|
||||||
matchesCreated: 0,
|
|
||||||
matchesJoined: 0,
|
|
||||||
lastActiveTime: new Date().toISOString()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
|
|
||||||
// 简单的 hooks
|
export const useUserInfo = () => useUser((state) => state.user)
|
||||||
export const useUserStats = () => useUserStore((state) => state.userStats)
|
|
||||||
export const useUserActions = () => useUserStore((state) => ({
|
export const useUserActions = () => useUser((state) => ({
|
||||||
incrementRequestCount: state.incrementRequestCount,
|
fetchUserInfo: state.fetchUserInfo,
|
||||||
resetUserStats: state.resetUserStats
|
updateUserInfo: state.updateUserInfo
|
||||||
}))
|
}))
|
||||||
Reference in New Issue
Block a user