diff --git a/docs/ALGORITHM.md b/docs/ALGORITHM.md index 4b54bb5..30ea753 100644 --- a/docs/ALGORITHM.md +++ b/docs/ALGORITHM.md @@ -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 周报数据结构 diff --git a/docs/DEVELOPMENT.md b/docs/DEVELOPMENT.md deleted file mode 100644 index 72af959..0000000 --- a/docs/DEVELOPMENT.md +++ /dev/null @@ -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 - - ``` - -- [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 - - ``` - -- [ ] 预填充数据 -- [ ] 调用 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 - - {{ group.displayDate }} - - -``` - -#### 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步完成 - -### 记录 -- [ ] 支持快速记录 -- [ ] 支持编辑/删除 -- [ ] 数据实时同步 - -### 统计 -- [ ] 图表正常显示 -- [ ] 数据计算准确 -- [ ] 切换流畅 - -### 整体 -- [ ] 无明显卡顿 -- [ ] 无崩溃闪退 -- [ ] 视觉符合设计稿 diff --git a/docs/PHASE3_COMPLETED.md b/docs/PHASE3_COMPLETED.md deleted file mode 100644 index f213de5..0000000 --- a/docs/PHASE3_COMPLETED.md +++ /dev/null @@ -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 -**状态**: ✅ 已完成并测试通过 diff --git a/docs/PHASE3_SUMMARY.md b/docs/PHASE3_SUMMARY.md deleted file mode 100644 index ac4768b..0000000 --- a/docs/PHASE3_SUMMARY.md +++ /dev/null @@ -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 - -``` - -### 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 进行中 diff --git a/docs/PHASE3_TODO.md b/docs/PHASE3_TODO.md deleted file mode 100644 index 91dabd7..0000000 --- a/docs/PHASE3_TODO.md +++ /dev/null @@ -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 开发后 diff --git a/docs/PHASE3_USER_GUIDE.md b/docs/PHASE3_USER_GUIDE.md deleted file mode 100644 index 542c616..0000000 --- a/docs/PHASE3_USER_GUIDE.md +++ /dev/null @@ -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 完整版 diff --git a/docs/PRD.md b/docs/PRD.md index f43169b..1a60d7a 100644 --- a/docs/PRD.md +++ b/docs/PRD.md @@ -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 数据预加载 diff --git a/docs/api.md b/docs/api.md index f3b25a9..04ed0a3 100644 --- a/docs/api.md +++ b/docs/api.md @@ -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)