1
This commit is contained in:
16
src/app.ts
16
src/app.ts
@@ -1,8 +1,11 @@
|
|||||||
import { Component, ReactNode } from 'react'
|
import { Component, ReactNode } from 'react'
|
||||||
|
import Taro from '@tarojs/taro';
|
||||||
import './nutui-theme.scss'
|
import './nutui-theme.scss'
|
||||||
import './app.scss'
|
import './app.scss'
|
||||||
import { useDictionaryStore } from './store/dictionaryStore'
|
import { useDictionaryStore } from './store/dictionaryStore'
|
||||||
import { useGlobalStore } from './store/global'
|
import { useGlobalStore } from './store/global'
|
||||||
|
import { check_login_status } from './services/loginService';
|
||||||
|
|
||||||
|
|
||||||
// import { getNavbarHeight } from "@/utils/getNavbarHeight";
|
// import { getNavbarHeight } from "@/utils/getNavbarHeight";
|
||||||
|
|
||||||
@@ -11,6 +14,19 @@ interface AppProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class App extends Component<AppProps> {
|
class App extends Component<AppProps> {
|
||||||
|
|
||||||
|
|
||||||
|
onLaunch() {
|
||||||
|
console.log('小程序启动,初始化逻辑写这里')
|
||||||
|
// 已经登录过就跳转到 列表页
|
||||||
|
let is_login = check_login_status()
|
||||||
|
if (is_login) {
|
||||||
|
Taro.redirectTo({
|
||||||
|
url: '/pages/list/index'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
// 初始化字典数据
|
// 初始化字典数据
|
||||||
this.initDictionaryData()
|
this.initDictionaryData()
|
||||||
|
|||||||
@@ -1,301 +0,0 @@
|
|||||||
import React, { useState, useEffect } from 'react'
|
|
||||||
import { View, Text, Button } from '@tarojs/components'
|
|
||||||
import { Cell, Avatar, Progress } from '@nutui/nutui-react-taro'
|
|
||||||
import Taro from '@tarojs/taro'
|
|
||||||
// 导入API服务
|
|
||||||
import demoApi from '../../services/demoApi'
|
|
||||||
import commonApi from '../../services/commonApi'
|
|
||||||
import PublishMenu from '../../components/PublishMenu'
|
|
||||||
import {
|
|
||||||
useUserStats,
|
|
||||||
useUserActions
|
|
||||||
} from '../../store/userStore'
|
|
||||||
import './index.scss'
|
|
||||||
|
|
||||||
function Index() {
|
|
||||||
// 使用Zustand store
|
|
||||||
const userStats = useUserStats()
|
|
||||||
const { incrementRequestCount, resetUserStats } = useUserActions()
|
|
||||||
|
|
||||||
// 本地状态管理
|
|
||||||
const [loading, setLoading] = useState(false)
|
|
||||||
const [userProfile, setUserProfile] = useState<any>(null)
|
|
||||||
const [interests, setInterests] = useState<string[]>([])
|
|
||||||
|
|
||||||
// 页面加载时获取数据
|
|
||||||
useEffect(() => {
|
|
||||||
initializeData()
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
// 初始化数据
|
|
||||||
const initializeData = async () => {
|
|
||||||
try {
|
|
||||||
// 获取推荐的兴趣爱好
|
|
||||||
const interestsRes = await demoApi.getRecommendedInterests()
|
|
||||||
if (interestsRes.success) {
|
|
||||||
setInterests(interestsRes.data || [])
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.log('获取初始数据失败:', error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 1. 获取用户信息 API 请求
|
|
||||||
const handleGetUserProfile = async () => {
|
|
||||||
console.log('获取用户信息...');
|
|
||||||
setLoading(true)
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await demoApi.getUserProfile()
|
|
||||||
|
|
||||||
if (response.success) {
|
|
||||||
setUserProfile(response.data)
|
|
||||||
incrementRequestCount()
|
|
||||||
|
|
||||||
Taro.showToast({
|
|
||||||
title: '获取用户信息成功',
|
|
||||||
icon: 'success'
|
|
||||||
})
|
|
||||||
|
|
||||||
console.log('用户信息:', response.data)
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('获取用户信息失败:', error)
|
|
||||||
Taro.showToast({
|
|
||||||
title: '获取失败,使用模拟数据',
|
|
||||||
icon: 'none'
|
|
||||||
})
|
|
||||||
|
|
||||||
// 模拟数据
|
|
||||||
setUserProfile({
|
|
||||||
id: '123',
|
|
||||||
nickname: '网球爱好者',
|
|
||||||
avatar: '',
|
|
||||||
gender: 'male',
|
|
||||||
interests: interests.slice(0, 3)
|
|
||||||
})
|
|
||||||
incrementRequestCount()
|
|
||||||
} finally {
|
|
||||||
setLoading(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. 提交统计数据 API 请求
|
|
||||||
const handleSubmitStats = async () => {
|
|
||||||
console.log('提交统计数据...');
|
|
||||||
setLoading(true)
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await commonApi.submitForm('userStats', [
|
|
||||||
{
|
|
||||||
type: 'userStats',
|
|
||||||
data: {
|
|
||||||
requestCount: userStats.requestCount,
|
|
||||||
matchesCreated: userStats.matchesCreated,
|
|
||||||
matchesJoined: userStats.matchesJoined,
|
|
||||||
lastActiveTime: userStats.lastActiveTime,
|
|
||||||
userId: userProfile?.id || 'guest'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
])
|
|
||||||
|
|
||||||
if (response.success) {
|
|
||||||
incrementRequestCount()
|
|
||||||
|
|
||||||
Taro.showToast({
|
|
||||||
title: '统计数据提交成功',
|
|
||||||
icon: 'success'
|
|
||||||
})
|
|
||||||
|
|
||||||
console.log('提交结果:', response.data)
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('提交统计数据失败:', error)
|
|
||||||
incrementRequestCount() // 即使失败也计数,用于演示
|
|
||||||
|
|
||||||
Taro.showToast({
|
|
||||||
title: '网络模拟提交成功',
|
|
||||||
icon: 'success'
|
|
||||||
})
|
|
||||||
} finally {
|
|
||||||
setLoading(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. 提交反馈 API 请求
|
|
||||||
const handleSubmitFeedback = async () => {
|
|
||||||
console.log('提交用户反馈...');
|
|
||||||
setLoading(true)
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await demoApi.submitFeedback({
|
|
||||||
matchId: 'demo_match_' + Date.now(),
|
|
||||||
rating: 5,
|
|
||||||
recommend: 'yes',
|
|
||||||
aspects: ['场地环境', '服务质量', '价格合理'],
|
|
||||||
comments: `用户反馈 - 请求次数: ${userStats.requestCount + 1},体验良好!`
|
|
||||||
})
|
|
||||||
|
|
||||||
if (response.success) {
|
|
||||||
incrementRequestCount()
|
|
||||||
|
|
||||||
Taro.showToast({
|
|
||||||
title: '反馈提交成功',
|
|
||||||
icon: 'success'
|
|
||||||
})
|
|
||||||
|
|
||||||
console.log('反馈结果:', response.data)
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('提交反馈失败:', error)
|
|
||||||
incrementRequestCount() // 即使失败也计数,用于演示
|
|
||||||
|
|
||||||
Taro.showToast({
|
|
||||||
title: '网络模拟提交成功',
|
|
||||||
icon: 'success'
|
|
||||||
})
|
|
||||||
} finally {
|
|
||||||
setLoading(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 重置所有数据
|
|
||||||
const handleResetAllData = () => {
|
|
||||||
console.log('重置所有数据...');
|
|
||||||
resetUserStats()
|
|
||||||
setUserProfile(null)
|
|
||||||
|
|
||||||
Taro.showToast({
|
|
||||||
title: '数据已重置',
|
|
||||||
icon: 'success'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<View className='index-page'>
|
|
||||||
{/* 页面标题 */}
|
|
||||||
<View className='page-header'>
|
|
||||||
<Text className='page-title'>API 请求演示</Text>
|
|
||||||
<Text className='page-subtitle'>真实网络请求功能测试</Text>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
{/* 用户信息卡片 */}
|
|
||||||
<View className='user-card'>
|
|
||||||
<View className='user-header'>
|
|
||||||
<Avatar
|
|
||||||
size="large"
|
|
||||||
src={userProfile?.avatar || ''}
|
|
||||||
style={{ backgroundColor: '#fa2c19' }}
|
|
||||||
>
|
|
||||||
{userProfile?.nickname?.charAt(0) || 'U'}
|
|
||||||
</Avatar>
|
|
||||||
<View className='user-info'>
|
|
||||||
<Text className='username'>
|
|
||||||
{userProfile?.nickname || '点击获取用户信息'}
|
|
||||||
</Text>
|
|
||||||
<Text className='user-level'>
|
|
||||||
性别: {userProfile?.gender === 'male' ? '男' : userProfile?.gender === 'female' ? '女' : '未知'}
|
|
||||||
</Text>
|
|
||||||
<Text className='join-date'>
|
|
||||||
兴趣: {userProfile?.interests?.join(', ') || '暂无'}
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
{/* 统计数据 */}
|
|
||||||
<View className='stats-section'>
|
|
||||||
<Text className='section-title'>📊 API 请求统计</Text>
|
|
||||||
|
|
||||||
<Cell title="API 请求次数" extra={userStats.requestCount} />
|
|
||||||
<Cell title="创建的比赛" extra={userStats.matchesCreated} />
|
|
||||||
<Cell title="参加的比赛" extra={userStats.matchesJoined} />
|
|
||||||
<Cell
|
|
||||||
title="最后活跃时间"
|
|
||||||
extra={new Date(userStats.lastActiveTime).toLocaleTimeString()}
|
|
||||||
/>
|
|
||||||
{interests.length > 0 && (
|
|
||||||
<Cell
|
|
||||||
title="推荐兴趣"
|
|
||||||
extra={interests.slice(0, 2).join(', ')}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</View>
|
|
||||||
|
|
||||||
{/* API 请求按钮区域 */}
|
|
||||||
<View className='action-section'>
|
|
||||||
<Text className='section-title'>🚀 API 请求功能</Text>
|
|
||||||
|
|
||||||
<View className='button-group'>
|
|
||||||
<Button
|
|
||||||
type="primary"
|
|
||||||
loading={loading}
|
|
||||||
onClick={handleGetUserProfile}
|
|
||||||
disabled={loading}
|
|
||||||
className="custom-button primary-btn"
|
|
||||||
>
|
|
||||||
{loading ? '请求中...' : '获取用户信息'}
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
type="default"
|
|
||||||
loading={loading}
|
|
||||||
onClick={handleSubmitStats}
|
|
||||||
disabled={loading}
|
|
||||||
className="custom-button success-btn"
|
|
||||||
>
|
|
||||||
{loading ? '提交中...' : '提交统计数据'}
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
type="default"
|
|
||||||
loading={loading}
|
|
||||||
onClick={handleSubmitFeedback}
|
|
||||||
disabled={loading}
|
|
||||||
className="custom-button warning-btn"
|
|
||||||
>
|
|
||||||
{loading ? '提交中...' : '提交用户反馈'}
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
type="warn"
|
|
||||||
onClick={handleResetAllData}
|
|
||||||
disabled={loading}
|
|
||||||
className="custom-button warning-btn"
|
|
||||||
>
|
|
||||||
重置所有数据
|
|
||||||
</Button>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
{/* 实时进度显示 */}
|
|
||||||
{loading && (
|
|
||||||
<View className='loading-section'>
|
|
||||||
<Text className='loading-text'>正在发送 API 请求...</Text>
|
|
||||||
<Progress percent={100} animated />
|
|
||||||
</View>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* 提示信息 */}
|
|
||||||
<View className='tips-section'>
|
|
||||||
<Text className='tips-title'>💡 API 功能说明</Text>
|
|
||||||
<View className='tips-content'>
|
|
||||||
<Text className='tip-item'>• "获取用户信息" - 调用用户资料 API</Text>
|
|
||||||
<Text className='tip-item'>• "提交统计数据" - 发送统计到服务器</Text>
|
|
||||||
<Text className='tip-item'>• "提交用户反馈" - 发送用户评价数据</Text>
|
|
||||||
<Text className='tip-item'>• 所有请求都会增加 API 计数统计</Text>
|
|
||||||
<Text className='tip-item'>• 请求失败时会自动使用模拟数据</Text>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
<PublishMenu
|
|
||||||
onPersonalPublish={() => {
|
|
||||||
Taro.navigateTo({
|
|
||||||
url: '/pages/publishBall/index'
|
|
||||||
})
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Index
|
|
||||||
@@ -9,13 +9,8 @@ const LoginPage: React.FC = () => {
|
|||||||
const [agree_terms, set_agree_terms] = useState(false);
|
const [agree_terms, set_agree_terms] = useState(false);
|
||||||
const [show_terms_layer, set_show_terms_layer] = useState(false);
|
const [show_terms_layer, set_show_terms_layer] = useState(false);
|
||||||
|
|
||||||
let is_login = check_login_status()
|
|
||||||
|
|
||||||
if (is_login) {
|
|
||||||
Taro.redirectTo({
|
|
||||||
url: '/pages/login/index'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 微信授权登录
|
// 微信授权登录
|
||||||
const handle_wechat_login = async (e: any) => {
|
const handle_wechat_login = async (e: any) => {
|
||||||
|
|||||||
@@ -1,176 +0,0 @@
|
|||||||
import httpService from './httpService'
|
|
||||||
import tokenManager from '../utils/tokenManager'
|
|
||||||
import type { ApiResponse } from './httpService'
|
|
||||||
|
|
||||||
// 用户接口
|
|
||||||
export interface User {
|
|
||||||
id: string
|
|
||||||
nickname: string
|
|
||||||
avatar?: string
|
|
||||||
phone?: string
|
|
||||||
email?: string
|
|
||||||
status: 'active' | 'inactive' | 'banned'
|
|
||||||
createdAt: string
|
|
||||||
updatedAt: string
|
|
||||||
}
|
|
||||||
|
|
||||||
// 登录响应接口
|
|
||||||
export interface LoginResponse {
|
|
||||||
token: string
|
|
||||||
refreshToken: string
|
|
||||||
user: User
|
|
||||||
expiresAt: number
|
|
||||||
}
|
|
||||||
|
|
||||||
// 认证服务类
|
|
||||||
class AuthService {
|
|
||||||
// 用户登录
|
|
||||||
async login(data: { phone: string; code: string }): Promise<ApiResponse<LoginResponse>> {
|
|
||||||
const response = await httpService.post('/auth/login', data, {
|
|
||||||
needAuth: false,
|
|
||||||
showLoading: true,
|
|
||||||
loadingText: '登录中...'
|
|
||||||
})
|
|
||||||
|
|
||||||
// 登录成功后保存token
|
|
||||||
if (response.success && response.data) {
|
|
||||||
tokenManager.setToken({
|
|
||||||
accessToken: response.data.token,
|
|
||||||
refreshToken: response.data.refreshToken,
|
|
||||||
expiresAt: response.data.expiresAt
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return response
|
|
||||||
}
|
|
||||||
|
|
||||||
// 发送验证码
|
|
||||||
async sendSmsCode(phone: string): Promise<ApiResponse<{ success: boolean }>> {
|
|
||||||
return httpService.post('/auth/sms-code', { phone }, {
|
|
||||||
needAuth: false,
|
|
||||||
showLoading: true,
|
|
||||||
loadingText: '发送中...'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 刷新token
|
|
||||||
async refreshToken(): Promise<ApiResponse<{ token: string; expiresAt: number }>> {
|
|
||||||
const refreshToken = tokenManager.getRefreshToken()
|
|
||||||
if (!refreshToken) {
|
|
||||||
throw new Error('没有刷新令牌')
|
|
||||||
}
|
|
||||||
|
|
||||||
const response = await httpService.post('/auth/refresh', {
|
|
||||||
refreshToken
|
|
||||||
}, {
|
|
||||||
needAuth: false
|
|
||||||
})
|
|
||||||
|
|
||||||
// 更新token
|
|
||||||
if (response.success && response.data) {
|
|
||||||
tokenManager.setToken({
|
|
||||||
accessToken: response.data.token,
|
|
||||||
expiresAt: response.data.expiresAt
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return response
|
|
||||||
}
|
|
||||||
|
|
||||||
// 用户登出
|
|
||||||
async logout(): Promise<void> {
|
|
||||||
try {
|
|
||||||
// 调用登出接口
|
|
||||||
await httpService.post('/auth/logout', {}, {
|
|
||||||
showLoading: true,
|
|
||||||
loadingText: '退出中...'
|
|
||||||
})
|
|
||||||
} catch (error) {
|
|
||||||
console.error('登出接口调用失败:', error)
|
|
||||||
} finally {
|
|
||||||
// 清除本地token
|
|
||||||
tokenManager.clearTokens()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取当前用户信息
|
|
||||||
async getCurrentUser(): Promise<ApiResponse<User>> {
|
|
||||||
return httpService.get('/auth/me')
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新用户信息
|
|
||||||
async updateProfile(data: Partial<User>): Promise<ApiResponse<User>> {
|
|
||||||
return httpService.put('/auth/profile', data, {
|
|
||||||
showLoading: true,
|
|
||||||
loadingText: '更新中...'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 修改密码
|
|
||||||
async changePassword(data: {
|
|
||||||
oldPassword: string
|
|
||||||
newPassword: string
|
|
||||||
}): Promise<ApiResponse<{ success: boolean }>> {
|
|
||||||
return httpService.put('/auth/password', data, {
|
|
||||||
showLoading: true,
|
|
||||||
loadingText: '修改中...'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 绑定手机号
|
|
||||||
async bindPhone(data: {
|
|
||||||
phone: string
|
|
||||||
code: string
|
|
||||||
}): Promise<ApiResponse<{ success: boolean }>> {
|
|
||||||
return httpService.post('/auth/bind-phone', data, {
|
|
||||||
showLoading: true,
|
|
||||||
loadingText: '绑定中...'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 解绑手机号
|
|
||||||
async unbindPhone(data: {
|
|
||||||
code: string
|
|
||||||
}): Promise<ApiResponse<{ success: boolean }>> {
|
|
||||||
return httpService.post('/auth/unbind-phone', data, {
|
|
||||||
showLoading: true,
|
|
||||||
loadingText: '解绑中...'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查登录状态
|
|
||||||
isLoggedIn(): boolean {
|
|
||||||
return tokenManager.hasValidToken()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取当前用户token
|
|
||||||
getToken(): string | null {
|
|
||||||
return tokenManager.getAccessToken()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 清除登录状态
|
|
||||||
clearAuth(): void {
|
|
||||||
tokenManager.clearTokens()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 账号注销
|
|
||||||
async deleteAccount(data: {
|
|
||||||
password: string
|
|
||||||
code: string
|
|
||||||
}): Promise<ApiResponse<{ success: boolean }>> {
|
|
||||||
const response = await httpService.delete('/auth/account', data, {
|
|
||||||
showLoading: true,
|
|
||||||
loadingText: '注销中...'
|
|
||||||
})
|
|
||||||
|
|
||||||
// 注销成功后清除本地数据
|
|
||||||
if (response.success) {
|
|
||||||
this.clearAuth()
|
|
||||||
}
|
|
||||||
|
|
||||||
return response
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 导出认证服务实例
|
|
||||||
export default new AuthService()
|
|
||||||
@@ -35,6 +35,9 @@ export interface VerifyCodeResponse {
|
|||||||
user_info?: WechatUserInfo;
|
user_info?: WechatUserInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 微信授权登录
|
// 微信授权登录
|
||||||
export const wechat_auth_login = async (phone_code?: string): Promise<LoginResponse> => {
|
export const wechat_auth_login = async (phone_code?: string): Promise<LoginResponse> => {
|
||||||
try {
|
try {
|
||||||
|
|||||||
Reference in New Issue
Block a user