状态管理
概述
项目使用 Pinia 作为状态管理方案,全局仅定义了一个 Store 实例 useStore(对应 store/index.ts),集中管理用户信息、登录状态、IM 连接、字典数据等全局状态。
Store 定义
import { defineStore } from 'pinia'
export const useStore = defineStore('main', {
state: () => ({ ... }),
actions: { ... },
persist: {
enabled: true,
strategies: [{ key: 'live-mall', storage: window?.localStorage, paths: [...] }]
}
})
State 字段说明
用户与认证
| 字段 | 类型 | 说明 |
|---|---|---|
user | IUserInfo | 当前登录用户信息 |
isLogin | boolean | 登录状态,基于 StorageKeyEnum.TOKEN 初始化 |
openId | string | 微信 openId,小程序登录后保存 |
phoneVisible | boolean | 个人信息中手机号是否完全可见 |
walletId | number | 当前用户钱包 ID |
系统与平台
| 字段 | 类型 | 说明 |
|---|---|---|
isIosApp | boolean | 是否为 iOS App 环境 |
isAppPlus | boolean | 是否为 App 环境(Android 或 iOS) |
isWeixin | boolean | 是否在微信小程序环境 |
sysInfo | UniApp.GetSystemInfoResult | 系统信息(屏幕尺寸、安全区域等) |
appPermissionMap | Record<PermissionType, boolean> | App 权限授权状态映射 |
appPermissionIds | Record<PermissionType, number> | App 权限状态码(1=已授权,-1=已拒绝) |
业务数据
| 字段 | 类型 | 说明 |
|---|---|---|
pageTabIndex | number | 当前 Tab 页索引 |
tabbarList | ITabbarItem[] | 动态 Tabbar 列表(根据平台动态生成) |
cityDataList | ICityData[] | 城市三级联动数据 |
museumitem | IMuseumItem | 当前博物馆详情(跨页面共享) |
dictMap | Record<string, IDictItem[]> | 字典数据缓存 |
isLiveVisible | boolean | 直播模块是否可见 |
recommendSwitch | boolean | 推送功能是否开启 |
IM 即时通讯
| 字段 | 类型 | 说明 |
|---|---|---|
isIMLogin | boolean | IM 是否已登录 |
chat | any | 腾讯云 IM SDK 实例 |
csUrl | string | 客服页面 URL |
imSDKAppId | number | IM SDK AppID |
imSecretKey | string | IM 密钥 |
tcPlayerLicenseUrl | string | H5 直播播放器授权地址 |
Actions 说明
登录与令牌
async setToken(token = '', refreshToken = '', openId = '') {
if (token === '') {
// 清除登录状态:移除 Storage 中的 Token、清空用户信息
this.isLogin = false
this.user = <IUserInfo>{}
uni.removeStorageSync(StorageKeyEnum.TOKEN)
uni.removeStorageSync(StorageKeyEnum.REFRESH_TOKEN)
} else {
// 设置登录状态:保存 Token → 拉取用户信息 → 登录 IM
this.isLogin = true
uni.setStorageSync(StorageKeyEnum.TOKEN, token)
uni.setStorageSync(StorageKeyEnum.REFRESH_TOKEN, refreshToken)
this.user = await getUserInfoApi()
await useIM().login()
}
}
关键点:setToken 不仅管理本地存储,还串联了用户信息拉取和 IM 登录流程。
Tab 管理
// 通过索引设置当前 Tab
setPageTabIndex(index: number)
// 通过 Tab 类型设置(自动处理小程序无直播 Tab 的情况)
setPageTabByType(type: TabbarTypeEnum)
TabbarTypeEnum 包含:HOME、MALL、LIVE、MUSEUM、MINE。
字典数据
// 支持批量设置和单个设置
setDictMap(key: string | Record<string, IDictItem[]>, data?: IDictItem[])
IM 配置
setIMSettings(settings: IDictItem[]) {
// 从字典数据中提取 im_sdk_app_id、im_secret_key、v_cube_license
this.imSDKAppId = Number(appIdStr)
this.imSecretKey = secretKey
this.tcPlayerLicenseUrl = license
}
持久化策略
Store 通过 pinia-plugin-persist 插件实现数据持久化,存储键为 live-mall,使用 localStorage:
persist: {
enabled: true,
strategies: [{
key: 'live-mall',
storage: window?.localStorage,
paths: [
'sysInfo', // 系统信息
'appPermissionMap', // 权限映射
'appPermissionIds', // 权限状态码
'user', // 用户信息
'museumitem', // 博物馆详情
'cityDataList', // 城市数据
'openId', // 微信 openId
'phoneVisible', // 手机号可见性
'recommendSwitch', // 推送开关
'walletId', // 钱包 ID
'dictMap', // 字典缓存
]
}]
}
注意:以下字段不持久化(每次启动重新获取):
isLogin— 基于 Token 是否存在重新计算isIMLogin/chat— IM 状态需重新初始化pageTabIndex/tabbarList— 每次启动动态生成isLiveVisible/showOneClickLogin— 临时 UI 状态
本地存储键枚举
除 Pinia 持久化外,项目还通过 StorageKeyEnum 管理独立的本地存储:
| 键 | 用途 |
|---|---|
TOKEN | 访问令牌 |
REFRESH_TOKEN | 刷新令牌 |
NETWORK_ALLOWED_IN_IOS | iOS 首次启动网络权限标识 |
INVOICE_TITLE_INFO | 发票抬头信息(列表页→详情页传递) |
LIVE_LIST | 直播列表缓存 |
PROD_ORDER_INFO | 商品订单信息 |
LIVE_PLAYBACK_DETAIL | 直播回放详情 |
使用示例
// 在组件中使用
import useStore from '@/store'
const store = useStore()
// 读取状态
console.log(store.user.nickname)
console.log(store.isLogin)
// 修改状态
store.setUserInfo(newUser)
store.setPageTabByType(TabbarTypeEnum.MALL)
store.setDictMap('promotion_product_scope', dictList)
// 登录流程
await store.setToken(accessToken, refreshToken, openId)
// 登出
store.setToken() // 传空参数,自动清除所有登录相关状态