优化:getSiteInfo、statistics使用了状态管理模式,提升性能。
This commit is contained in:
228
docs/store-usage.md
Normal file
228
docs/store-usage.md
Normal file
@@ -0,0 +1,228 @@
|
||||
# 网站信息和统计数据状态管理使用指南
|
||||
|
||||
## 概述
|
||||
|
||||
项目已经实现了网站信息和统计数据的状态管理,使用 Pinia 进行状态管理,避免了在多个组件中重复调用 API。
|
||||
|
||||
## Store 结构
|
||||
|
||||
### 1. 网站信息 Store (`useSiteStore`)
|
||||
|
||||
位置:`src/store/modules/site.ts`
|
||||
|
||||
**功能:**
|
||||
- 缓存网站基本信息(名称、Logo、域名等)
|
||||
- 自动计算系统运行天数
|
||||
- 智能缓存管理(默认30分钟有效期)
|
||||
- 自动更新 localStorage 中的相关信息
|
||||
|
||||
**主要 API:**
|
||||
```typescript
|
||||
const siteStore = useSiteStore();
|
||||
|
||||
// 获取网站信息(带缓存)
|
||||
await siteStore.fetchSiteInfo();
|
||||
|
||||
// 强制刷新
|
||||
await siteStore.fetchSiteInfo(true);
|
||||
|
||||
// 获取计算属性
|
||||
siteStore.websiteName
|
||||
siteStore.websiteLogo
|
||||
siteStore.runDays
|
||||
```
|
||||
|
||||
### 2. 统计数据 Store (`useStatisticsStore`)
|
||||
|
||||
位置:`src/store/modules/statistics.ts`
|
||||
|
||||
**功能:**
|
||||
- 缓存统计数据(用户数、订单数、销售额等)
|
||||
- 自动刷新机制(默认5分钟间隔)
|
||||
- 异步更新数据库
|
||||
- 短期缓存策略
|
||||
|
||||
**主要 API:**
|
||||
```typescript
|
||||
const statisticsStore = useStatisticsStore();
|
||||
|
||||
// 获取统计数据
|
||||
await statisticsStore.fetchStatistics();
|
||||
|
||||
// 开始自动刷新(5分钟间隔)
|
||||
statisticsStore.startAutoRefresh();
|
||||
|
||||
// 停止自动刷新
|
||||
statisticsStore.stopAutoRefresh();
|
||||
|
||||
// 获取统计数据
|
||||
statisticsStore.userCount
|
||||
statisticsStore.orderCount
|
||||
statisticsStore.totalSales
|
||||
```
|
||||
|
||||
## 使用方式
|
||||
|
||||
### 方式一:直接使用 Store
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<div>
|
||||
<h1>{{ siteStore.websiteName }}</h1>
|
||||
<img :src="siteStore.websiteLogo" alt="logo" />
|
||||
<p>用户总数: {{ statisticsStore.userCount }}</p>
|
||||
<p>运行天数: {{ siteStore.runDays }}</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useSiteStore } from '@/store/modules/site';
|
||||
import { useStatisticsStore } from '@/store/modules/statistics';
|
||||
import { onMounted, onUnmounted } from 'vue';
|
||||
|
||||
const siteStore = useSiteStore();
|
||||
const statisticsStore = useStatisticsStore();
|
||||
|
||||
onMounted(async () => {
|
||||
// 加载数据
|
||||
await Promise.all([
|
||||
siteStore.fetchSiteInfo(),
|
||||
statisticsStore.fetchStatistics()
|
||||
]);
|
||||
|
||||
// 开始自动刷新统计数据
|
||||
statisticsStore.startAutoRefresh();
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
// 停止自动刷新
|
||||
statisticsStore.stopAutoRefresh();
|
||||
});
|
||||
</script>
|
||||
```
|
||||
|
||||
### 方式二:使用组合式函数(推荐)
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<div>
|
||||
<h1>{{ websiteName }}</h1>
|
||||
<img :src="websiteLogo" alt="logo" />
|
||||
<p>用户总数: {{ userCount }}</p>
|
||||
<p>运行天数: {{ runDays }}</p>
|
||||
<a-spin :spinning="loading">
|
||||
<!-- 内容 -->
|
||||
</a-spin>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useSiteData } from '@/composables/useSiteData';
|
||||
import { onMounted, onUnmounted } from 'vue';
|
||||
|
||||
const {
|
||||
websiteName,
|
||||
websiteLogo,
|
||||
userCount,
|
||||
runDays,
|
||||
loading,
|
||||
refreshAll,
|
||||
startAutoRefresh,
|
||||
stopAutoRefresh
|
||||
} = useSiteData();
|
||||
|
||||
onMounted(async () => {
|
||||
await refreshAll();
|
||||
startAutoRefresh();
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
stopAutoRefresh();
|
||||
});
|
||||
</script>
|
||||
```
|
||||
|
||||
## 缓存策略
|
||||
|
||||
### 网站信息缓存
|
||||
- **有效期:** 30分钟
|
||||
- **策略:** 长期缓存,信息相对稳定
|
||||
- **刷新时机:** 手动刷新或缓存过期
|
||||
|
||||
### 统计数据缓存
|
||||
- **有效期:** 5分钟
|
||||
- **策略:** 短期缓存 + 自动刷新
|
||||
- **刷新时机:** 自动刷新(5分钟间隔)或手动刷新
|
||||
|
||||
## 最佳实践
|
||||
|
||||
### 1. 组件生命周期管理
|
||||
```typescript
|
||||
onMounted(async () => {
|
||||
// 加载数据
|
||||
await refreshAll();
|
||||
// 开始自动刷新
|
||||
startAutoRefresh();
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
// 清理定时器
|
||||
stopAutoRefresh();
|
||||
});
|
||||
```
|
||||
|
||||
### 2. 错误处理
|
||||
```typescript
|
||||
try {
|
||||
await siteStore.fetchSiteInfo();
|
||||
} catch (error) {
|
||||
console.error('获取网站信息失败:', error);
|
||||
// 处理错误
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 强制刷新
|
||||
```typescript
|
||||
// 用户手动刷新时
|
||||
const handleRefresh = async () => {
|
||||
await refreshAll(true); // 强制刷新
|
||||
};
|
||||
```
|
||||
|
||||
## 迁移指南
|
||||
|
||||
### 从直接 API 调用迁移
|
||||
|
||||
**之前:**
|
||||
```typescript
|
||||
import { getSiteInfo } from '@/api/layout';
|
||||
|
||||
const siteInfo = ref({});
|
||||
const loadSiteInfo = async () => {
|
||||
siteInfo.value = await getSiteInfo();
|
||||
};
|
||||
```
|
||||
|
||||
**现在:**
|
||||
```typescript
|
||||
import { useSiteStore } from '@/store/modules/site';
|
||||
|
||||
const siteStore = useSiteStore();
|
||||
// 直接使用 siteStore.siteInfo 或 siteStore.websiteName 等
|
||||
```
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **自动刷新管理:** 确保在组件卸载时停止自动刷新,避免内存泄漏
|
||||
2. **缓存有效性:** 可以通过 `isCacheValid` 检查缓存是否有效
|
||||
3. **错误处理:** 所有异步操作都应该有适当的错误处理
|
||||
4. **性能优化:** 使用计算属性而不是直接访问 store 状态
|
||||
|
||||
## 扩展功能
|
||||
|
||||
如需添加新的统计数据或网站信息字段,请:
|
||||
|
||||
1. 更新对应的 Store 接口
|
||||
2. 添加相应的 getter
|
||||
3. 更新组合式函数
|
||||
4. 更新类型定义
|
||||
205
docs/状态管理实现总结.md
Normal file
205
docs/状态管理实现总结.md
Normal file
@@ -0,0 +1,205 @@
|
||||
# 网站信息和统计数据状态管理实现总结
|
||||
|
||||
## 问题背景
|
||||
|
||||
原项目中 `getSiteInfo` 和 `loadStatistics` 方法在多个组件中重复调用,存在以下问题:
|
||||
|
||||
1. **重复请求**:每个组件都独立调用 API,造成不必要的网络请求
|
||||
2. **数据不一致**:各组件间数据可能不同步
|
||||
3. **类型安全问题**:TypeScript 提示 "Object is possibly undefined" 错误
|
||||
4. **维护困难**:相同逻辑分散在多个组件中
|
||||
|
||||
## 解决方案
|
||||
|
||||
### 1. 创建状态管理 Store
|
||||
|
||||
#### 网站信息 Store (`src/store/modules/site.ts`)
|
||||
- **功能**:管理网站基本信息(名称、Logo、域名等)
|
||||
- **缓存策略**:30分钟有效期,适合相对稳定的数据
|
||||
- **特性**:
|
||||
- 智能缓存管理
|
||||
- 自动计算系统运行天数
|
||||
- 自动更新 localStorage
|
||||
- 完整的类型保护
|
||||
|
||||
#### 统计数据 Store (`src/store/modules/statistics.ts`)
|
||||
- **功能**:管理统计数据(用户数、订单数、销售额等)
|
||||
- **缓存策略**:5分钟有效期,支持自动刷新
|
||||
- **特性**:
|
||||
- 短期缓存 + 自动刷新机制
|
||||
- 异步更新数据库
|
||||
- 类型安全的数据处理
|
||||
- 错误处理和重试机制
|
||||
|
||||
### 2. 类型保护工具 (`src/utils/type-guards.ts`)
|
||||
|
||||
创建了一套完整的类型保护工具函数:
|
||||
|
||||
```typescript
|
||||
// 安全获取数字值
|
||||
safeNumber(value: unknown, defaultValue = 0): number
|
||||
|
||||
// 检查对象是否有有效的 ID
|
||||
hasValidId(obj: unknown): obj is { id: number }
|
||||
|
||||
// 检查 API 响应是否有效
|
||||
isValidApiResponse<T>(response: unknown): response is { count: number; list?: T[] }
|
||||
```
|
||||
|
||||
### 3. 组合式函数 (`src/composables/useSiteData.ts`)
|
||||
|
||||
提供统一的数据访问接口:
|
||||
|
||||
```typescript
|
||||
const {
|
||||
websiteName,
|
||||
websiteLogo,
|
||||
userCount,
|
||||
orderCount,
|
||||
loading,
|
||||
refreshAll,
|
||||
startAutoRefresh,
|
||||
stopAutoRefresh
|
||||
} = useSiteData();
|
||||
```
|
||||
|
||||
## 核心特性
|
||||
|
||||
### 1. 智能缓存管理
|
||||
- **网站信息**:30分钟缓存,适合稳定数据
|
||||
- **统计数据**:5分钟缓存,支持实时更新
|
||||
- **缓存验证**:自动检查缓存有效性
|
||||
|
||||
### 2. 自动刷新机制
|
||||
```typescript
|
||||
// 开始自动刷新(默认5分钟间隔)
|
||||
statisticsStore.startAutoRefresh();
|
||||
|
||||
// 停止自动刷新
|
||||
statisticsStore.stopAutoRefresh();
|
||||
```
|
||||
|
||||
### 3. 类型安全
|
||||
- 完整的 TypeScript 类型定义
|
||||
- 运行时类型检查
|
||||
- 安全的数据访问方法
|
||||
|
||||
### 4. 错误处理
|
||||
- API 调用失败处理
|
||||
- 数据验证和默认值
|
||||
- 详细的错误日志
|
||||
|
||||
## 使用方式
|
||||
|
||||
### 方式一:直接使用 Store
|
||||
```vue
|
||||
<script setup>
|
||||
import { useSiteStore } from '@/store/modules/site';
|
||||
import { useStatisticsStore } from '@/store/modules/statistics';
|
||||
|
||||
const siteStore = useSiteStore();
|
||||
const statisticsStore = useStatisticsStore();
|
||||
|
||||
onMounted(async () => {
|
||||
await Promise.all([
|
||||
siteStore.fetchSiteInfo(),
|
||||
statisticsStore.fetchStatistics()
|
||||
]);
|
||||
|
||||
statisticsStore.startAutoRefresh();
|
||||
});
|
||||
</script>
|
||||
```
|
||||
|
||||
### 方式二:使用组合式函数(推荐)
|
||||
```vue
|
||||
<script setup>
|
||||
import { useSiteData } from '@/composables/useSiteData';
|
||||
|
||||
const {
|
||||
websiteName,
|
||||
userCount,
|
||||
loading,
|
||||
refreshAll,
|
||||
startAutoRefresh,
|
||||
stopAutoRefresh
|
||||
} = useSiteData();
|
||||
|
||||
onMounted(async () => {
|
||||
await refreshAll();
|
||||
startAutoRefresh();
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
stopAutoRefresh();
|
||||
});
|
||||
</script>
|
||||
```
|
||||
|
||||
## 已更新的组件
|
||||
|
||||
1. **`src/views/cms/dashboard/index.vue`** - 仪表板页面
|
||||
2. **`src/layout/components/header-tools.vue`** - 头部工具栏
|
||||
3. **`src/views/cms/setting/index.vue`** - 设置页面
|
||||
4. **`src/views/shop/index.vue`** - 商店页面
|
||||
|
||||
## 数据更新策略
|
||||
|
||||
### 推荐的混合策略:
|
||||
|
||||
1. **前端定时更新** + **后端实时计算**
|
||||
- 前端每5-10分钟自动刷新统计数据
|
||||
- 后端提供实时计算接口
|
||||
- 用户手动刷新时立即更新
|
||||
|
||||
2. **分层缓存**
|
||||
- 基础信息(网站信息):状态管理 + 长期缓存
|
||||
- 统计数据:短期缓存 + 定时更新
|
||||
- 实时数据:不缓存,每次请求
|
||||
|
||||
## 性能优化
|
||||
|
||||
1. **减少 API 调用**:智能缓存避免重复请求
|
||||
2. **内存优化**:及时清理定时器和监听器
|
||||
3. **类型优化**:编译时类型检查,减少运行时错误
|
||||
4. **按需加载**:只在需要时获取数据
|
||||
|
||||
## 最佳实践
|
||||
|
||||
1. **生命周期管理**:
|
||||
```typescript
|
||||
onMounted(() => startAutoRefresh());
|
||||
onUnmounted(() => stopAutoRefresh());
|
||||
```
|
||||
|
||||
2. **错误处理**:
|
||||
```typescript
|
||||
try {
|
||||
await fetchSiteInfo();
|
||||
} catch (error) {
|
||||
console.error('获取网站信息失败:', error);
|
||||
}
|
||||
```
|
||||
|
||||
3. **强制刷新**:
|
||||
```typescript
|
||||
const handleRefresh = () => refreshAll(true);
|
||||
```
|
||||
|
||||
## 构建验证
|
||||
|
||||
✅ TypeScript 编译通过
|
||||
✅ 所有类型错误已解决
|
||||
✅ 生产构建成功
|
||||
✅ 无运行时错误
|
||||
|
||||
## 总结
|
||||
|
||||
通过实现状态管理,我们成功解决了:
|
||||
|
||||
1. **重复 API 调用问题** - 智能缓存机制
|
||||
2. **类型安全问题** - 完整的类型保护
|
||||
3. **数据一致性问题** - 统一的数据源
|
||||
4. **维护性问题** - 集中的状态管理
|
||||
|
||||
这个实现为项目提供了更好的性能、更强的类型安全性和更易维护的代码结构。
|
||||
Reference in New Issue
Block a user