166 lines
8.3 KiB
Markdown
166 lines
8.3 KiB
Markdown
# 📝 记分本(Point Book)Flutter 纯本地版 PRD
|
||
|
||
## 文档信息
|
||
|
||
- **文档状态**:已完成(重构版)
|
||
- **适用端**:iOS / Android 客户端(Flutter 纯本地架构)
|
||
- **变现模式**:免费试用 + iOS 苹果内购(IAP 买断/解锁)
|
||
- **关联模块**:本地训练统计 / 个人资料管理 / 记分管理 / 苹果内购
|
||
|
||
---
|
||
|
||
## 1. 页面概述
|
||
|
||
### 1.1 页面定位与目标
|
||
|
||
- **定位**:记分本业务线的 **总入口与本地数据总览页**。
|
||
- **目标**:
|
||
|
||
1. **零门槛使用**:无任何登录流程,首次打开即可直接查看本地统计或发起记分。
|
||
2. **正向数据反馈**:直观展示本地累计射箭数据、日均消耗、环值命中分布与落点热力图。
|
||
3. **内购合规转化**:提供免费体验额度,在用户第 N 次点击【开始记分】时,平滑唤起苹果内购付费解锁弹框。
|
||
|
||
### 1.2 权限与架构变更
|
||
|
||
- **数据架构**:**纯本地架构(Local-First)**,无后端服务器、无网络 API,所有训练数据与配置均存储于手机本地数据库(Isar/Hive)。
|
||
- **用户体系**:**完全免登录**,移除所有手机号获取、微信登录及协议勾选框。
|
||
- **排行榜**:**彻底移除**周榜、点赞及任何他人对比功能。
|
||
|
||
---
|
||
|
||
## 2. 页面流转与初始化逻辑
|
||
|
||
```mermaid
|
||
graph TD
|
||
A[用户打开 App / 进入首页] --> B[加载本地数据库 Isar]
|
||
B --> C[读取/初始化本地 UserProfile]
|
||
B --> D[读取/初始化本地 AppConfig]
|
||
B --> E[读取本地历史 PointRecord 列表]
|
||
|
||
C --> F[渲染:顶部个人资料卡片]
|
||
D --> G[渲染:用户权益/免费剩余次数]
|
||
E --> H[渲染:本地统计指标、落点热力图、环值分布图]
|
||
|
||
```
|
||
|
||
---
|
||
|
||
## 3. 核心功能与交互说明
|
||
|
||
### 3.1 本地个人资料管理(头像与昵称修改)
|
||
|
||
- **默认生成**:App 首次启动时,本地自动创建默认 Profile:
|
||
- **默认昵称**:`弓箭手_XXXX`(四位随机数字)。
|
||
- **默认头像**:预设本地 Avatar Asset。
|
||
- **编辑交互**:
|
||
- **入口**:点击首页顶部的个人资料卡片或【编辑】图标。
|
||
- **修改昵称**:弹出本地输入框,限制 1~12 个字符。
|
||
- **修改头像**:支持从手机本地相册选择图片或调起相机拍摄;选中后将图片异步拷贝至 App 本地沙盒目录 `ApplicationDocumentsDirectory/avatar.png`,数据库中仅保存文件路径。
|
||
|
||
---
|
||
|
||
### 3.2 个人训练统计卡片(纯本地计算)
|
||
|
||
- **关键指标**:今日射箭数、今日消耗、运动强度、训练天数、累计射箭数、平均环数。
|
||
- **计算规则**:
|
||
- **无数据时**:指标统一展示为 `-`。
|
||
- **今日消耗**:$\text{今日箭数} \times 1.6$。
|
||
- **运动强度**:$\frac{\text{今日箭数} \times 5}{60}$(上限封顶为 10)。
|
||
- $> 6$:标记为 **重度**
|
||
- $4 \sim 6$:标记为 **中度**
|
||
- $< 4$:标记为 **轻度**
|
||
|
||
---
|
||
|
||
### 3.3 核心业务入口与苹果内购(IAP)拦截
|
||
|
||
#### 🔹 入口一:【计分记录】
|
||
|
||
- **交互**:点击直接进入 `本地计分记录列表页`(支持按弓型/距离/靶纸筛选及本地记录滑动删除)。
|
||
|
||
#### 🔹 入口二:【开始记分】(含免费试用与内购拦截)
|
||
|
||
- **参数配置**:
|
||
- `free_trial_limit`: 可配置免费试用次数(默认 `2` 次)。
|
||
- `used_trial_count`: 已使用免费试用次数。
|
||
- `is_vip_unlocked`: 是否已购买内购解锁(`true` / `false`)。
|
||
- **拦截判定流程**:
|
||
|
||
```mermaid
|
||
graph TD
|
||
Start[点击“开始记分”] --> VIPCheck{is_vip_unlocked == true ?}
|
||
VIPCheck -- 是 --> DraftCheck
|
||
VIPCheck -- 否 --> TrialCheck{used_trial_count < free_trial_limit ?}
|
||
|
||
TrialCheck -- 是 (试用额度内) --> DraftCheck
|
||
TrialCheck -- 否 (试用额度已满) --> Paywall[阻断进入,弹出收费解锁弹框]
|
||
|
||
DraftCheck{本地是否存在未完成草稿?} -- 无草稿 --> CreatePage[进入参数选择/新建记分页]
|
||
DraftCheck -- 有草稿 --> DraftConfirmDialog[弹出草稿二选一确认框]
|
||
|
||
DraftConfirmDialog -- 继续编辑 --> EditPage[进入记分编辑页加载草稿]
|
||
DraftConfirmDialog -- 重新计分 --> ClearDraft[清空本地草稿] --> CreatePage
|
||
|
||
```
|
||
|
||
> **计数更新时机**:当用户在试用期内完成一次完整记分并点击**【保存记分】**成功写入本地数据库后,系统自动执行 `used_trial_count + 1`。
|
||
|
||
#### 💳 内购解锁弹窗与结果流转
|
||
|
||
- **弹窗展示**:包含内购商品名称、价格、买断权益说明、`[立即解锁]` 按钮、`[恢复购买]` 按钮及 `[取消/暂不解锁]` 按钮。
|
||
- **支付流转规则**:
|
||
|
||
| 用户操作 / 支付状态 | 系统响应 | 页面流转 |
|
||
| ------------------------ | ------------------------------------------ | --------------------------- |
|
||
| **点击 [立即解锁]** | 调起 Apple App Store 原生支付组件。 | 界面显示原生 Loading 遮罩。 |
|
||
| **支付成功 (Purchased)** | 1. 本地数据库更新 `is_vip_unlocked = true` | |
|
||
|
||
2. 弹出 Toast 提示:“解锁成功!已获得无限记分权益” | 1. 关闭内购弹窗;
|
||
|
||
3. **返回【记分本首页】**;
|
||
|
||
4. 再次点击【开始记分】自动解锁放行。 |
|
||
| **取消支付 (Canceled)** | 1. 弹出 Toast 提示:“支付已取消” | 1. 关闭内购弹窗;
|
||
|
||
5. **停留在【记分本首页】**。 |
|
||
| **支付失败 (Error)** | 1. 弹出 Toast 提示:“支付失败:[错误信息]” | 1. 关闭 Loading;
|
||
|
||
6. **停留在【记分本首页】**。 |
|
||
| **点击 [恢复购买]** | 调起 `InAppPurchase.instance.restorePurchases()` | 查到历史购买凭证后更新 `is_vip_unlocked = true` 并提示“权益已恢复”,关闭弹窗并**返回【记分本首页】**。 |
|
||
|
||
---
|
||
|
||
### 3.4 本地图像分析模块(热力图与环值分布)
|
||
|
||
#### 🎯 落点热力图
|
||
|
||
- **展示条件**:本地存在历史训练数据时展示。
|
||
- **生成方式**:读取本地 `PointRecord` 中的 `hitPoints` 坐标数据,使用 Flutter Canvas 在本地预设靶纸底图上直接绘制热力点覆盖层。
|
||
|
||
#### 📊 个人环值分布图
|
||
|
||
- **展示条件**:本地存在历史记录时展示。
|
||
- **展示形式**:按 `M / X / 1~10 环` 统计本地所有箭数的占比,以柱状图形式呈现。
|
||
|
||
---
|
||
|
||
## 4. 边界异常处理与业务细节(QA 关注)
|
||
|
||
| 场景 | 预期处理机制 | 备注 / 风险点 |
|
||
| --------------------- | ------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------- |
|
||
| **首次安装 / 无数据** | 统计数据指标展示 `-`,热力图展示纯靶纸背景图,免费次数显示 `0/2`。 | 避免因为数据为空导致本地 Canvas 渲染报错。 |
|
||
| **本地草稿覆盖** | 点击“重新计分”会强制删除本地 SQLite/Isar 中的草稿记录,并覆盖写入。 | 需有二次弹窗明确确认,防止误删未保存数据。 |
|
||
| **重装 App / 换手机** | 纯本地 App 不支持跨设备数据同步;用户可通过内购弹窗的 **[恢复购买]** 恢复付费权益。 | 需在 App 内“关于我们”或设置页明确告知“数据存储于本地,卸载 App 会清空训练记录”。 |
|
||
| **网络离线内购** | 发起购买需要网络连接,若离线调起内购,提示:“无法连接到 App Store,请检查网络设置”。 | - |
|
||
|
||
---
|
||
|
||
---
|
||
|
||
## 5. 关联页面流转汇总
|
||
|
||
- 📄 **记分本首页** (`PointBookHomeScreen`):本地数据总览、免费次数提示、个人资料编辑入口、内购弹窗触发。
|
||
- 📄 **计分记录列表** (`PointBookListPage`):读取本地 Isar 历史列表、草稿展示与记录删除。
|
||
- 📄 **新建参数配置** (`PointBookCreatePage`):选择弓型、距离、靶纸类型及组数。
|
||
- 📄 **记分编辑/打靶页** (`PointBookEditPage`):本地实时记录落点与环数,保存时写入本地数据库并扣减试用次数。
|