Update algorithm documentation and API specifications. Enhanced clarity on parameters and calculations in ALGORITHM.md, including default values and boundary conditions. Modified API endpoints from PUT to POST for updating logs and profiles in api.md. Removed outdated DEVELOPMENT.md and related phase documentation files. Added comprehensive health and savings statistics in API responses. Improved user guidance in PHASE3_USER_GUIDE.md.

This commit is contained in:
nepiedg
2026-01-25 17:14:24 +08:00
parent 661f39dfd7
commit 35405efcdf
8 changed files with 205 additions and 2402 deletions
+17 -17
View File
@@ -21,7 +21,7 @@
| 参数 | 来源 | 默认值 | 说明 |
|------|------|--------|------|
| base_interval | profile.baseline_interval_minutes | 60 分钟 | 用户初始平均抽烟间隔 |
| base_interval | profile.baseline_interval_minutes | 60 分钟 | 用户初始平均抽烟间隔(为空/0 时默认 60 |
| resisted_7d | 近7天忍住次数 | 0 | level=0,num=0 的记录数 |
| bonus_interval | 计算得出 | 0 | 奖励延长时间 |
@@ -31,7 +31,7 @@
```
bonus_interval = min(floor(resisted_7d / 5) * 5, 60)
final_interval = base_interval + bonus_interval
final_interval = clamp(base_interval + bonus_interval, 5, 240)
```
**示例**
@@ -41,17 +41,22 @@ final_interval = base_interval + bonus_interval
### 2.4 睡眠规避
若计算出的时间落在睡眠区间,顺延到次日起床时间
若计算出的时间落在睡眠区间,顺延到**下一次**起床时间(可能是当天也可能是次日)
```
if suggested_time in [sleep_time, wake_up_time]:
suggested_time = next_day_wake_up_time
```
### 2.5 算法流程图
### 2.5 边界与兜底
- 若没有历史记录,则以“当前时间”作为 `last_smoke_at` 参与计算。
- 若生成未来日期计划(如明天),默认建议不早于该日起床时间;未配置作息时按 `07:00` 处理。
### 2.6 算法流程图
```
获取上次抽烟时间 (last_smoke_at)
获取上次抽烟时间 (last_smoke_at, 若无记录则取当前时间)
获取用户基础间隔 (base_interval_minutes)
@@ -59,7 +64,7 @@ if suggested_time in [sleep_time, wake_up_time]:
计算奖励间隔: bonus = min(floor(resisted_7d / 5) * 5, 60)
计算建议时间: suggested = last_smoke_at + base + bonus
计算建议时间: suggested = last_smoke_at + base + bonus (并限制在 5~240 分钟区间)
检查是否在睡眠时间?
├── 是 → 顺延到起床时间
@@ -91,20 +96,14 @@ if suggested_time in [sleep_time, wake_up_time]:
### 3.2 AI 建议内容
AI 会生成以下内容:
AI 会生成以下内容(实际接口格式)
```json
{
"advice": "昨天你的吸烟量比限额少了2支,这是一个巨大的胜利!数据显示你的烟瘾在下午2点左右达到顶峰——今天试着那个时候去散散步。",
"time_nodes": [
{ "time": "09:30", "type": "suggested", "note": "第一支,早餐后" },
{ "time": "12:30", "type": "suggested", "note": "午餐后" },
{ "time": "15:30", "type": "suggested", "note": "下午茶时间" },
{ "time": "19:00", "type": "suggested", "note": "晚餐后" },
{ "time": "22:00", "type": "suggested", "note": "睡前最后一支" }
],
"daily_target": 5,
"tips": ["2点是你的高峰期,准备一颗薄荷糖", "试着用深呼吸替代"]
"not_before_at": "2026-01-05T10:18:00+08:00",
"suggested_at": "2026-01-05T10:28:00+08:00",
"time_nodes": ["09:30", "12:30", "15:30", "19:00", "22:00"],
"advice": "昨天你的吸烟量比限额少了2支,这是一个巨大的胜利!数据显示你的烟瘾在下午2点左右达到顶峰——今天试着那个时候去散散步。"
}
```
@@ -299,6 +298,7 @@ function getMotivationMessage(context) {
| 忍住成功率 | 忍住次数 / (忍住+抽烟次数) | 意志力评估 |
| 平均间隔 | 总时长 / 抽烟次数 | 递减效果 |
| 最长无烟时长 | 最大间隔记录 | 成就激励 |
| 较昨日减少 | 昨日支数 - 今日支数(可为负) | 若为负,表示今天超出昨日 |
### 8.2 周报数据结构
-922
View File
@@ -1,922 +0,0 @@
# 开发计划与任务拆分
## 1. 开发阶段概览
```
Phase 1: 基础框架搭建 (2天)
Phase 2: 首页核心功能 (3天) ★ 优先保证首页体验
Phase 3: 记录与历史 (2天)
Phase 4: 统计与图表 (2天)
Phase 5: AI助手与个人中心 (3天)
Phase 6: 优化与测试 (2天)
```
---
## 2. Phase 1: 基础框架搭建 (2天)
### 2.1 项目初始化
- [ ] 创建 uni-app 项目 (Vue3 + JavaScript)
- [ ] 配置路径别名 (@/)
- [ ] 创建目录结构
### 2.2 基础配置
- [ ] 配置 pages.json (页面路由 + TabBar)
- [ ] 配置全局样式 (暗色主题变量)
- [ ] 配置环境变量 (开发/生产 API 地址)
### 2.3 核心模块
- [ ] 封装 request.js (请求拦截、Token管理、错误处理)
- [ ] 封装 storage.js (本地存储工具)
- [ ] 配置 Pinia stores 结构
- [ ] 实现登录流程 (wx.login + 后端认证)
### 2.4 公共组件
- [ ] 创建 Loading 组件
- [ ] 创建 Skeleton 骨架屏组件
- [ ] 创建 Button 组件 (主按钮/次按钮样式)
- [ ] 创建 Card 组件 (卡片容器)
**交付物**:可运行的空白项目,登录功能正常
---
## 3. Phase 2: 首页核心功能 (3天) ★
> ⚠️ 首页是用户最常访问的页面,必须保证 < 500ms 首屏渲染
### 3.1 Day 1: 页面结构 + 数据层
#### API 封装
- [ ] `api/smoke.js`: getDashboard()
- [ ] `api/smoke.js`: getNextSmokeTime()
- [ ] `api/profile.js`: getProfile()
#### Store 设计
- [ ] `stores/dashboard.js`: 看板数据 + 缓存逻辑
- [ ] `stores/user.js`: 用户信息 + 登录状态
#### 页面结构
- [ ] 首页骨架屏
- [ ] 页面布局 (header + timer + cards + buttons)
### 3.2 Day 2: 核心组件
#### 计时器组件 (TimerRing)
- [ ] Canvas 绘制进度环
- [ ] 时间格式化 (HH:MM:SS)
- [ ] requestAnimationFrame 优化
- [ ] 页面可见性处理 (切后台暂停)
#### 统计卡片
- [ ] 今日已抽卡片 (X/目标, 较昨日±N)
- [ ] 烟瘾发作已抵抗卡片
#### 快捷按钮
- [ ] 记录抽烟按钮 → 弹出记录表单
- [ ] 想抽忍住了按钮 → 快速提交
### 3.3 Day 3: 交互 + 优化
#### AI 提示卡片
- [ ] 延迟加载 (300ms后)
- [ ] 可关闭 (本地存储关闭状态)
- [ ] 下次建议时间显示
#### 性能优化
- [ ] 并行请求优化
- [ ] 骨架屏过渡动画
- [ ] 首屏性能埋点
#### 新用户引导
- [ ] 检测 profile.exists
- [ ] 跳转引导页逻辑
**交付物**:完整可用的首页,首屏 < 500ms
---
## 4. Phase 3: 记录与历史 (2天)
### 4.1 Day 1: 记录表单组件
#### 4.1.1 smoke-record-dialog 组件开发
**组件结构** (`components/smoke-record-dialog/smoke-record-dialog.vue`)
- [x] 底部弹出动画 (从底部滑入,半屏展示)
- [x] 明亮主题 UI (白色背景 + 翡翠绿主题色 #10B981)
- [x] 遮罩层点击关闭
- [x] 表单项布局
**表单字段实现**
- [x] 时间选择器
- 日期选择 (picker mode="date")
- 时间选择 (picker mode="time")
- 默认当前时间
- 自动拼接为 `smoke_at` 字段
- [x] 数量选择器 (仅抽烟模式显示)
- 加减按钮 (+/-)
- 数字输入框
- 最小值 1
- 默认值 1
- [x] 烟瘾等级选择 (仅抽烟模式显示)
- 1-5 级按钮组
- 选中态样式切换
- 默认值 2
- [x] 备注输入框
- 多行文本域 (textarea)
- 最大长度 200 字符
- 根据模式显示不同占位符
- 抽烟: "记录抽烟原因..."
- 忍住: "记录抵抗心得..."
**组件逻辑**
- [x] Props 定义
```javascript
{
show: Boolean, // 控制显示
type: String // 'smoke' | 'resisted'
}
```
- [x] 数据初始化
- 打开弹框时自动初始化当前时间
- 根据 type 设置默认值
- smoke: num=1, level=2
- resisted: num=0, level=2
- [x] 提交逻辑
```javascript
{
smoke_time: "2025-01-25",
smoke_at: "2025-01-25 14:30:00",
remark: "",
level: 2,
num: 1 // 或 0 (忍住时)
}
```
- [x] 关闭动画
- 延迟 300ms 触发 update:show
- 平滑过渡效果
#### 4.1.2 组件配置
**easycom 自动导入** (`pages.json`)
- [x] 配置组件路径
```json
{
"easycom": {
"autoscan": true,
"custom": {
"^smoke-record-dialog$": "@/components/smoke-record-dialog/smoke-record-dialog.vue"
}
}
}
```
**组件文档**
- [x] 创建 `components/smoke-record-dialog/README.md`
- [x] 包含使用示例、Props 说明、Events 说明
- [x] 创建 `components/README.md` 全局组件使用指南
#### 4.1.3 API 集成
**API 封装** (`api/smoke.js`)
- [x] `createLog(data)` - POST /api/v1/smoke/logs
- 支持抽烟记录 (num > 0)
- 支持忍住记录 (num = 0, level = 0)
- [ ] `updateLog(id, data)` - PUT /api/v1/smoke/logs/:id
- [ ] `deleteLog(id)` - DELETE /api/v1/smoke/logs/:id
- [x] `getLatestLogs(limit)` - GET /api/v1/smoke/logs/latest
**首页集成** (`pages/index/index.vue`)
- [x] 引入组件 (easycom 自动导入)
- [x] 双向绑定 show 状态
- [x] 区分两种模式
```vue
<smoke-record-dialog
v-model:show="showDialog"
:type="dialogType"
@submit="handleSubmit"
/>
```
- [x] 提交处理
- 调用 API 创建记录
- 更新 dashboard store 数据
- 抽烟: incrementTodayCount()
- 抽烟: resetTimer()
- 显示成功提示
- 关闭弹框
**性能优化**
- [x] 组件懒加载 (easycom 按需加载)
- [x] 表单数据仅在打开时初始化
- [x] 提交后自动关闭
---
### 4.2 Day 2: 历史记录页
#### 4.2.1 页面结构 (`pages/logs/index.vue`)
**顶部导航**
- [ ] 导航栏标题 "历史记录"
- [ ] 筛选 Tabs 组件
```javascript
tabs: [
{ id: 'all', name: '全部' },
{ id: 'smoke', name: '已抽烟', filter: (item) => item.num > 0 },
{ id: 'resisted', name: '已忍住', filter: (item) => item.num === 0 }
]
```
**列表容器**
- [ ] scroll-view 组件
- [ ] 下拉刷新 (refresher-enabled)
- [ ] 上拉加载更多
- [ ] 空状态提示
#### 4.2.2 数据层
**Store 设计** (`stores/logs.js`)
```javascript
{
state: {
logs: [], // 记录列表
total: 0, // 总条数
page: 1, // 当前页
pageSize: 20, // 每页数量
hasMore: true, // 是否有更多
loading: false // 加载状态
},
getters: {
groupedByDate: (state) => {
// 按日期分组
// { '2025-01-25': [...], '2025-01-24': [...] }
},
smokeCount: (state) => {
// 抽烟记录数量
},
resistedCount: (state) => {
// 忍住记录数量
}
},
actions: {
async fetchLogs(refresh = false),
async loadMore(),
async deleteLog(id),
clearLogs()
}
}
```
**API 调用**
- [ ] `getLogs({ page, page_size, start, end })`
- [ ] `getLatestLogs(limit)` - 首次快速加载
- [ ] `deleteLog(id)`
#### 4.2.3 记录卡片组件 (`components/log-item/log-item.vue`)
**卡片布局**
```
┌─────────────────────────────────────┐
│ 🚬 14:30 3 支 │
│ 压力大、工作繁忙 │
│ 距上次 2小时15分 │
└─────────────────────────────────────┘
```
**字段显示**
- [ ] 类型图标
- 🚬 抽烟 (num > 0)
- 💪 忍住 (num = 0)
- [ ] 时间显示
- 格式: HH:mm
- 今天/昨天/具体日期
- [ ] 数量显示 (抽烟时)
- `${num} 支`
- 烟瘾等级 (1-5 级)
- [ ] 备注内容
- 单行显示,超出省略
- 最多显示 50 字符
- [ ] 间隔时间
- 距上一条记录的时间差
- 格式: "X小时Y分" / "X分钟"
**卡片样式**
- [ ] 白色背景
- [ ] 圆角 16rpx
- [ ] 阴影效果
- [ ] 抽烟/忍住不同边框色
- 抽烟: 红色左边框
- 忍住: 绿色左边框
#### 4.2.4 左滑操作
**左滑按钮**
- [ ] 使用 uni-ui 的 uni-swipe-action
- [ ] 编辑按钮 (蓝色)
- 打开编辑弹框
- 预填充当前数据
- [ ] 删除按钮 (红色)
- 显示确认对话框
- 调用删除 API
- 更新列表数据
**编辑功能**
- [ ] 复用 smoke-record-dialog 组件
- [ ] 添加 recordId 和 mode props
```vue
<smoke-record-dialog
v-model:show="showEditDialog"
:type="editType"
:record-id="editRecordId"
mode="edit"
@submit="handleUpdate"
/>
```
- [ ] 预填充数据
- [ ] 调用 updateLog API
- [ ] 刷新列表
**删除功能**
- [ ] uni.showModal 确认对话框
- [ ] 调用 deleteLog API
- [ ] 乐观更新 (先删除本地数据)
- [ ] 失败时回滚
#### 4.2.5 日期分组
**分组逻辑**
```javascript
function groupByDate(logs) {
const groups = {}
logs.forEach(log => {
const date = formatDate(log.smoke_time)
if (!groups[date]) {
groups[date] = {
date,
displayDate: getDisplayDate(date), // 今天/昨天/MM-DD
logs: []
}
}
groups[date].logs.push(log)
})
return Object.values(groups)
}
```
**渲染结构**
```vue
<view class="date-group" v-for="group in groupedLogs" :key="group.date">
<view class="date-header">{{ group.displayDate }}</view>
<log-item
v-for="log in group.logs"
:key="log.id"
:data="log"
@edit="handleEdit"
@delete="handleDelete"
/>
</view>
```
#### 4.2.6 加载状态
**下拉刷新**
- [ ] refresher-triggered 状态控制
- [ ] 重置 page = 1
- [ ] 清空现有数据
- [ ] 调用 fetchLogs(true)
- [ ] 完成后关闭刷新状态
**上拉加载**
- [ ] onReachBottom 触发
- [ ] 检查 hasMore 状态
- [ ] page++
- [ ] 调用 loadMore()
- [ ] 追加数据到列表
**加载骨架屏**
- [ ] 初次加载显示
- [ ] 3-5 个卡片骨架
- [ ] shimmer 动画效果
**空状态**
- [ ] 无数据时显示
- [ ] 空状态图标 + 文案
- [ ] 引导按钮 "去记录"
#### 4.2.7 浮动操作按钮
**新增按钮**
- [ ] 固定在右下角
- [ ] 圆形按钮 (96rpx)
- [ ] 图标
- [ ] 点击打开记录弹框
- [ ] 阴影 + 缩放动画
**样式**
```css
.fab {
position: fixed;
right: 32rpx;
bottom: 120rpx; /* 避开 tabbar */
width: 96rpx;
height: 96rpx;
background: #10B981;
border-radius: 50%;
box-shadow: 0 8rpx 24rpx rgba(16, 185, 129, 0.4);
}
```
#### 4.2.8 性能优化
**列表优化**
- [ ] 虚拟列表 (数据量 > 100 时)
- [ ] 分页加载 (每页 20 条)
- [ ] 图片懒加载 (如有头像等)
**缓存策略**
- [ ] 首次加载使用 getLatestLogs (快速)
- [ ] 后续使用分页接口
- [ ] 缓存最近 3 页数据
- [ ] 超过 5 分钟刷新缓存
**用户体验**
- [ ] 乐观更新 (删除/编辑)
- [ ] Loading 状态提示
- [ ] 错误处理 + 重试按钮
- [ ] 防抖处理 (下拉刷新/上拉加载)
---
### 4.3 验收标准
**记录功能**
- [x] 弹框动画流畅 (< 300ms)
- [x] 表单提交成功率 > 99%
- [x] 支持快速记录 (< 3 步)
- [ ] 编辑/删除操作正常
**历史记录页**
- [ ] 列表加载 < 1s
- [ ] 滚动流畅 (60fps)
- [ ] 分组显示正确
- [ ] 筛选功能正常
- [ ] 下拉刷新/上拉加载正常
**数据同步**
- [ ] 新增记录后首页数据实时更新
- [ ] 删除记录后列表实时更新
- [ ] 编辑记录后详情实时更新
**异常处理**
- [ ] 网络异常提示
- [ ] 删除失败回滚
- [ ] 空状态正确显示
**交付物**
- ✅ smoke-record-dialog 组件 (已完成)
- ✅ 组件文档和使用指南 (已完成)
- ✅ 首页记录功能集成 (已完成)
- [ ] 历史记录页完整功能
- [ ] log-item 组件
- [ ] logs store 状态管理
- [ ] 编辑/删除功能
---
### 4.4 Phase 3 技术要点与最佳实践
#### 4.4.1 组件设计原则
**组件命名规范**
- ✅ 使用 kebab-case: `smoke-record-dialog`
- ✅ 目录结构: `components/smoke-record-dialog/smoke-record-dialog.vue`
- ❌ 避免 PascalCase: `SmokeRecordDialog.vue` (微信小程序依赖分析问题)
**组件 API 风格**
- ✅ 使用 Options API (更好的兼容性)
- ✅ 支持 v-model:show 双向绑定
- ✅ 使用 @submit 事件传递数据
- ✅ Props 类型校验完整
**组件复用性**
- 通过 props.type 区分模式 ('smoke' / 'resisted')
- 表单字段根据模式动态显示/隐藏
- 提交数据格式统一,由组件内部处理差异
#### 4.4.2 状态管理策略
**Store 职责划分**
```javascript
// dashboard.js - 首页数据
{
todayCount, // 今日抽烟数
minutesSinceLast, // 距上次时间
nextSmokeTime, // 下次建议时间
actions: {
incrementTodayCount(),
resetTimer()
}
}
// logs.js - 历史记录
{
logs, // 记录列表
page, total, hasMore, // 分页信息
actions: {
fetchLogs(),
loadMore(),
deleteLog()
}
}
// user.js - 用户信息
{
user, // 用户基本信息
token, // 认证令牌
isLogin // 登录状态
}
```
**数据流向**
```
用户操作 → 组件 emit → 页面处理 → 调用 API
更新 Store ← API 响应
触发视图更新
```
#### 4.4.3 API 错误处理
**统一错误处理** (`api/request.js`)
```javascript
// 已实现
- Token 失效自动刷新
- 网络错误重试 (最多 3 次)
- 错误码统一处理
- Toast 提示
// 需要注意
- 记录提交失败要保留用户输入
- 删除失败要回滚本地状态
- 编辑冲突要提示用户
```
**乐观更新 vs 悲观更新**
- 删除操作: 乐观更新 (先删除,失败回滚)
- 新增操作: 悲观更新 (成功后添加)
- 编辑操作: 悲观更新 (成功后更新)
#### 4.4.4 性能优化清单
**组件层面**
- [x] easycom 按需加载
- [x] 弹框懒加载 (打开时才初始化数据)
- [ ] 虚拟列表 (历史记录 > 100 条)
- [ ] 图片懒加载
**请求层面**
- [ ] 并行请求 (多个接口同时调用)
- [ ] 请求缓存 (5 分钟内复用)
- [ ] 防抖处理 (快速点击)
- [ ] 请求取消 (页面离开时)
**渲染层面**
- [ ] 分页加载 (每页 20 条)
- [ ] 骨架屏过渡
- [ ] 平滑滚动
- [ ] 动画性能优化 (CSS transform)
#### 4.4.5 用户体验优化
**反馈机制**
- 提交成功: Toast 提示 + 自动关闭弹框
- 提交失败: Toast 提示 + 保留输入内容
- 删除确认: Modal 二次确认
- 加载状态: Loading + 禁用按钮
**快捷操作**
- 首页快速记录按钮 (2 个按钮对应 2 种模式)
- 历史记录页浮动新增按钮
- 左滑快速删除/编辑
- 下拉刷新快速更新
**引导提示**
- 首次使用引导
- 空状态引导
- 错误状态引导
- 功能提示
#### 4.4.6 测试要点
**单元测试**
- [ ] 组件 props 验证
- [ ] 表单数据初始化
- [ ] 日期分组逻辑
- [ ] 时间格式化函数
**集成测试**
- [ ] 记录提交流程
- [ ] 编辑/删除流程
- [ ] 分页加载流程
- [ ] 筛选切换流程
**E2E 测试场景**
```
场景 1: 快速记录抽烟
1. 点击"记录抽烟"按钮
2. 不修改默认值
3. 直接提交
4. 验证首页数据更新
场景 2: 详细记录
1. 点击"记录抽烟"按钮
2. 修改时间、数量、等级
3. 输入备注
4. 提交
5. 在历史记录页验证
场景 3: 编辑记录
1. 进入历史记录页
2. 左滑某条记录
3. 点击编辑
4. 修改内容
5. 提交
6. 验证更新成功
场景 4: 删除记录
1. 进入历史记录页
2. 左滑某条记录
3. 点击删除
4. 确认删除
5. 验证列表更新
```
#### 4.4.7 常见问题与解决方案
**问题 1: 微信小程序组件依赖分析错误**
```
错误: components/SmokeRecordDialog.js 已被代码依赖分析忽略
解决:
1. 使用 kebab-case 命名
2. 组件放在同名文件夹内
3. 配置 easycom 自动导入
4. 使用 Options API
```
**问题 2: 弹框关闭时数据未重置**
```
原因: 组件销毁前未清理数据
解决: watch show 变化,false 时清理数据
```
**问题 3: 列表滚动性能差**
```
原因: 数据量大,DOM 节点过多
解决:
1. 虚拟列表
2. 分页加载
3. 使用 CSS transform 优化动画
```
**问题 4: 删除后列表显示错误**
```
原因: 本地状态未同步
解决: 乐观更新时正确处理索引
```
#### 4.4.8 安全注意事项
**输入校验**
- 时间范围验证 (不能是未来时间)
- 数量范围验证 (1-99)
- 备注长度限制 (200 字符)
- XSS 防护 (转义用户输入)
**权限控制**
- 只能编辑/删除自己的记录
- Token 验证
- 接口鉴权
**数据保护**
- 敏感信息脱敏
- 本地存储加密
- HTTPS 传输
---
## 5. Phase 4: 统计与图表 (2天)
### 5.1 Day 1: 统计页基础
#### 时间范围切换
- [ ] 周/月/年 Tabs
- [ ] 日期范围计算
- [ ] 数据请求 (`GET /dashboard?start=&end=`)
#### 吸烟趋势图
- [ ] 集成 uCharts / ECharts
- [ ] 柱状图组件封装
- [ ] 数据格式转换
#### 每周洞察卡片
- [ ] AI 分析展示 (异步加载)
### 5.2 Day 2: 详细指标
#### 健康与储蓄卡片
- [ ] 节省金额计算 + 环形进度
- [ ] 肺部功能恢复 + 环形进度
#### 成就卡片
- [ ] 连续记录天数
- [ ] 已拒绝次数
#### 趋势对比
- [ ] 周同比变化计算
- [ ] 日均吸烟量
**交付物**:完整的统计页,图表正常显示
---
## 6. Phase 5: AI助手与个人中心 (3天)
### 6.1 Day 1: AI 助手页
#### 阶段进度卡片
- [ ] 阶段计算逻辑
- [ ] 进度条展示
- [ ] 天数倒计时
#### 每日 AI 分析
- [ ] 对话式 UI
- [ ] `GET /ai/advice` 集成
- [ ] 会员/广告解锁判断
#### 今日目标
- [ ] 任务列表
- [ ] 完成状态切换 (本地存储)
### 6.2 Day 2: 个人中心页
#### 用户信息
- [ ] 头像 + 昵称展示
- [ ] 目标戒烟日期
- [ ] 连续天数
#### 设置项
- [ ] 目标设定入口
- [ ] AI 计划调整入口
- [ ] 通知设置
- [ ] 会员解锁
#### 基础设置
- [ ] 作息时间设置
- [ ] 每包价格设置
### 6.3 Day 3: 新用户引导
#### 引导页面
- [ ] 分步表单 (5步)
- [ ] 进度指示器
- [ ] 动画过渡
#### 数据收集
- [ ] 日均吸烟量
- [ ] 烟龄
- [ ] 抽烟/戒烟动机
- [ ] 作息时间
#### 提交流程
- [ ] `PUT /profile` 提交
- [ ] 完成后跳转首页
**交付物**:AI助手页、个人中心页、引导流程完整
---
## 7. Phase 6: 优化与测试 (2天)
### 7.1 Day 1: 性能优化
#### 首页优化
- [ ] 首屏时间 < 500ms 验证
- [ ] 图片懒加载
- [ ] 组件按需加载
#### 缓存优化
- [ ] 请求缓存策略检查
- [ ] 本地存储清理策略
#### 包体积
- [ ] 依赖分析
- [ ] 无用代码移除
- [ ] 分包加载配置
### 7.2 Day 2: 测试与修复
#### 功能测试
- [ ] 全流程测试 (新用户 → 日常使用)
- [ ] 边界情况测试
- [ ] 网络异常测试
#### UI 适配
- [ ] 不同机型测试
- [ ] 安全区域适配
#### Bug 修复
- [ ] 测试问题修复
- [ ] 体验优化
**交付物**:可发布的小程序版本
---
## 8. 开发优先级
按重要性和依赖关系排序:
```
P0 (必须完成):
├── 登录认证
├── 首页看板 (计时器 + 今日统计)
├── 记录抽烟/忍住
├── 历史记录查看
└── 新用户引导
P1 (核心功能):
├── 统计图表 (周视图)
├── 下次建议时间
├── 个人设置
└── 基础 AI 建议
P2 (增强功能):
├── 月/年统计
├── AI 时间节点
├── 会员/广告解锁
└── 通知提醒
P3 (未来迭代):
├── 成就系统
├── 社交分享
└── 数据导出
```
---
## 9. 技术风险与应对
| 风险 | 影响 | 应对措施 |
|------|------|----------|
| 首页加载慢 | 用户体验差 | 骨架屏 + 并行请求 + 缓存 |
| 图表库体积大 | 包体积超标 | 按需引入 + 分包 |
| AI 接口慢 | 等待时间长 | 异步加载 + Loading状态 |
| 网络不稳定 | 数据丢失 | 离线缓存 + 重试机制 |
| 微信审核不通过 | 延期上线 | 提前了解审核规范 |
---
## 10. 验收标准
### 首页
- [ ] 首屏渲染 < 500ms
- [ ] 计时器实时更新
- [ ] 记录操作 < 3步完成
### 记录
- [ ] 支持快速记录
- [ ] 支持编辑/删除
- [ ] 数据实时同步
### 统计
- [ ] 图表正常显示
- [ ] 数据计算准确
- [ ] 切换流畅
### 整体
- [ ] 无明显卡顿
- [ ] 无崩溃闪退
- [ ] 视觉符合设计稿
-434
View File
@@ -1,434 +0,0 @@
# Phase 3: 记录与历史 - 完成报告
## ✅ 开发完成情况
**开发时间**: 2025-01-25
**完成度**: 100% (Day 1 + Day 2)
---
## 📦 已完成功能
### Day 1: 记录表单组件 ✅
#### 1. smoke-record-dialog 组件
**文件**: `components/smoke-record-dialog/smoke-record-dialog.vue`
**功能清单**:
- ✅ 底部弹出动画 (300ms 平滑过渡)
- ✅ 明亮主题 UI (白色背景 + #10B981 主题色)
- ✅ 双向绑定 (v-model:show)
- ✅ 两种模式支持
- type="smoke": 记录抽烟
- type="resisted": 想抽忍住了
- ✅ 完整表单字段
- 日期时间选择 (默认当前时间)
- 数量选择 (加减按钮 + 输入框)
- 烟瘾等级选择 (1-5 级)
- 备注输入 (最大 200 字符)
- ✅ 编辑模式支持
- initialData prop 预填充数据
- 支持修改现有记录
- ✅ 表单验证和提交
- ✅ easycom 自动导入配置
**API 集成**:
- ✅ createLog - 新增记录
- ✅ updateLog - 更新记录 (新增)
- ✅ deleteLog - 删除记录 (新增)
**文档**:
-`components/smoke-record-dialog/README.md`
-`components/README.md`
-`CHANGELOG_COMPONENT.md`
---
### Day 2: 历史记录页 ✅
#### 1. logs Store
**文件**: `stores/logs.js`
**状态管理**:
```javascript
{
logs: [], // 记录列表
total: 0, // 总条数
page: 1, // 当前页
pageSize: 20, // 每页数量
hasMore: true, // 是否有更多
loading: false, // 加载状态
refreshing: false // 刷新状态
}
```
**Getters**:
- ✅ groupedByDate - 按日期分组记录
- ✅ smokeCount - 抽烟记录数量
- ✅ resistedCount - 忍住记录数量
- ✅ formattedLogs - 格式化记录列表(包含间隔时间计算)
**Actions**:
- ✅ fetchLogs - 获取记录列表
- ✅ loadMore - 加载更多
- ✅ deleteLog - 删除记录(乐观更新)
- ✅ updateLog - 更新记录
- ✅ clearLogs - 清空列表
#### 2. 历史记录页面
**文件**: `pages/logs/index.vue`
**核心功能**:
- ✅ 筛选 Tabs
- 全部
- 已抽烟
- 已忍住
- ✅ 时间轴布局
- 按日期分组显示
- 日期标签(今天/昨天/日期)
- 时间线连接线
- 类型图标(💪 忍住 / 🚬 抽烟)
- ✅ 记录卡片
- 类型标题
- 时间显示 (HH:mm)
- 数量和等级(抽烟时)
- 备注内容
- 间隔时间显示
- 操作按钮(编辑/删除)
- ✅ 下拉刷新
- ✅ 上拉加载更多
- ✅ 骨架屏加载状态
- ✅ 空状态提示
- ✅ 浮动新增按钮
- ✅ 编辑功能
- 打开编辑弹框
- 预填充数据
- 更新记录
- ✅ 删除功能
- 确认对话框
- 乐观更新
- 失败回滚
**UI 优化**:
- ✅ 明亮主题(渐变背景 #D1FAE5#FFFFFF
- ✅ 白色卡片 + 阴影
- ✅ 彩色边框(绿色=忍住,红色=抽烟)
- ✅ 流畅动画效果
- ✅ 响应式布局
---
## 🎨 UI/UX 改进
### 配色方案更新
**旧配色(深色主题)**:
- 背景: #0D1F17 (深绿黑)
- 卡片: #1A3325 (深绿)
- 主题色: #4ADE80 (亮绿)
**新配色(明亮主题)**:
- 背景: 渐变 #D1FAE5#F0FDF4#FFFFFF
- 卡片: #FFFFFF (白色 + 阴影)
- 主题色: #10B981 (翡翠绿)
- 文字: #1F2937 (深灰)
- 次要文字: #6B7280 (中灰)
### 交互优化
1. **下拉刷新**
- 原生下拉刷新组件
- 加载状态提示
- 自动重置页码
2. **上拉加载**
- 触底自动加载
- hasMore 状态控制
- 加载中提示
- 没有更多提示
3. **编辑/删除**
- 卡片内置按钮
- 编辑: 蓝色背景
- 删除: 红色背景 + 确认对话框
- 乐观更新提升体验
4. **加载状态**
- 骨架屏(首次加载)
- shimmer 动画
- 空状态友好提示
---
## 🔧 技术实现
### 1. 组件规范
**命名**: kebab-case
```
✅ smoke-record-dialog
✅ log-item (虽然未单独组件化,但集成在页面中)
❌ SmokeRecordDialog
```
**目录结构**:
```
components/
└── smoke-record-dialog/
├── smoke-record-dialog.vue
└── README.md
```
**API 风格**: Options API
```javascript
export default {
name: 'SmokeRecordDialog',
props: { ... },
data() { ... },
methods: { ... }
}
```
### 2. 状态管理
**数据流**:
```
用户操作 → 页面事件 → Store Action → API 调用
Store 状态更新
视图自动刷新
```
**更新策略**:
- 新增记录: 悲观更新(成功后添加)
- 删除记录: 乐观更新(先删除,失败回滚)
- 编辑记录: 悲观更新(成功后更新)
- 列表刷新: 清空后重新获取
### 3. 性能优化
**实现的优化**:
- ✅ 分页加载(每页 20 条)
- ✅ 骨架屏过渡
- ✅ easycom 按需加载
- ✅ 防抖处理(下拉刷新)
- ✅ CSS transform 动画
**未实现(可选)**:
- ⏳ 虚拟列表(数据量 > 100 时)
- ⏳ 请求缓存(5 分钟)
- ⏳ 图片懒加载(目前无图片)
### 4. 错误处理
**已实现**:
- ✅ API 调用异常捕获
- ✅ Toast 错误提示
- ✅ 删除失败回滚
- ✅ 空状态处理
- ✅ 加载失败提示
---
## 📊 数据流程
### 新增记录
```
首页/历史页 → 点击按钮 → 打开弹框 → 填写表单
→ 提交 → createLog API → Store 更新 → 视图刷新
```
### 编辑记录
```
历史页 → 点击编辑 → 打开弹框 → 预填充数据
→ 修改 → updateLog API → Store 更新 → 视图刷新
```
### 删除记录
```
历史页 → 点击删除 → 确认对话框 → deleteLog API
→ 乐观更新(先删除) → 失败则刷新列表恢复
```
### 列表加载
```
进入页面 → fetchLogs(refresh=true) → 显示骨架屏
→ 获取数据 → 渲染列表
下拉刷新 → fetchLogs(refresh=true) → 重置页码
→ 清空列表 → 重新获取
上拉加载 → loadMore → page++ → 追加数据
```
---
## ✅ 验收测试
### 功能测试 ✅
**记录提交**:
- ✅ 快速记录(使用默认值)
- ✅ 完整记录(填写所有字段)
- ✅ 记录抽烟模式
- ✅ 记录忍住模式
- ✅ 时间选择功能
- ✅ 备注输入功能
**历史记录**:
- ✅ 列表正常显示
- ✅ 日期分组正确
- ✅ 筛选功能正常
- ✅ 下拉刷新正常
- ✅ 上拉加载正常
- ✅ 编辑记录正常
- ✅ 删除记录正常
### 性能测试 ✅
- ✅ 弹框动画 < 300ms
- ✅ 列表首次加载 < 1s(模拟数据)
- ✅ 滚动流畅(60fps
- ✅ 提交响应及时
### UI/UX 测试 ✅
- ✅ 明亮主题正确应用
- ✅ 操作反馈及时
- ✅ 错误提示友好
- ✅ 空状态显示正确
- ✅ 加载状态清晰
---
## 📁 文件清单
### 新增文件
```
stores/
└── logs.js ✅ Logs Store
components/
└── smoke-record-dialog/
├── smoke-record-dialog.vue ✅ 记录弹框组件
└── README.md ✅ 组件文档
docs/
├── PHASE3_SUMMARY.md ✅ Phase 3 总结
├── PHASE3_TODO.md ✅ 待办清单
└── PHASE3_COMPLETED.md ✅ 完成报告(本文件)
```
### 修改文件
```
pages/
└── logs/
└── index.vue ✅ 历史记录页
pages/
└── index/
└── index.vue ✅ 首页(集成记录功能)
stores/
└── index.js ✅ 导出 logs store
pages.json ✅ easycom 配置
docs/
└── DEVELOPMENT.md ✅ 完善 Phase 3 文档
```
---
## 🎯 已完成的任务
### Day 1 任务 ✅
- [x] 创建 smoke-record-dialog 组件
- [x] 实现时间选择功能
- [x] 实现数量选择功能
- [x] 实现烟瘾等级选择
- [x] 实现备注输入
- [x] 底部弹出动画
- [x] 双向绑定支持
- [x] 两种模式支持
- [x] easycom 配置
- [x] 组件文档
- [x] 首页集成
### Day 2 任务 ✅
- [x] 创建 logs store
- [x] 实现状态管理
- [x] 历史记录页面布局
- [x] 筛选 Tabs 功能
- [x] 时间轴展示
- [x] 按日期分组
- [x] 记录卡片渲染
- [x] 编辑功能
- [x] 删除功能
- [x] 下拉刷新
- [x] 上拉加载
- [x] 骨架屏
- [x] 空状态
- [x] 浮动按钮
- [x] 明亮主题
---
## 🚀 下一步计划
Phase 3 已全部完成,可以进入 Phase 4: 统计与图表
### Phase 4 任务预览
1. 统计页基础布局
2. 时间范围切换(周/月/年)
3. 吸烟趋势图(集成图表库)
4. 健康与储蓄卡片
5. 成就卡片
6. 趋势对比
---
## 📝 开发笔记
### 遇到的问题
1. **微信小程序组件依赖错误**
- 问题: `SmokeRecordDialog.js` 被依赖分析忽略
- 解决: 使用 kebab-case 命名 + 目录结构 + easycom
2. **深色主题改为明亮主题**
- 调整了所有颜色值
- 添加了渐变背景
- 优化了阴影和边框
3. **编辑模式支持**
- 添加 initialData prop
- 在 initFormData 中判断是否有初始数据
- 预填充表单字段
### 最佳实践
1. **组件设计**
- 单一职责原则
- Props 清晰定义
- 事件命名规范
- 支持扩展
2. **状态管理**
- Store 职责明确
- Getters 处理计算逻辑
- Actions 异步操作
- 乐观/悲观更新策略
3. **用户体验**
- 操作反馈及时
- 加载状态清晰
- 错误提示友好
- 空状态引导
---
**完成时间**: 2025-01-25
**开发者**: AI Assistant
**状态**: ✅ 已完成并测试通过
-368
View File
@@ -1,368 +0,0 @@
# Phase 3: 记录与历史 - 开发总结
## 📋 概览
Phase 3 主要实现记录功能和历史记录页面,是用户日常使用的核心功能。
**开发周期**: 2 天
**当前进度**: Day 1 已完成 80%Day 2 待开始
---
## ✅ 已完成功能 (Day 1)
### 1. smoke-record-dialog 组件
**文件位置**: `components/smoke-record-dialog/smoke-record-dialog.vue`
**核心特性**:
- ✅ 底部弹出动画 (300ms 平滑过渡)
- ✅ 明亮主题 UI (白色背景 + #10B981 主题色)
- ✅ 支持两种模式
- `type="smoke"`: 记录抽烟 (显示数量、等级)
- `type="resisted"`: 想抽忍住了 (num=0)
- ✅ 表单字段
- 日期时间选择器 (默认当前时间)
- 数量选择 (加减按钮 + 输入框)
- 烟瘾等级 (1-5 级按钮组)
- 备注输入 (最大 200 字符)
- ✅ 数据验证和提交
- ✅ easycom 自动导入配置
**使用示例**:
```vue
<smoke-record-dialog
v-model:show="showDialog"
:type="dialogType"
@submit="handleSubmit"
/>
```
### 2. API 集成
**已实现**:
-`createLog(data)` - 新增记录
-`getLatestLogs(limit)` - 获取最近记录
-`updateLog(id, data)` - 更新记录 (API 已定义,待集成)
-`deleteLog(id)` - 删除记录 (API 已定义,待集成)
### 3. 首页集成
**文件位置**: `pages/index/index.vue`
**已实现**:
- ✅ 两个快捷按钮
- "记录抽烟" → 打开弹框 (type="smoke")
- "想抽忍住了" → 打开弹框 (type="resisted")
- ✅ 提交后数据更新
- 更新今日抽烟数
- 重置计时器
- 显示成功提示
### 4. 文档
**已创建**:
-`components/smoke-record-dialog/README.md` - 组件文档
-`components/README.md` - 全局组件使用指南
-`CHANGELOG_COMPONENT.md` - 组件错误修复说明
---
## 📝 待完成功能 (Day 2)
### 1. 历史记录页面
**文件位置**: `pages/logs/index.vue`
**核心功能**:
```
┌─────────────────────────────────────┐
│ 历史记录 │
│ ───────────────────────────────── │
│ [全部] [已抽烟] [已忍住] │
│ ───────────────────────────────── │
│ │
│ 今天 │
│ ┌────────────────────────────┐ │
│ │ 🚬 14:30 3 支 │ │
│ │ 压力大、工作繁忙 │ │
│ │ 距上次 2小时15分 │ │
│ └────────────────────────────┘ │
│ ┌────────────────────────────┐ │
│ │ 💪 12:15 │ │
│ │ 想抽但忍住了 │ │
│ │ 距上次 30分钟 │ │
│ └────────────────────────────┘ │
│ │
│ 昨天 │
│ ┌────────────────────────────┐ │
│ │ 🚬 18:00 2 支 │ │
│ │ 下班应酬 │ │
│ └────────────────────────────┘ │
│ │
│ [+] │
└─────────────────────────────────────┘
```
**任务清单**:
- [ ] 页面布局和导航
- [ ] 筛选 Tabs (全部/已抽烟/已忍住)
- [ ] 按日期分组显示
- [ ] 记录卡片组件 (log-item)
- [ ] 左滑操作 (编辑/删除)
- [ ] 下拉刷新
- [ ] 上拉加载更多
- [ ] 浮动新增按钮
- [ ] 空状态提示
### 2. log-item 组件
**文件位置**: `components/log-item/log-item.vue`
**显示内容**:
- 类型图标 (🚬 抽烟 / 💪 忍住)
- 时间 (HH:mm)
- 数量 (X 支) + 烟瘾等级
- 备注内容
- 间隔时间 (距上次 X 小时 Y 分)
- 左滑按钮 (编辑/删除)
### 3. logs Store
**文件位置**: `stores/logs.js`
**状态管理**:
```javascript
{
logs: [], // 记录列表
total: 0, // 总数
page: 1, // 当前页
pageSize: 20, // 每页条数
hasMore: true, // 是否有更多
loading: false, // 加载状态
getters: {
groupedByDate, // 按日期分组
smokeCount, // 抽烟记录数
resistedCount // 忍住记录数
},
actions: {
fetchLogs, // 获取记录
loadMore, // 加载更多
deleteLog, // 删除记录
updateLog // 更新记录
}
}
```
### 4. 编辑功能
**复用组件**: `smoke-record-dialog`
**新增 Props**:
```javascript
{
mode: 'create' | 'edit', // 模式
recordId: Number, // 记录 ID (编辑时)
initialData: Object // 初始数据 (编辑时)
}
```
**流程**:
1. 点击编辑按钮
2. 打开弹框,预填充数据
3. 修改内容
4. 调用 updateLog API
5. 更新列表数据
### 5. 删除功能
**流程**:
1. 左滑显示删除按钮
2. 点击删除
3. 显示确认对话框
4. 确认后调用 deleteLog API
5. 乐观更新列表 (失败时回滚)
---
## 🎯 开发优先级
### P0 (必须完成)
- [ ] 历史记录页面基础布局
- [ ] 记录列表显示
- [ ] 分页加载
- [ ] 删除功能
### P1 (核心功能)
- [ ] 编辑功能
- [ ] 筛选功能
- [ ] 日期分组
- [ ] 下拉刷新
### P2 (体验优化)
- [ ] 骨架屏
- [ ] 空状态
- [ ] 加载动画
- [ ] 错误处理
---
## 🔧 技术要点
### 1. 组件规范
**命名规范**:
- ✅ kebab-case: `smoke-record-dialog`, `log-item`
- ✅ 目录结构: `components/xxx/xxx.vue`
- ❌ 避免: PascalCase 单文件组件
**API 风格**:
- ✅ Options API (兼容性)
- ✅ v-model 双向绑定
- ✅ 事件传递数据
### 2. 状态管理
**数据流**:
```
用户操作 → 组件事件 → 页面处理 → API 调用
Store 更新 ← API 响应
视图自动更新
```
**更新策略**:
- 新增: 悲观更新 (成功后添加)
- 删除: 乐观更新 (先删除,失败回滚)
- 编辑: 悲观更新 (成功后更新)
### 3. 性能优化
**列表优化**:
- 分页加载 (每页 20 条)
- 虚拟列表 (数据量 > 100)
- 图片懒加载
- 防抖处理
**请求优化**:
- 请求缓存 (5 分钟)
- 并行请求
- 请求取消 (页面离开)
**渲染优化**:
- 骨架屏过渡
- CSS transform 动画
- 平滑滚动
### 4. 用户体验
**反馈机制**:
- 操作成功: Toast + 自动关闭
- 操作失败: Toast + 保留输入
- 删除确认: Modal 二次确认
- 加载状态: Loading + 禁用按钮
**快捷操作**:
- 首页快速记录 (2 个按钮)
- 历史页浮动按钮 (+)
- 左滑快速编辑/删除
- 下拉刷新
---
## 🧪 测试清单
### 功能测试
**记录提交**:
- [ ] 快速记录 (使用默认值)
- [ ] 完整记录 (填写所有字段)
- [ ] 记录抽烟
- [ ] 记录忍住
- [ ] 时间选择
- [ ] 备注输入
**历史记录**:
- [ ] 列表显示
- [ ] 日期分组
- [ ] 筛选切换
- [ ] 下拉刷新
- [ ] 上拉加载
- [ ] 编辑记录
- [ ] 删除记录
### 边界测试
- [ ] 空数据状态
- [ ] 网络异常
- [ ] 提交失败
- [ ] 删除失败
- [ ] 并发操作
- [ ] 快速点击
### 兼容性测试
- [ ] iOS 系统
- [ ] Android 系统
- [ ] 不同机型
- [ ] 不同屏幕尺寸
- [ ] 安全区域适配
---
## 📊 验收标准
### 性能指标
- [ ] 弹框动画 < 300ms
- [ ] 列表首次加载 < 1s
- [ ] 滚动帧率 60fps
- [ ] 提交成功率 > 99%
### 功能完整性
- [ ] 记录提交 ✅
- [ ] 记录编辑 ⏳
- [ ] 记录删除 ⏳
- [ ] 列表分页 ⏳
- [ ] 数据筛选 ⏳
### 用户体验
- [ ] 操作流畅无卡顿
- [ ] 反馈及时明确
- [ ] 错误提示友好
- [ ] 视觉符合设计稿
---
## 📖 相关文档
- [完整开发计划](./DEVELOPMENT.md)
- [API 文档](./api.md)
- [组件使用指南](../components/README.md)
- [smoke-record-dialog 组件文档](../components/smoke-record-dialog/README.md)
- [组件错误修复说明](../CHANGELOG_COMPONENT.md)
---
## 🚀 下一步
1. **开始 Day 2 开发**
- 创建历史记录页面
- 实现 log-item 组件
- 创建 logs store
2. **功能开发顺序**
- 列表基础显示 → 分页加载 → 删除功能 → 编辑功能 → 筛选功能
3. **测试与优化**
- 功能测试
- 性能测试
- 用户体验优化
---
**更新时间**: 2025-01-25
**负责人**: 开发团队
**状态**: Day 1 完成,Day 2 进行中
-270
View File
@@ -1,270 +0,0 @@
# Phase 3: 记录与历史 - 待办清单
> 快速查看待完成任务,详细说明请参考 [DEVELOPMENT.md](./DEVELOPMENT.md)
## Day 1: 记录表单组件 ✅
### smoke-record-dialog 组件
- [x] 组件结构和布局
- [x] 时间选择器 (日期 + 时间)
- [x] 数量选择器 (加减按钮)
- [x] 烟瘾等级选择 (1-5 级)
- [x] 备注输入框
- [x] 底部弹出动画
- [x] 双向绑定 (v-model:show)
- [x] 两种模式支持 (smoke/resisted)
- [x] 数据提交逻辑
### 配置和文档
- [x] easycom 自动导入配置
- [x] 组件文档 (README.md)
- [x] 使用示例和说明
- [x] 错误修复文档
### 首页集成
- [x] 导入组件
- [x] 两个快捷按钮
- [x] 提交处理逻辑
- [x] Dashboard 数据更新
### API 封装
- [x] createLog API
- [x] getLatestLogs API
- [ ] updateLog API (已定义,待集成)
- [ ] deleteLog API (已定义,待集成)
---
## Day 2: 历史记录页 ⏳
### 页面结构 (`pages/logs/index.vue`)
- [ ] 创建页面文件
- [ ] 导航栏配置
- [ ] 页面基础布局
- [ ] scroll-view 容器
### 筛选功能
- [ ] Tabs 组件
- [ ] 全部
- [ ] 已抽烟
- [ ] 已忍住
- [ ] 筛选逻辑实现
- [ ] 切换动画
### 数据层 (`stores/logs.js`)
- [ ] 创建 store 文件
- [ ] State 定义
```javascript
{
logs: [],
total: 0,
page: 1,
pageSize: 20,
hasMore: true,
loading: false
}
```
- [ ] Getters 实现
- [ ] groupedByDate (按日期分组)
- [ ] smokeCount (抽烟记录数)
- [ ] resistedCount (忍住记录数)
- [ ] Actions 实现
- [ ] fetchLogs (获取记录列表)
- [ ] loadMore (加载更多)
- [ ] deleteLog (删除记录)
- [ ] updateLog (更新记录)
- [ ] clearLogs (清空列表)
### log-item 组件 (`components/log-item/log-item.vue`)
- [ ] 创建组件文件
- [ ] 卡片布局
- [ ] 类型图标显示 (🚬/💪)
- [ ] 时间显示 (HH:mm)
- [ ] 数量和等级显示
- [ ] 备注内容显示
- [ ] 间隔时间计算
- [ ] 样式实现
- [ ] 基础样式
- [ ] 抽烟/忍住边框色
- [ ] 响应式布局
### 左滑操作
- [ ] 安装/导入 uni-swipe-action
- [ ] 左滑菜单
- [ ] 编辑按钮 (蓝色)
- [ ] 删除按钮 (红色)
- [ ] 编辑功能
- [ ] 打开编辑弹框
- [ ] 预填充数据
- [ ] 调用 updateLog API
- [ ] 更新列表
- [ ] 删除功能
- [ ] 确认对话框
- [ ] 调用 deleteLog API
- [ ] 乐观更新
- [ ] 失败回滚
### 日期分组
- [ ] groupByDate 函数
- [ ] 日期格式化
- [ ] 今天
- [ ] 昨天
- [ ] MM-DD
- [ ] 分组渲染
- [ ] 日期头部样式
### 加载状态
- [ ] 骨架屏组件
- [ ] 卡片骨架
- [ ] shimmer 动画
- [ ] 下拉刷新
- [ ] refresher 配置
- [ ] 刷新逻辑
- [ ] 重置页码
- [ ] 上拉加载
- [ ] onReachBottom 处理
- [ ] hasMore 检查
- [ ] 加载动画
- [ ] 空状态
- [ ] 空状态图标
- [ ] 提示文案
- [ ] 引导按钮
### 浮动按钮
- [ ] 固定定位
- [ ] 样式实现
- [ ] 圆形按钮
- [ ] 阴影效果
- [ ] 动画效果
- [ ] 点击打开记录弹框
- [ ] 避开 tabbar
### 性能优化
- [ ] 虚拟列表 (可选)
- [ ] 图片懒加载 (如有)
- [ ] 请求缓存
- [ ] 防抖处理
- [ ] 请求取消
### 错误处理
- [ ] 网络异常提示
- [ ] 加载失败重试
- [ ] 删除失败回滚
- [ ] 表单验证
---
## 测试任务 ⏳
### 功能测试
- [ ] 记录提交
- [ ] 快速记录 (默认值)
- [ ] 完整记录
- [ ] 抽烟模式
- [ ] 忍住模式
- [ ] 历史记录
- [ ] 列表显示
- [ ] 分页加载
- [ ] 筛选功能
- [ ] 编辑记录
- [ ] 删除记录
### 边界测试
- [ ] 空数据状态
- [ ] 网络异常
- [ ] 提交失败
- [ ] 删除失败
- [ ] 并发操作
- [ ] 快速点击
### 性能测试
- [ ] 弹框动画 < 300ms
- [ ] 列表加载 < 1s
- [ ] 滚动流畅度 (60fps)
- [ ] 长列表性能
### 兼容性测试
- [ ] iOS 系统
- [ ] Android 系统
- [ ] 不同机型
- [ ] 安全区域适配
---
## 文档任务 ✅
- [x] 完善 DEVELOPMENT.md Phase 3 部分
- [x] 创建 PHASE3_SUMMARY.md
- [x] 创建 PHASE3_TODO.md
- [x] 组件使用文档
- [x] API 集成说明
---
## 进度统计
**总任务**: ~60 个
**已完成**: ~60 个 (100%) ✅
**进行中**: 0 个
**待开始**: 0 个
**Day 1 进度**: ✅ 100% 完成
**Day 2 进度**: ✅ 100% 完成
---
## 优先级标记
- 🔴 P0 - 必须完成
- 🟡 P1 - 核心功能
- 🟢 P2 - 体验优化
### P0 任务
- [ ] 🔴 历史记录页面基础布局
- [ ] 🔴 记录列表显示
- [ ] 🔴 分页加载功能
- [ ] 🔴 删除功能
- [ ] 🔴 logs store 创建
### P1 任务
- [ ] 🟡 编辑功能
- [ ] 🟡 筛选功能
- [ ] 🟡 日期分组
- [ ] 🟡 下拉刷新
- [ ] 🟡 log-item 组件
### P2 任务
- [ ] 🟢 骨架屏
- [ ] 🟢 空状态
- [ ] 🟢 加载动画
- [ ] 🟢 虚拟列表
- [ ] 🟢 错误处理优化
---
## 开发建议
1. **Day 2 开发顺序**
```
创建页面 → 数据层 → 组件 → 功能 → 优化
```
2. **最小可用版本**
- 先实现基础列表显示
- 再添加删除功能
- 最后优化体验
3. **并行开发**
- log-item 组件可独立开发
- logs store 可先完成
- 页面布局和组件同步进行
4. **测试策略**
- 边开发边测试
- 功能完成后集成测试
- 最后进行性能测试
---
**更新时间**: 2025-01-25
**下次更新**: 完成 Day 2 开发后
-378
View File
@@ -1,378 +0,0 @@
# Phase 3 功能使用指南
## 📖 用户操作指南
### 1. 记录抽烟
#### 方式一:从首页快速记录
1. 打开小程序,进入首页
2. 点击「记录抽烟」按钮
3. 弹出记录表单:
- **时间**: 默认当前时间,可修改日期和时间
- **数量**: 默认 1 支,可通过 +/- 调整或直接输入
- **烟瘾等级**: 选择 1-5 级(默认 2 级)
- **备注**: 选填,最多 200 字符
4. 点击「确定」提交
5. 提示"记录成功",首页数据自动更新
#### 方式二:从历史记录页新增
1. 切换到「记录」标签页
2. 点击右下角浮动 按钮
3. 跳转到首页进行记录
### 2. 记录想抽忍住了
#### 从首页记录
1. 打开小程序,进入首页
2. 点击「想抽忍住了」按钮(绿色)
3. 弹出记录表单:
- **时间**: 默认当前时间,可修改
- **备注**: 记录抵抗心得或当时的想法
- 数量和等级不显示(自动设置为 num=0, level=2
4. 点击「确定」提交
5. 提示"太棒了!"
### 3. 查看历史记录
1. 切换到「记录」标签页
2. 查看所有记录,按日期分组显示
3. 可以通过顶部标签筛选:
- **全部**: 显示所有记录
- **已抽烟**: 只显示抽烟记录
- **已忍住**: 只显示忍住记录
#### 记录卡片信息
每条记录显示:
- **类型图标**: 💪(忍住)或 🚬(抽烟)
- **类型标题**: "想抽忍住了" 或 "记录抽烟"
- **时间**: HH:mm 格式
- **数量和等级**: 仅抽烟记录显示
- **备注**: 如果有填写
- **间隔时间**: 距离上一条记录的时间
#### 日期分组
- **今天**: 显示"今天 X月X日"
- **昨天**: 显示"昨天 X月X日"
- **更早**: 显示"X月X日"
### 4. 编辑记录
1. 进入「记录」标签页
2. 找到要编辑的记录
3. 点击卡片右上角的「编辑」按钮(蓝色)
4. 弹出编辑表单,数据已预填充
5. 修改需要更改的内容
6. 点击「确定」保存
7. 提示"更新成功",列表自动刷新
**注意**:
- 可以修改时间、数量、等级、备注
- 不能改变记录类型(抽烟/忍住)
### 5. 删除记录
1. 进入「记录」标签页
2. 找到要删除的记录
3. 点击卡片右上角的「删除」按钮(红色)
4. 弹出确认对话框:"确定要删除这条记录吗?"
5. 点击「确定」删除
6. 提示"删除成功",记录从列表中消失
**注意**:
- 删除操作不可恢复
- 删除后会立即从列表中移除(乐观更新)
- 如果删除失败,会自动恢复记录并提示错误
### 6. 下拉刷新
1. 进入「记录」标签页
2. 在列表顶部向下拉动
3. 显示刷新指示器
4. 释放后自动刷新数据
5. 刷新完成后回到顶部
**用途**:
- 同步最新数据
- 查看其他设备的记录
- 修复显示异常
### 7. 上拉加载更多
1. 进入「记录」标签页
2. 滚动到列表底部
3. 自动触发加载更多
4. 显示"加载中..."
5. 新数据追加到列表底部
**说明**:
- 每次加载 20 条记录
- 没有更多时显示"没有更多了"
- 正在加载时不会重复请求
---
## 🎨 界面说明
### 首页 (pages/index/index.vue)
#### 配色
- **背景**: 渐变(浅绿 → 白色)
- **卡片**: 白色 + 阴影
- **主题色**: 翡翠绿 #10B981
- **按钮**:
- 记录抽烟: 白色背景 + 灰色边框
- 想抽忍住了: 绿色背景 + 白色文字
#### 布局
```
┌─────────────────────────────┐
│ 状态栏 │
│ 问候语 + 头像 ⚙️ │
│ AI 提示卡片 (可关闭) × │
│ ┌─────────────────────┐ │
│ │ 距上次抽烟 │ │
│ │ 02:45:39 │ │
│ │ ✨ 下次建议: 15:30 │ │
│ └─────────────────────┘ │
│ ┌──────┐ ┌──────┐ │
│ │今日 │ │烟瘾 │ │
│ │已抽 │ │发作 │ │
│ └──────┘ └──────┘ │
│ [🚬 记录抽烟] [💪 想抽忍住了] │
└─────────────────────────────┘
```
### 历史记录页 (pages/logs/index.vue)
#### 配色
- **背景**: 渐变(浅绿 → 白色)
- **标签栏**:
- 未选中: 白色 + 灰色边框
- 选中: 绿色背景 + 白色文字
- **卡片**:
- 白色背景
- 绿色左边框(忍住)
- 红色左边框(抽烟)
#### 布局
```
┌─────────────────────────────┐
│ 历史记录 │
│ [全部] [已抽烟] [已忍住] │
├─────────────────────────────┤
│ 今天 1月25日 │
│ ● ┌───────────────────┐ │
│ │ │ 💪 想抽忍住了 │ │
│ │ │ 14:30 │ │
│ │ │ 想抽但忍住了 │ │
│ │ │ 距上次 2小时15分 │ │
│ │ └───────────────────┘ │
│ │ [编辑] [删除] │
│ ● ┌───────────────────┐ │
│ │ 🚬 记录抽烟 │ │
│ │ 12:15 3支 等级2 │ │
│ │ 压力大、工作繁忙 │ │
│ └───────────────────┘ │
│ [编辑] [删除] │
│ │
│ 昨天 1月24日 │
│ ● ┌───────────────────┐ │
│ │ ... │ │
│ └───────────────────┘ │
│ │
│ [+] │
└─────────────────────────────┘
```
### 记录弹框 (components/smoke-record-dialog)
#### 抽烟模式
```
┌─────────────────────────────┐
│ 记录抽烟 × │
├─────────────────────────────┤
│ 时间 │
│ [2025-01-25] [14:30] │
│ │
│ 数量 │
│ [-] [1] [+] │
│ │
│ 烟瘾等级 │
│ [1] [2] [3] [4] [5] │
│ │
│ 备注 │
│ ┌─────────────────────┐ │
│ │ 记录抽烟原因... │ │
│ └─────────────────────┘ │
├─────────────────────────────┤
│ [取消] [确定] │
└─────────────────────────────┘
```
#### 忍住模式
```
┌─────────────────────────────┐
│ 想抽忍住了 × │
├─────────────────────────────┤
│ 时间 │
│ [2025-01-25] [14:30] │
│ │
│ 备注 │
│ ┌─────────────────────┐ │
│ │ 记录抵抗心得... │ │
│ └─────────────────────┘ │
├─────────────────────────────┤
│ [取消] [确定] │
└─────────────────────────────┘
```
---
## 💡 使用技巧
### 1. 快速记录
**场景**: 刚抽完烟,想快速记录
**操作**:
1. 打开小程序
2. 点击「记录抽烟」
3. 直接点击「确定」(使用默认值)
**时间**: < 3 秒
### 2. 详细记录
**场景**: 需要记录详细信息
**操作**:
1. 打开记录表单
2. 修改时间(如果不是刚抽的)
3. 调整数量和等级
4. 填写备注(为什么抽、当时心情等)
5. 提交
**建议备注内容**:
- 抽烟原因:压力大、无聊、社交、习惯
- 当时心情:焦虑、放松、开心、郁闷
- 触发场景:工作、休息、饭后、等人
### 3. 回顾分析
**查看抽烟规律**:
1. 进入历史记录页
2. 查看时间分布
3. 查看间隔时间
4. 查看备注了解触发原因
**筛选特定类型**:
1. 点击「已抽烟」查看所有抽烟记录
2. 点击「已忍住」查看抵抗记录
3. 对比数量,激励自己
### 4. 纠正错误
**场景**: 记录时间或内容错误
**操作**:
1. 进入历史记录页
2. 找到错误记录
3. 点击「编辑」
4. 修改错误信息
5. 保存
### 5. 删除重复
**场景**: 误操作重复记录
**操作**:
1. 进入历史记录页
2. 找到重复记录
3. 点击「删除」
4. 确认删除
---
## ⚠️ 注意事项
### 数据同步
- 记录会实时同步到服务器
- 多设备登录时,数据自动同步
- 删除后不可恢复,请谨慎操作
### 时间设置
- 可以记录过去的时间
- 不能记录未来的时间
- 建议在抽烟后立即记录,更准确
### 备注内容
- 最多 200 字符
- 建议记录关键信息
- 帮助分析抽烟规律
### 网络问题
- 需要网络连接才能同步
- 网络异常时会提示错误
- 可以下拉刷新重试
---
## 🆘 常见问题
### Q: 记录后首页数据没更新?
**A**: 尝试以下方法:
1. 下拉刷新首页
2. 切换 Tab 重新进入
3. 检查网络连接
### Q: 删除记录后又出现了?
**A**: 可能是网络问题导致删除失败:
1. 检查网络连接
2. 重新尝试删除
3. 联系客服
### Q: 编辑后数据没变?
**A**:
1. 检查是否点击了「确定」
2. 查看是否有错误提示
3. 刷新列表重试
### Q: 看不到历史记录?
**A**:
1. 下拉刷新列表
2. 检查筛选标签(是否选了「已抽烟」但没有记录)
3. 检查网络连接
### Q: 如何查看更早的记录?
**A**:
1. 滚动到列表底部
2. 会自动加载更多
3. 每次加载 20 条
---
## 📞 技术支持
如遇到其他问题,请通过以下方式联系:
- 小程序内客服
- 问题反馈
- GitHub Issues
---
**更新时间**: 2025-01-25
**版本**: Phase 3 完整版
+11 -11
View File
@@ -28,10 +28,10 @@
|------|------|----------|
| 问候语 | 根据时段显示(早上好/下午好等) + 用户昵称 | 本地计算 + profile |
| AI 提示卡片 | 发现的抽烟规律/建议(可关闭) | `GET /ai/advice` 缓存 |
| 计时环 | 距上次抽烟时间(时:分:秒) | `dashboard.minutes_since_last` |
| 计时环 | 距上次抽烟时间(时:分:秒) | `GET /next_smoke_time``last_smoke_at`(前端计时) |
| 下次建议时间 | 显示建议的下次抽烟时间点 | `GET /next_smoke_time` |
| 今日已抽 | X / 目标数,较昨日 ±N | `dashboard.today_count` |
| 烟瘾发作已抵抗 | 忍住次数统计 | 筛选 `level=0,num=0` 记录 |
| 今日已抽 | X / 目标数,较昨日 ±N | `next_smoke_time.today_count` + `next_smoke_time.reduced_from_yesterday`(可为负) + `next_smoke_time.exceeded_yesterday`(标识“超出昨日”) |
| 烟瘾发作已抵抗 | 忍住次数统计 | `next_smoke_time.resisted_count` |
| 记录抽烟按钮 | 快速记录一次抽烟 | `POST /logs` |
| 想抽忍住了按钮 | 记录成功抵抗 | `POST /logs/resisted` |
@@ -81,7 +81,7 @@
| 筛选 Tabs | 全部 / 已抽烟 / 已忍住 | 前端筛选 |
| 时间线 | 按日期分组展示 | `GET /logs` |
| 记录卡片 | 类型、时间、原因标签、间隔时间 | logs 数据 |
| 左滑操作 | 编辑 / 删除 | `PUT/DELETE /logs/:id` |
| 左滑操作 | 编辑 / 删除 | `POST/DELETE /logs/:id` |
| 新增按钮 | 浮动按钮快速新增 | 跳转记录流程 |
### 2.5 个人中心 (profile_&_settings)
@@ -92,11 +92,11 @@
|------|------|----------|
| 用户信息 | 头像、昵称 | 微信授权 |
| 目标展示 | 目标戒烟日期、连续天数 | profile |
| 目标设定 | 调整每日限额与戒烟日期 | `PUT /profile` |
| 目标设定 | 调整每日限额与戒烟日期 | `POST /profile` |
| AI 计划调整 | 个性化辅导风格设置 | profile 扩展 |
| 通知设置 | 提醒时间、频率 | 本地存储 |
| 会员解锁 | PRO 功能 / 广告解锁 | 会员系统 |
| 基础设置 | 作息时间等 | `PUT /profile` |
| 基础设置 | 作息时间等 | `POST /profile` |
| 隐私与数据 | 数据导出、账号注销 | 待扩展 |
---
@@ -126,7 +126,7 @@ Step 5: 作息时间 (wake_up_time, sleep_time)
Step 6: 设置目标 (目标日期、每日限额)
提交 profile (PUT /profile)
提交 profile (POST /profile)
进入首页
```
@@ -186,8 +186,8 @@ Step 6: 设置目标 (目标日期、每日限额)
```
[并行请求]
├── GET /profile (用户信息,判断是否需引导)
├── GET /dashboard (今日统计,计时器数据)
└── GET /next_smoke_time (下次建议时间)
├── GET /next_smoke_time (首页汇总 + 下次建议时间)
└── GET /dashboard (看板数据,可延迟)
[延迟加载]
└── GET /ai/advice (AI提示卡片,非关键)
@@ -195,8 +195,8 @@ Step 6: 设置目标 (目标日期、每日限额)
**缓存策略**
- profile: 登录后缓存,变更时更新
- dashboard: 每次进入刷新,后台定时更
- next_smoke_time: 缓存至下次记录
- next_smoke_time: 每次进入刷新,下一次记录后刷
- dashboard: 进入看板时刷新
- ai/advice: 按天缓存
### 5.2 数据预加载
+177 -2
View File
@@ -155,7 +155,7 @@ curl -X GET 'http://127.0.0.1:8080/api/v1/smoke/logs/5202' \
## 6) 更新记录
`PUT /api/v1/smoke/logs/:id`
`POST /api/v1/smoke/logs/:id`
请求体(字段可选,按需传):
@@ -302,7 +302,7 @@ curl -X GET 'http://127.0.0.1:8080/api/v1/smoke/logs/5202' \
## 11) 补全/更新用户基础信息(Upsert)
`PUT /api/v1/smoke/profile`
`POST /api/v1/smoke/profile`
说明:
- 字段按需传;首次进入建议一次性补全。
@@ -348,6 +348,7 @@ curl -X GET 'http://127.0.0.1:8080/api/v1/smoke/logs/5202' \
说明:
- 用于首页展示“建议的下次记录时间”。
- 已整合首页所需汇总字段(上次抽烟时间/今日抽烟支数/今日克制次数/较昨日减少支数)。
- 如果指定日期存在 AI 给出的时间节点(`time_nodes` 不为空),则优先使用 AI 的建议;否则使用默认策略。
- 可选参数:
- `date`:计划日期(默认今天),支持 `YYYY-MM-DD``today/tomorrow`
@@ -359,6 +360,7 @@ curl -X GET 'http://127.0.0.1:8080/api/v1/smoke/logs/5202' \
默认策略(不使用 AI):
- 基础间隔:优先使用 `GET /api/v1/smoke/profile` 返回的 `baseline_interval_minutes`;若不存在则默认 `60` 分钟。
- 阶梯式延时:最近 7 天内每累计 `5` 条“忍住记录(level=0,num=0)”,在基础间隔上 `+5` 分钟(最多 `+60` 分钟)。
- 间隔兜底:最终间隔会限制在 `5~240` 分钟之间。
- 若用户已补全作息时间,会自动规避睡眠区间:若计算出的时间落在睡眠区间,顺延到下一次起床时间。
AI 生成说明:
@@ -374,6 +376,11 @@ AI 生成说明:
"source": "default",
"not_before_at": "2026-01-05T10:18:00+08:00",
"suggested_at": "2026-01-05T10:18:00+08:00",
"last_smoke_at": "2026-01-05T09:30:00+08:00",
"today_count": 3,
"resisted_count": 1,
"reduced_from_yesterday": 2,
"exceeded_yesterday": false,
"default": {
"last_smoke_at": "2026-01-05T09:30:00+08:00",
"next_smoke_at": "2026-01-05T10:18:00+08:00",
@@ -398,6 +405,11 @@ AI 生成说明:
"source": "ai",
"not_before_at": "2026-01-05T10:18:00+08:00",
"suggested_at": "2026-01-05T10:28:00+08:00",
"last_smoke_at": "2026-01-05T09:30:00+08:00",
"today_count": 3,
"resisted_count": 1,
"reduced_from_yesterday": 2,
"exceeded_yesterday": false,
"time_nodes": ["10:30", "11:10", "14:00", "16:30"],
"advice": "先把这次冲动延后到10:28,期间做一次5分钟快走+喝水,压力场景用深呼吸替代。",
"default": { "algorithm": "staircase_delay_v1" },
@@ -414,3 +426,166 @@ AI 生成说明:
}
}
```
字段说明(新增首页字段):
- `last_smoke_at`:上次“实际抽烟”时间(忽略忍住记录),格式 `RFC3339`(含时区)。
- `today_count`:今日抽烟支数(累加 `num`)。
- `resisted_count`:今日克制次数(`level=0 && num=0`)。
- `reduced_from_yesterday`:较昨日减少的支数(允许为负数;为负时表示“今天超出昨日”)。
- `exceeded_yesterday`:是否超出昨日(`true` 表示今天超出昨日,前端可用作单独标识)。
## 14) 获取健康与储蓄统计(合并接口)
`GET /api/v1/smoke/health_savings?period=week&start=2026-01-01&end=2026-01-07`
说明:
- 合并了"肺部功能恢复"和"节省金额"两个指标,专用于统计页面展示。
- 支持按周/月/年查询,通过 `period` 参数指定时间范围类型。
参数:
- `period`(必填):时间范围类型,可选值:
- `week`:周(默认本周一至本周日)
- `month`:月(默认本月1日至本月最后一日)
- `year`:年(默认本年1月1日至本年12月31日)
- `start`(可选):起始日期(格式 `YYYY-MM-DD`),不传则根据 `period` 自动计算
- `end`(可选):截止日期(格式 `YYYY-MM-DD`),不传则根据 `period` 自动计算
**计算逻辑**
1. **肺部功能恢复百分比**
- 基于用户最后一次实际抽烟时间(忽略 `level=0 && num=0` 的忍住记录)
- 计算无烟时长(分钟)
- 根据医学研究恢复时间线计算恢复百分比(详见 `docs/ALGORITHM.md`
- 公式:
```
无烟天数 = (当前时间 - 最后抽烟时间) / (24 * 60) 分钟
恢复百分比计算:
- < 14天: (天数 / 14) * 15%
- 14-30天: 15% + ((天数 - 14) / 16) * 15%
- 30-90天: 30% + ((天数 - 30) / 60) * 20%
- > 90天: 50% + ((天数 - 90) / 275) * 50%,最高 100%
```
2. **节省金额**
- 基于用户在统计周期内的实际抽烟量与基线对比
- 计算公式:
```
预期总支数 = baseline_cigs_per_day * 周期天数
实际总支数 = 周期内所有记录的 num 累加(排除 level=0 && num=0
节省支数 = 预期总支数 - 实际总支数
节省包数 = 节省支数 / 20(假设每包20支)
节省金额(分)= 节省包数 * pack_price_cent
```
- 若实际总支数 > 预期总支数,则节省金额为 0(不显示负数)
3. **目标金额**
- 默认目标:`baseline_cigs_per_day * 周期天数 / 20 * pack_price_cent`(即完全戒烟节省的金额)
- 或使用用户设定的目标金额(如有)
成功响应示例:
```json
{
"code": 200,
"message": "success",
"data": {
"period": "week",
"start": "2026-01-01",
"end": "2026-01-07",
"days": 7,
"health": {
"lung_recovery_percent": 40.5,
"smoke_free_minutes": 11520,
"smoke_free_days": 8,
"last_smoke_at": "2025-12-24T14:30:00+08:00",
"recovery_stage": "early", // early(0-14天) / mid(14-30天) / late(30-90天) / advanced(>90天)
"next_milestone": {
"days_until": 6,
"milestone": "2周 - 肺功能提升15%",
"percent_at_milestone": 15
}
},
"savings": {
"saved_amount_cent": 14500, // 已节省金额(分)
"saved_amount_yuan": 145.00, // 已节省金额(元,前端展示用)
"target_amount_cent": 20000, // 目标金额(分)
"target_amount_yuan": 200.00, // 目标金额(元)
"saved_cigs": 58, // 节省支数
"expected_cigs": 140, // 预期总支数
"actual_cigs": 82, // 实际总支数
"progress_percent": 72.5, // 完成进度百分比
"pack_price_cent": 2500, // 单包价格(分)
"cigs_per_pack": 20 // 每包支数
},
"profile": {
"baseline_cigs_per_day": 20,
"pack_price_cent": 2500,
"smoking_years": 8
},
"calculated_at": "2026-01-08T10:00:00+08:00"
}
}
```
字段说明:
**health(健康数据)**
- `lung_recovery_percent`:肺部功能恢复百分比(0-100
- `smoke_free_minutes`:无烟时长(分钟)
- `smoke_free_days`:无烟天数(保留1位小数)
- `last_smoke_at`:最后一次实际抽烟时间(RFC3339格式)
- `recovery_stage`:恢复阶段标识
- `next_milestone`:下一个里程碑信息
**savings(储蓄数据)**
- `saved_amount_cent`:已节省金额(分,用于计算)
- `saved_amount_yuan`:已节省金额(元,用于前端展示)
- `target_amount_cent`:目标金额(分)
- `target_amount_yuan`:目标金额(元)
- `saved_cigs`:节省的支数
- `expected_cigs`:预期总支数(基线 × 天数)
- `actual_cigs`:实际总支数
- `progress_percent`:完成进度百分比(saved_amount / target_amount * 100
- `pack_price_cent`:单包价格(分)
- `cigs_per_pack`:每包支数(默认20
**period 参数说明**
- `period=week`(周):
- 默认:本周一 00:00:00 至 本周日 23:59:59
- 若传 `start`,则 `end = start + 6 天`
- `period=month`(月):
- 默认:本月1日 00:00:00 至 本月最后一日 23:59:59
- 若传 `start`,则 `end = start 所在月的最后一日`
- `period=year`(年):
- 默认:本年1月1日 00:00:00 至 本年12月31日 23:59:59
- 若传 `start`,则 `end = start 所在年的12月31日`
curl 示例:
```bash
# 查询本周数据
curl -X GET 'http://127.0.0.1:8080/api/v1/smoke/health_savings?period=week' \
-H 'Authorization: Bearer wx-session-key'
# 查询本月数据
curl -X GET 'http://127.0.0.1:8080/api/v1/smoke/health_savings?period=month' \
-H 'Authorization: Bearer wx-session-key'
# 查询本年数据
curl -X GET 'http://127.0.0.1:8080/api/v1/smoke/health_savings?period=year' \
-H 'Authorization: Bearer wx-session-key'
# 查询指定日期范围
curl -X GET 'http://127.0.0.1:8080/api/v1/smoke/health_savings?period=week&start=2026-01-01&end=2026-01-07' \
-H 'Authorization: Bearer wx-session-key'
```
**注意事项**
1. 若用户尚未补全 `profile`(缺少 `baseline_cigs_per_day` 或 `pack_price_cent`),相关计算字段可能为 0 或使用默认值
2. 若用户从未抽烟(无历史记录),`last_smoke_at` 可能不存在,肺部恢复百分比按最大恢复计算
3. 节省金额计算时,若实际支数 > 预期支数,`saved_amount_cent` 为 0(不显示负数)
4. 时间范围计算时,使用用户所在时区(后端需根据用户配置或默认使用 UTC+8)