Files
real-time-fund/doc/localStorage 数据结构.md
2026-02-19 21:37:56 +08:00

377 lines
7.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# localStorage 数据结构说明
本文档详细说明了 real-time-fund 项目中使用的 localStorage 数据结构。
## 概述
项目使用 localStorage 来持久化用户的基金数据、配置和状态。所有数据都以 JSON 字符串格式存储(除简单字符串外)。
---
## 数据键列表
### 1. funds
**类型**: `Array<Object>`
**默认值**: `[]`
**说明**: 存储用户添加的所有基金信息
**数据结构**:
```javascript
[
{
code: string, // 基金代码(唯一标识)
name: string, // 基金名称
type: string, // 基金类型
dwjz: number, // 单位净值
gsz: number, // 估算净值
gszzl: number, // 估算涨跌幅
jzrq: string, // 净值日期
gztime: string, // 估值时间
// ... 其他基金字段
}
]
```
**使用场景**:
- 页面加载时恢复基金列表
- 添加/删除基金时更新
- 导入/导出配置时包含
- 云端同步时同步
---
### 2. favorites
**类型**: `Array<string>`
**默认值**: `[]`
**说明**: 存储用户标记为自选的基金代码列表
**数据结构**:
```javascript
[
"000001", // 基金代码
"110022",
// ...
]
```
**使用场景**:
- 显示自选基金标签页
- 添加/移除自选时更新
- 导入/导出配置时包含
---
### 3. groups
**类型**: `Array<Object>`
**默认值**: `[]`
**说明**: 存储用户创建的基金分组信息
**数据结构**:
```javascript
[
{
id: string, // 分组唯一标识
name: string, // 分组名称
codes: Array<string> // 分组内的基金代码列表
}
]
```
**使用场景**:
- 显示分组标签页
- 分组管理(添加、编辑、删除)
- 导入/导出配置时包含
---
### 4. collapsedCodes
**类型**: `Array<string>`
**默认值**: `[]`
**说明**: 存储用户收起的基金代码列表(用于折叠基金详情)
**数据结构**:
```javascript
[
"000001", // 收起的基金代码
"110022",
// ...
]
```
**使用场景**:
- 记录用户折叠的基金卡片
- 页面刷新后保持折叠状态
---
### 5. collapsedTrends
**类型**: `Array<string>`
**默认值**: `[]`
**说明**: 存储用户收起的业绩走势图表的基金代码列表
**数据结构**:
```javascript
[
"000001", // 收起走势图的基金代码
"110022",
// ...
]
```
**使用场景**:
- 记录用户折叠的业绩走势图表
- 页面刷新后保持折叠状态
---
### 6. viewMode
**类型**: `string`
**默认值**: `'card'`
**可选值**: `'card'` | `'list'`
**说明**: 存储用户选择的视图模式
**数据结构**:
```javascript
'card' // 卡片视图
'list' // 列表视图
```
**使用场景**:
- 切换卡片/列表视图
- 页面刷新后保持视图模式
---
### 7. refreshMs
**类型**: `number` (字符串存储)
**默认值**: `30000` (30秒)
**最小值**: `5000` (5秒)
**说明**: 存储数据刷新间隔时间(毫秒)
**数据结构**:
```javascript
'30000' // 30秒刷新一次
'60000' // 60秒刷新一次
```
**使用场景**:
- 控制基金数据自动刷新频率
- 用户设置刷新间隔时更新
---
### 8. holdings
**类型**: `Object`
**默认值**: `{}`
**说明**: 存储用户的持仓信息
**数据结构**:
```javascript
{
"000001": {
share: number, // 持有份额
cost: number // 持仓成本价
},
"110022": {
share: number,
cost: number
}
}
```
**使用场景**:
- 计算持仓收益
- 买入/卖出操作时更新
- 导入/导出配置时包含
---
### 9. pendingTrades
**类型**: `Array<Object>`
**默认值**: `[]`
**说明**: 存储待处理的交易记录(当净值未更新时)
**数据结构**:
```javascript
[
{
id: string, // 交易唯一标识
fundCode: string, // 基金代码
fundName: string, // 基金名称
type: string, // 交易类型 'buy' | 'sell'
share: number, // 交易份额
amount: number, // 交易金额
feeRate: number, // 手续费率
feeMode: string, // 手续费模式
feeValue: number, // 手续费金额
date: string, // 交易日期
isAfter3pm: boolean, // 是否下午3点后
isAfter3pm: boolean, // 是否下午3点后
timestamp: number // 时间戳
}
]
```
**使用场景**:
- 净值未更新时暂存交易
- 净值更新后自动处理待处理交易
- 导入/导出配置时包含
---
### 10. localUpdatedAt
**类型**: `string` (ISO 8601 格式)
**默认值**: `null`
**说明**: 存储本地数据最后更新时间戳,用于云端同步冲突检测
**数据结构**:
```javascript
'2024-01-15T10:30:00.000Z'
```
**使用场景**:
- 云端同步时比较数据版本
- 检测本地和云端数据冲突
---
### 11. hasClosedAnnouncement_v7
**类型**: `string`
**默认值**: `null`
**可选值**: `'true'`
**说明**: 标记用户是否已关闭公告弹窗
**数据结构**:
```javascript
'true' // 用户已关闭公告
```
**使用场景**:
- 控制公告弹窗显示
- 版本号后缀v7用于控制公告版本
---
## 数据同步机制
### 云端同步
项目支持通过 Supabase 进行云端数据同步:
1. **上传到云端**: 用户登录后,本地数据会自动上传到云端
2. **从云端下载**: 用户在其他设备登录时,会从云端下载数据
3. **冲突处理**: 当本地和云端数据不一致时,会提示用户选择使用哪份数据
**同步的数据字段**:
- funds
- favorites
- groups
- collapsedCodes
- collapsedTrends
- viewMode
- refreshMs
- holdings
- pendingTrades
### 导入/导出
用户可以导出配置到 JSON 文件,或从 JSON 文件导入配置:
**导出格式**:
```javascript
{
funds: [],
favorites: [],
groups: [],
collapsedCodes: [],
refreshMs: 30000,
viewMode: 'card',
holdings: {},
pendingTrades: [],
exportedAt: '2024-01-15T10:30:00.000Z'
}
```
**导入逻辑**:
- 合并基金列表(去重)
- 合并自选、分组等配置
- 保留现有数据,避免覆盖
---
## 数据验证和清理
### 数据去重
基金列表使用 `dedupeByCode` 函数进行去重,确保每个基金代码只出现一次。
```javascript
const dedupeByCode = (list) => {
const seen = new Set();
return list.filter(f => {
if (!f?.code) return false;
if (seen.has(f.code)) return false;
seen.add(f.code);
return true;
});
};
```
### 数据清理
在收集数据上传云端时,会进行数据验证和清理:
1. 清理无效的持仓数据(基金不存在的持仓)
2. 清理无效的自选、分组、收起状态
3. 确保数据类型正确
---
## 存储辅助工具
项目使用 `storageHelper` 对象来封装 localStorage 操作,提供统一的错误处理和日志记录。
```javascript
const storageHelper = {
setItem: (key, value) => { /* ... */ },
getItem: (key) => { /* ... */ },
removeItem: (key) => { /* ... */ },
clear: () => { /* ... */ }
};
```
---
## 注意事项
1. **数据大小限制**: localStorage 有约 5-10MB 的存储限制,大量基金数据可能超出限制
2. **数据同步**: 修改数据后需要同时更新 localStorage 和 React state
3. **错误处理**: 所有 localStorage 操作都应包含 try-catch 错误处理
4. **数据格式**: 复杂数据必须使用 JSON.stringify/JSON.parse 进行序列化/反序列化
5. **版本控制**: 公告等配置使用版本号后缀,便于控制不同版本的显示
---
## 相关文件
- `app/page.jsx` - 主要页面组件,包含所有 localStorage 操作
- `app/components/Announcement.jsx` - 公告组件
- `app/lib/supabase.js` - Supabase 客户端配置
---
## 更新日志
- **2026-02-19**: 初始文档创建