初始化工程

This commit is contained in:
筱野
2025-08-10 21:09:19 +08:00
commit 42c71f5d13
30 changed files with 12882 additions and 0 deletions

199
src/store/README.md Normal file
View File

@@ -0,0 +1,199 @@
# 用户状态管理使用说明
本项目使用 Zustand 进行用户状态管理,提供简洁、高效的用户信息管理解决方案。
## 主要特性
- 🚀 简单易用:无需 Provider 包装,直接使用 hooks
- 🔄 自动持久化:状态变化自动保存到本地存储
- 🎯 TypeScript 友好:完整的类型支持
- 👥 团队协作:清晰的状态结构,易于维护
- 📊 实时统计:自动记录用户活动和 API 请求
## 基本使用
### 1. 获取用户信息
```tsx
import { useUserInfo, useUserStats, useIsLoggedIn } from '../store/userStore'
function MyComponent() {
// 获取用户信息
const userInfo = useUserInfo()
// 获取用户统计数据
const userStats = useUserStats()
// 获取登录状态
const isLoggedIn = useIsLoggedIn()
return (
<div>
<h1> {userInfo?.username}!</h1>
<p>API : {userStats.requestCount}</p>
<p>: {isLoggedIn ? '已登录' : '未登录'}</p>
</div>
)
}
```
### 2. 修改用户信息
```tsx
import { useUserActions } from '../store/userStore'
function MyComponent() {
const {
updateUserInfo,
incrementRequestCount,
incrementMatchesCreated
} = useUserActions()
const handleUpdateUsername = () => {
updateUserInfo('username', '新用户名')
}
const handleApiRequest = () => {
incrementRequestCount() // API 请求计数 +1
}
const handleCreateMatch = () => {
incrementMatchesCreated() // 创建比赛计数 +1
}
return (
<div>
<button onClick={handleUpdateUsername}></button>
<button onClick={handleApiRequest}> API </button>
<button onClick={handleCreateMatch}></button>
</div>
)
}
```
### 3. 模拟 API 请求示例
```tsx
import { useState } from 'react'
import { useUserActions } from '../store/userStore'
function MyComponent() {
const { incrementRequestCount } = useUserActions()
const [loading, setLoading] = useState(false)
const handleSendRequest = async () => {
setLoading(true)
try {
// 模拟网络延迟
await new Promise(resolve => setTimeout(resolve, 1000))
// 更新请求计数
incrementRequestCount()
console.log('请求成功!')
} catch (error) {
console.error('请求失败:', error)
} finally {
setLoading(false)
}
}
return (
<div>
<button onClick={handleSendRequest} disabled={loading}>
{loading ? '发送中...' : '发送请求'}
</button>
</div>
)
}
```
## 数据结构
### UserInfo 接口
```typescript
interface UserInfo {
id: string // 用户唯一标识
username: string // 用户名
avatar: string // 头像 URL
phone: string // 手机号
email: string // 邮箱
location: string // 位置
ntrpLevel: number // NTRP 等级
joinDate: string // 加入日期
totalMatches: number // 总比赛数
winRate: number // 胜率
}
```
### UserStats 接口
```typescript
interface UserStats {
requestCount: number // API 请求次数
matchesCreated: number // 创建的比赛数量
matchesJoined: number // 参加的比赛数量
lastActiveTime: string // 最后活跃时间
}
```
## 可用的 Actions
| Action | 参数 | 说明 |
|--------|------|------|
| `setUserInfo(userInfo)` | userInfo: UserInfo | 设置用户信息 |
| `updateUserInfo(field, value)` | field: keyof UserInfo, value: any | 更新用户信息字段 |
| `clearUserInfo()` | 无 | 清除用户信息(登出) |
| `incrementRequestCount()` | 无 | API 请求计数 +1 |
| `incrementMatchesCreated()` | 无 | 创建比赛计数 +1 |
| `incrementMatchesJoined()` | 无 | 参加比赛计数 +1 |
| `updateLastActiveTime()` | 无 | 更新最后活跃时间 |
| `resetUserStats()` | 无 | 重置用户统计数据 |
| `setLoading(loading)` | loading: boolean | 设置加载状态 |
## 本地存储
- 用户信息保存键值:`user_info`
- 用户统计保存键值:`user_stats`
- 所有状态变化会自动保存到本地存储
- 应用启动时自动加载保存的数据
## 便捷 Hooks
| Hook | 返回值 | 说明 |
|------|--------|------|
| `useUserInfo()` | UserInfo \| null | 获取用户信息 |
| `useUserStats()` | UserStats | 获取用户统计 |
| `useIsLoggedIn()` | boolean | 获取登录状态 |
| `useUserActions()` | Actions | 获取所有操作函数 |
## 最佳实践
1. **优先使用专用 hooks**:使用 `useUserInfo()``useUserActions()` 而不是完整的 `useUserStore()`
2. **按需获取**:只获取组件需要的状态,避免不必要的重渲染
3. **类型安全**:充分利用 TypeScript 类型检查,避免字段名错误
4. **数据纯净**:状态管理只处理数据,不包含业务逻辑
5. **及时更新**:用户操作后及时更新相关统计数据
## 使用示例
查看 `src/pages/index/index.tsx` 获取完整的使用示例,包括:
- 用户信息展示
- 统计数据实时更新
- API 请求模拟
- 加载状态管理
- 数据持久化演示
## 扩展建议
如需添加新的用户状态或功能:
1.`UserInfo``UserStats` 接口中添加新字段
2. 在 store 的初始状态中设置默认值
3. 添加相应的 action 函数
4. 导出便捷的 hooks如果需要
这种设计让用户状态管理既简单又强大,非常适合团队协作开发。

39
src/store/storage.ts Normal file
View File

@@ -0,0 +1,39 @@
import Taro from '@tarojs/taro'
// 通用存储工具函数
export const setStorage = (key: string, data: any) => {
try {
Taro.setStorageSync(key, JSON.stringify(data))
} catch (error) {
console.error('保存数据失败:', error)
}
}
export const getStorage = <T>(key: string): T | null => {
try {
const data = Taro.getStorageSync(key)
if (data) {
return JSON.parse(data)
}
return null
} catch (error) {
console.error('读取数据失败:', error)
return null
}
}
export const removeStorage = (key: string) => {
try {
Taro.removeStorageSync(key)
} catch (error) {
console.error('清除数据失败:', error)
}
}
export const clearAllStorage = () => {
try {
Taro.clearStorageSync()
} catch (error) {
console.error('清除所有数据失败:', error)
}
}

58
src/store/userStore.ts Normal file
View File

@@ -0,0 +1,58 @@
import { create } from 'zustand'
// 用户统计信息
export interface UserStats {
requestCount: number
matchesCreated: number
matchesJoined: number
lastActiveTime: string
}
// 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()
},
// Actions
incrementRequestCount: () => {
console.log('store: incrementRequestCount 被调用')
set((state) => ({
userStats: {
...state.userStats,
requestCount: state.userStats.requestCount + 1,
lastActiveTime: new Date().toISOString()
}
}))
},
resetUserStats: () => {
console.log('store: resetUserStats 被调用')
set({
userStats: {
requestCount: 0,
matchesCreated: 0,
matchesJoined: 0,
lastActiveTime: new Date().toISOString()
}
})
}
}))
// 简单的 hooks
export const useUserStats = () => useUserStore((state) => state.userStats)
export const useUserActions = () => useUserStore((state) => ({
incrementRequestCount: state.incrementRequestCount,
resetUserStats: state.resetUserStats
}))