后端: - 添加 articles 表迁移 + Entity + Service + Handler - 健康数据趋势 API (get_mini_trend) 注册路由 - article CRUD (list/get) + DTO 前端 (11个新页面 + 5个服务): - 预约挂号: 列表/创建向导/详情页 - 报告管理: 列表/详情页 - 随访管理: 任务列表/记录详情页 - 资讯文章: 文章详情页 - 个人中心: 就诊人管理/新增/我的报告/我的随访/用药提醒/设置 - 更新 app.config.ts 注册全部路由 - 更新 profile/article 页面为真实功能
1245 lines
34 KiB
Markdown
1245 lines
34 KiB
Markdown
# HMS 患者小程序实施计划
|
||
|
||
> **For agentic workers:** REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||
|
||
**Goal:** 基于 Taro 4 + React 19 构建微信小程序患者端,直连 erp-server 后端 API。
|
||
|
||
**Architecture:** 小程序代码位于 `apps/miniprogram/`,通过 Taro 编译为微信小程序。后端在 erp-auth 新增微信登录支持,erp-health 新增小程序所需 API。前端用 Zustand 管理状态,services 层封装 Taro.request 调用后端 `/api/v1/` 端点。
|
||
|
||
**Tech Stack:** Taro 4, React 19, TypeScript 6, Zustand 5, SCSS, echarts-taro3-react, Rust/Axum/SeaORM (后端)
|
||
|
||
**Spec:** `docs/superpowers/specs/2026-04-23-hms-miniprogram-design.md`
|
||
|
||
---
|
||
|
||
## Chunk 1: Phase 1 — 后端微信认证
|
||
|
||
### Task 1: 创建 wechat_users 数据库迁移
|
||
|
||
**Files:**
|
||
- Create: `crates/erp-server/migration/src/m20260423_000001_wechat_users.rs`
|
||
|
||
- [ ] **Step 1: 创建迁移文件**
|
||
|
||
```rust
|
||
// m20260423_000001_wechat_users.rs
|
||
use sea_orm_migration::prelude::*;
|
||
|
||
#[derive(DeriveMigrationAction)]
|
||
pub struct Migration;
|
||
|
||
#[async_trait::async_trait]
|
||
impl MigrationTrait for Migration {
|
||
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||
manager
|
||
.create_table(
|
||
Table::create()
|
||
.table(WechatUsers::Table)
|
||
.if_not_exists()
|
||
.col(ColumnDef::new(WechatUsers::Id).uuid().not_null().primary_key())
|
||
.col(ColumnDef::new(WechatUsers::TenantId).uuid().not_null())
|
||
.col(ColumnDef::new(WechatUsers::Openid).string().not_null())
|
||
.col(ColumnDef::new(WechatUsers::UnionId).string())
|
||
.col(ColumnDef::new(WechatUsers::UserId).uuid().not_null())
|
||
.col(ColumnDef::new(WechatUsers::Phone).string())
|
||
.col(ColumnDef::new(WechatUsers::CreatedAt).timestamp_with_time_zone().not_null().default(Expr::current_timestamp()))
|
||
.col(ColumnDef::new(WechatUsers::UpdatedAt).timestamp_with_time_zone().not_null().default(Expr::current_timestamp()))
|
||
.col(ColumnDef::new(WechatUsers::DeletedAt).timestamp_with_time_zone())
|
||
.to_owned(),
|
||
)
|
||
.await?;
|
||
manager
|
||
.create_index(
|
||
Index::create()
|
||
.name("idx_wechat_users_openid")
|
||
.table(WechatUsers::Table)
|
||
.col(WechatUsers::Openid)
|
||
.col(WechatUsers::TenantId)
|
||
.unique()
|
||
.to_owned(),
|
||
)
|
||
.await
|
||
}
|
||
|
||
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||
manager.drop_index(Index::drop().name("idx_wechat_users_openid").table(WechatUsers::Table).to_owned()).await?;
|
||
manager.drop_table(Table::drop().table(WechatUsers::Table).to_owned()).await
|
||
}
|
||
}
|
||
|
||
#[derive(DeriveIden)]
|
||
enum WechatUsers {
|
||
Table,
|
||
Id,
|
||
TenantId,
|
||
Openid,
|
||
UnionId,
|
||
UserId,
|
||
Phone,
|
||
CreatedAt,
|
||
UpdatedAt,
|
||
DeletedAt,
|
||
}
|
||
```
|
||
|
||
- [ ] **Step 2: 注册迁移**
|
||
|
||
在 `crates/erp-server/migration/src/lib.rs` 的 migration 列表中添加新迁移。
|
||
|
||
- [ ] **Step 3: 验证迁移**
|
||
|
||
Run: `cargo check -p erp-server`
|
||
Expected: 编译通过
|
||
|
||
- [ ] **Step 4: 提交**
|
||
|
||
```bash
|
||
git add crates/erp-server/migration/src/m20260423_000001_wechat_users.rs crates/erp-server/migration/src/lib.rs
|
||
git commit -m "feat(auth): 添加 wechat_users 表迁移"
|
||
```
|
||
|
||
---
|
||
|
||
### Task 2: 创建 wechat_users Entity
|
||
|
||
**Files:**
|
||
- Create: `crates/erp-auth/src/entity/wechat_user.rs`
|
||
- Modify: `crates/erp-auth/src/entity/mod.rs`
|
||
|
||
- [ ] **Step 1: 创建 Entity 文件**
|
||
|
||
参照 `crates/erp-auth/src/entity/user_token.rs` 的模式,创建 `wechat_user.rs`,包含 `Model`、`Relation`、`ActiveModelBehavior`。
|
||
|
||
- [ ] **Step 2: 在 mod.rs 注册**
|
||
|
||
在 `crates/erp-auth/src/entity/mod.rs` 添加 `pub mod wechat_user;`。
|
||
|
||
- [ ] **Step 3: 验证**
|
||
|
||
Run: `cargo check -p erp-auth`
|
||
Expected: 编译通过
|
||
|
||
- [ ] **Step 4: 提交**
|
||
|
||
```bash
|
||
git add crates/erp-auth/src/entity/wechat_user.rs crates/erp-auth/src/entity/mod.rs
|
||
git commit -m "feat(auth): 添加 wechat_user SeaORM entity"
|
||
```
|
||
|
||
---
|
||
|
||
### Task 3: 微信登录 DTO
|
||
|
||
**Files:**
|
||
- Modify: `crates/erp-auth/src/dto.rs`
|
||
|
||
- [ ] **Step 1: 添加微信登录相关 DTO**
|
||
|
||
在 `crates/erp-auth/src/dto.rs` 中新增:
|
||
|
||
```rust
|
||
// 微信登录请求
|
||
#[derive(Deserialize, ToSchema)]
|
||
pub struct WechatLoginReq {
|
||
pub code: String,
|
||
}
|
||
|
||
// 微信登录响应
|
||
#[derive(Serialize, ToSchema)]
|
||
pub struct WechatLoginResp {
|
||
pub bound: bool,
|
||
pub openid: String,
|
||
pub token: Option<LoginResp>, // 已绑定时返回
|
||
}
|
||
|
||
// 绑定手机号请求
|
||
#[derive(Deserialize, ToSchema)]
|
||
pub struct WechatBindPhoneReq {
|
||
pub openid: String,
|
||
pub encrypted_data: String,
|
||
pub iv: String,
|
||
}
|
||
```
|
||
|
||
- [ ] **Step 2: 验证**
|
||
|
||
Run: `cargo check -p erp-auth`
|
||
|
||
- [ ] **Step 3: 提交**
|
||
|
||
```bash
|
||
git add crates/erp-auth/src/dto.rs
|
||
git commit -m "feat(auth): 添加微信登录 DTO"
|
||
```
|
||
|
||
---
|
||
|
||
### Task 4: 微信登录 Service
|
||
|
||
**Files:**
|
||
- Create: `crates/erp-auth/src/service/wechat_service.rs`
|
||
- Modify: `crates/erp-auth/src/service/mod.rs`
|
||
|
||
- [ ] **Step 1: 实现 wechat_service.rs**
|
||
|
||
核心逻辑:
|
||
- `login(state, tenant_id, code)`: 用 code 调用微信 API 换 openid → 查 wechat_users 表 → 返回绑定状态
|
||
- `bind_phone(state, tenant_id, req)`: 解密手机号 → 查找/创建 user → 创建 wechat_user 记录 → 签发 JWT
|
||
- 微信 API 调用:`GET https://api.weixin.qq.com/sns/jscode2session?appid=...&secret=...&js_code={code}&grant_type=authorization_code`
|
||
|
||
注意:appid 和 secret 从 AppConfig 中读取,需在 erp-server 配置中新增 `wechat` 段。
|
||
|
||
- [ ] **Step 2: 在 mod.rs 注册**
|
||
|
||
添加 `pub mod wechat_service;`
|
||
|
||
- [ ] **Step 3: 验证**
|
||
|
||
Run: `cargo check -p erp-auth`
|
||
|
||
- [ ] **Step 4: 提交**
|
||
|
||
```bash
|
||
git add crates/erp-auth/src/service/wechat_service.rs crates/erp-auth/src/service/mod.rs
|
||
git commit -m "feat(auth): 实现微信登录/绑定手机号 service"
|
||
```
|
||
|
||
---
|
||
|
||
### Task 5: 微信登录 Handler + 路由注册
|
||
|
||
**Files:**
|
||
- Create: `crates/erp-auth/src/handler/wechat_handler.rs`
|
||
- Modify: `crates/erp-auth/src/handler/mod.rs`
|
||
- Modify: `crates/erp-auth/src/lib.rs` (路由注册)
|
||
|
||
- [ ] **Step 1: 创建 handler**
|
||
|
||
```rust
|
||
// wechat_handler.rs
|
||
pub async fn wechat_login<S>(State(state): State<AuthState>, ...) -> Result<Json<ApiResponse<WechatLoginResp>>, AppError>
|
||
pub async fn wechat_bind_phone<S>(State(state): State<AuthState>, ...) -> Result<Json<ApiResponse<LoginResp>>, AppError>
|
||
```
|
||
|
||
- [ ] **Step 2: 注册公开路由**
|
||
|
||
微信登录端点是公开的(无需 JWT),在 `AuthModule::public_routes()` 中添加:
|
||
- `POST /auth/wechat/login`
|
||
- `POST /auth/wechat/bind-phone`
|
||
|
||
- [ ] **Step 3: 在 AppConfig 中添加微信配置**
|
||
|
||
在 `crates/erp-server/src/config.rs` 中新增:
|
||
```rust
|
||
pub wechat: WechatConfig,
|
||
pub struct WechatConfig { pub appid: String, pub secret: String }
|
||
```
|
||
|
||
- [ ] **Step 4: 验证**
|
||
|
||
Run: `cargo check -p erp-server`
|
||
|
||
- [ ] **Step 5: 提交**
|
||
|
||
```bash
|
||
git add crates/erp-auth/src/handler/wechat_handler.rs crates/erp-auth/src/handler/mod.rs crates/erp-auth/src/lib.rs crates/erp-server/src/config.rs
|
||
git commit -m "feat(auth): 添加微信登录 handler 和公开路由"
|
||
```
|
||
|
||
---
|
||
|
||
### Task 6: 验证微信登录端到端
|
||
|
||
- [ ] **Step 1: 启动后端**
|
||
|
||
Run: `cargo run -p erp-server`
|
||
|
||
- [ ] **Step 2: 测试端点**
|
||
|
||
用 curl 测试:
|
||
```bash
|
||
curl -X POST http://localhost:3000/api/v1/auth/wechat/login -H "Content-Type: application/json" -d '{"code":"test_code"}'
|
||
```
|
||
Expected: 返回 `{ "success": true, "data": { "bound": false, "openid": "..." } }` 或类似响应
|
||
|
||
- [ ] **Step 3: 确认迁移执行**
|
||
|
||
检查 `wechat_users` 表已创建:
|
||
```bash
|
||
PGPASSWORD=123123 "D:\postgreSQL\bin\psql.exe" -U postgres -h localhost -d erp -c "\dt wechat_users"
|
||
```
|
||
|
||
- [ ] **Step 4: 提交确认**
|
||
|
||
如果有修复:
|
||
```bash
|
||
git add -A && git commit -m "fix(auth): 微信登录端到端验证修复"
|
||
```
|
||
|
||
---
|
||
|
||
## Chunk 2: Phase 1 — 小程序项目骨架 + 登录 + 首页
|
||
|
||
### Task 7: 初始化 Taro 项目
|
||
|
||
- [ ] **Step 1: 用 Taro CLI 初始化项目**
|
||
|
||
```bash
|
||
cd apps
|
||
npx @tarojs/cli init miniprogram --template react-ts
|
||
```
|
||
|
||
选择:
|
||
- 框架:React
|
||
- TypeScript:Yes
|
||
- CSS 预处理:Sass
|
||
- 模板:默认模板
|
||
- 编译工具:Webpack5
|
||
|
||
- [ ] **Step 2: 安装核心依赖**
|
||
|
||
```bash
|
||
cd apps/miniprogram
|
||
pnpm add zustand
|
||
pnpm add echarts echarts-taro3-react
|
||
```
|
||
|
||
- [ ] **Step 3: 配置 project.config.json**
|
||
|
||
设置 appid(先用测试号 `touristappid`)、ES6 转 ES5、增强编译等。
|
||
|
||
- [ ] **Step 4: 验证**
|
||
|
||
```bash
|
||
cd apps/miniprogram && pnpm dev:weapp
|
||
```
|
||
用微信开发者工具打开 `dist/` 目录,确认空白小程序可运行。
|
||
|
||
- [ ] **Step 5: 提交**
|
||
|
||
```bash
|
||
git add apps/miniprogram/
|
||
git commit -m "feat(miniprogram): 初始化 Taro 4 + React 项目骨架"
|
||
```
|
||
|
||
---
|
||
|
||
### Task 8: 全局样式 + 主题变量
|
||
|
||
**Files:**
|
||
- Modify: `apps/miniprogram/src/app.scss`
|
||
- Create: `apps/miniprogram/src/styles/variables.scss`
|
||
- Create: `apps/miniprogram/src/styles/mixins.scss`
|
||
|
||
- [ ] **Step 1: 创建主题变量**
|
||
|
||
`src/styles/variables.scss`:
|
||
```scss
|
||
$pri: #0891B2;
|
||
$pri-l: #E0F7FA;
|
||
$pri-d: #065A73;
|
||
$pri-surface: #ECFEFF;
|
||
$acc: #059669;
|
||
$acc-l: #D1FAE5;
|
||
$bg: #F0FDFA;
|
||
$card: #FFFFFF;
|
||
$tx: #134E4A;
|
||
$tx2: #6B7280;
|
||
$tx3: #94A3B8;
|
||
$bd: #E5E7EB;
|
||
$bd-l: #F3F4F6;
|
||
$dan: #DC2626;
|
||
$dan-l: #FEE2E2;
|
||
$wrn: #D97706;
|
||
$wrn-l: #FEF3C7;
|
||
$r: 12px;
|
||
$r-sm: 8px;
|
||
$r-lg: 16px;
|
||
```
|
||
|
||
- [ ] **Step 2: 创建常用 mixins**
|
||
|
||
`src/styles/mixins.scss`:
|
||
```scss
|
||
@mixin card {
|
||
background: $card;
|
||
border-radius: $r;
|
||
box-shadow: 0 2px 8px rgba(0,0,0,.06);
|
||
padding: 16px;
|
||
margin: 0 16px 12px;
|
||
}
|
||
```
|
||
|
||
- [ ] **Step 3: 更新 app.scss**
|
||
|
||
导入变量和全局基础样式(字体、背景色)。
|
||
|
||
- [ ] **Step 4: 提交**
|
||
|
||
```bash
|
||
git add apps/miniprogram/src/styles/ apps/miniprogram/src/app.scss
|
||
git commit -m "feat(miniprogram): 添加医疗清新主题样式变量"
|
||
```
|
||
|
||
---
|
||
|
||
### Task 9: services/request.ts — API 请求层
|
||
|
||
**Files:**
|
||
- Create: `apps/miniprogram/src/services/request.ts`
|
||
|
||
- [ ] **Step 1: 实现 request 封装**
|
||
|
||
```typescript
|
||
import Taro from '@tarojs/taro';
|
||
|
||
const BASE_URL = process.env.TARO_APP_API_URL || 'http://localhost:3000/api/v1';
|
||
|
||
interface ApiResponse<T> {
|
||
success: boolean;
|
||
data?: T;
|
||
message?: string;
|
||
}
|
||
|
||
async function getHeaders(): Promise<Record<string, string>> {
|
||
const headers: Record<string, string> = { 'Content-Type': 'application/json' };
|
||
const token = Taro.getStorageSync('access_token');
|
||
if (token) headers['Authorization'] = `Bearer ${token}`;
|
||
const patientId = Taro.getStorageSync('current_patient_id');
|
||
if (patientId) headers['X-Patient-Id'] = patientId;
|
||
const tenantId = Taro.getStorageSync('tenant_id');
|
||
if (tenantId) headers['X-Tenant-Id'] = tenantId;
|
||
return headers;
|
||
}
|
||
|
||
export async function request<T>(method: string, path: string, data?: unknown): Promise<T> {
|
||
const headers = await getHeaders();
|
||
const res = await Taro.request({ url: `${BASE_URL}${path}`, method, data, header: headers });
|
||
|
||
if (res.statusCode === 401) {
|
||
const refreshed = await tryRefreshToken();
|
||
if (refreshed) return request(method, path, data);
|
||
Taro.redirectTo({ url: '/pages/login/index' });
|
||
throw new Error('登录已过期');
|
||
}
|
||
|
||
const body = res.data as ApiResponse<T>;
|
||
if (!body.success) throw new Error(body.message || '请求失败');
|
||
return body.data as T;
|
||
}
|
||
|
||
async function tryRefreshToken(): Promise<boolean> {
|
||
const refreshToken = Taro.getStorageSync('refresh_token');
|
||
if (!refreshToken) return false;
|
||
try {
|
||
const res = await Taro.request({
|
||
url: `${BASE_URL}/auth/refresh`,
|
||
method: 'POST',
|
||
data: { refresh_token: refreshToken },
|
||
});
|
||
if (res.statusCode === 200 && res.data?.success) {
|
||
Taro.setStorageSync('access_token', res.data.data.access_token);
|
||
Taro.setStorageSync('refresh_token', res.data.data.refresh_token);
|
||
return true;
|
||
}
|
||
} catch {}
|
||
Taro.removeStorageSync('access_token');
|
||
Taro.removeStorageSync('refresh_token');
|
||
return false;
|
||
}
|
||
|
||
export const api = {
|
||
get: <T>(path: string) => request<T>('GET', path),
|
||
post: <T>(path: string, data?: unknown) => request<T>('POST', path, data),
|
||
put: <T>(path: string, data?: unknown) => request<T>('PUT', path, data),
|
||
delete: <T>(path: string) => request<T>('DELETE', path),
|
||
};
|
||
```
|
||
|
||
- [ ] **Step 2: 提交**
|
||
|
||
```bash
|
||
git add apps/miniprogram/src/services/request.ts
|
||
git commit -m "feat(miniprogram): 实现 API 请求层封装"
|
||
```
|
||
|
||
---
|
||
|
||
### Task 10: services/auth.ts + auth store
|
||
|
||
**Files:**
|
||
- Create: `apps/miniprogram/src/services/auth.ts`
|
||
- Create: `apps/miniprogram/src/stores/auth.ts`
|
||
|
||
- [ ] **Step 1: auth service**
|
||
|
||
```typescript
|
||
// services/auth.ts
|
||
import { api } from './request';
|
||
|
||
export interface LoginResp {
|
||
bound: boolean;
|
||
openid: string;
|
||
token?: { access_token: string; refresh_token: string; user: UserInfo };
|
||
}
|
||
|
||
export interface UserInfo {
|
||
id: string; name: string; phone: string; avatar?: string; tenant_id: string;
|
||
}
|
||
|
||
export interface PatientInfo {
|
||
id: string; name: string; gender?: string; birthday?: string; relation: string;
|
||
}
|
||
|
||
export async function wechatLogin(code: string): Promise<LoginResp> {
|
||
return api.post('/auth/wechat/login', { code });
|
||
}
|
||
|
||
export async function wechatBindPhone(openid: string, encryptedData: string, iv: string) {
|
||
return api.post('/auth/wechat/bind-phone', { openid, encrypted_data: encryptedData, iv });
|
||
}
|
||
|
||
export async function getPatients() {
|
||
return api.get<PatientInfo[]>('/health/patients');
|
||
}
|
||
```
|
||
|
||
- [ ] **Step 2: auth store**
|
||
|
||
参照 Web 端 `stores/auth.ts` 模式,使用 `Taro.getStorageSync` / `setStorageSync` 替代 `localStorage`。
|
||
|
||
State: `token, refreshToken, user, currentPatient, patients, loading`
|
||
Actions: `login(), bindPhone(), setCurrentPatient(), logout()`
|
||
|
||
- [ ] **Step 3: 提交**
|
||
|
||
```bash
|
||
git add apps/miniprogram/src/services/auth.ts apps/miniprogram/src/stores/auth.ts
|
||
git commit -m "feat(miniprogram): 实现 auth service 和 store"
|
||
```
|
||
|
||
---
|
||
|
||
### Task 11: 登录页
|
||
|
||
**Files:**
|
||
- Create: `apps/miniprogram/src/pages/login/index.tsx`
|
||
- Create: `apps/miniprogram/src/pages/login/index.scss`
|
||
|
||
- [ ] **Step 1: 实现登录页 UI**
|
||
|
||
登录页包含:
|
||
- 品牌标识(Logo + "健康管理" 标题)
|
||
- 微信一键登录按钮(调用 `wx.login` → `wechatLogin(code)`)
|
||
- 如果返回 `bound: false`,显示手机号授权按钮(使用 `<Button openType="getPhoneNumber">`)
|
||
- 登录成功后 `Taro.switchTab({ url: '/pages/index/index' })`
|
||
|
||
- [ ] **Step 2: 实现样式**
|
||
|
||
医疗清新风格:青色渐变背景、白色卡片、圆角按钮。
|
||
|
||
- [ ] **Step 3: 注册页面路由**
|
||
|
||
在 `src/app.config.ts` 的 `pages` 数组中添加 `/pages/login/index`。
|
||
|
||
- [ ] **Step 4: 提交**
|
||
|
||
```bash
|
||
git add apps/miniprogram/src/pages/login/ apps/miniprogram/src/app.config.ts
|
||
git commit -m "feat(miniprogram): 实现微信登录页面"
|
||
```
|
||
|
||
---
|
||
|
||
### Task 12: 首页(静态数据)
|
||
|
||
**Files:**
|
||
- Create: `apps/miniprogram/src/pages/index/index.tsx`
|
||
- Create: `apps/miniprogram/src/pages/index/index.scss`
|
||
- Create: `apps/miniprogram/src/components/HealthCard/index.tsx`
|
||
- Modify: `apps/miniprogram/src/app.config.ts` (TabBar 配置)
|
||
|
||
- [ ] **Step 1: 配置 TabBar**
|
||
|
||
在 `app.config.ts` 中定义 5 个 Tab:
|
||
|
||
```typescript
|
||
tabBar: {
|
||
color: '#94A3B8',
|
||
selectedColor: '#0891B2',
|
||
backgroundColor: '#FFFFFF',
|
||
list: [
|
||
{ pagePath: 'pages/index/index', text: '首页', iconPath: 'assets/tab-home.png', selectedIconPath: 'assets/tab-home-active.png' },
|
||
{ pagePath: 'pages/health/index', text: '健康', iconPath: 'assets/tab-health.png', selectedIconPath: 'assets/tab-health-active.png' },
|
||
{ pagePath: 'pages/appointment/index', text: '预约', iconPath: 'assets/tab-appt.png', selectedIconPath: 'assets/tab-appt-active.png' },
|
||
{ pagePath: 'pages/article/index', text: '资讯', iconPath: 'assets/tab-article.png', selectedIconPath: 'assets/tab-article-active.png' },
|
||
{ pagePath: 'pages/profile/index', text: '我的', iconPath: 'assets/tab-profile.png', selectedIconPath: 'assets/tab-profile-active.png' },
|
||
],
|
||
}
|
||
```
|
||
|
||
- [ ] **Step 2: 创建 Tab 图标**
|
||
|
||
准备 10 个图标文件(5 普通 + 5 选中态),放到 `src/assets/`。
|
||
|
||
- [ ] **Step 3: 实现 HealthCard 组件**
|
||
|
||
健康指标卡片:接收 `title, value, unit, status`,显示渐变背景 + 数值 + 状态标签。
|
||
|
||
- [ ] **Step 4: 实现首页**
|
||
|
||
按设计规格布局:问候栏 + 今日健康(2×2 网格)+ 快捷服务(4 宫格)+ 即将到来 + 待办随访。
|
||
MVP 先用静态数据,后续 Phase 对接真实 API。
|
||
|
||
- [ ] **Step 5: 创建其他 Tab 占位页**
|
||
|
||
为 `health/index`、`appointment/index`、`article/index`、`profile/index` 创建简单占位页,显示页面名称。
|
||
|
||
- [ ] **Step 6: 验证**
|
||
|
||
```bash
|
||
pnpm dev:weapp
|
||
```
|
||
微信开发者工具中确认:登录流程可用、首页布局正确、Tab 切换正常。
|
||
|
||
- [ ] **Step 7: 提交**
|
||
|
||
```bash
|
||
git add apps/miniprogram/src/
|
||
git commit -m "feat(miniprogram): 实现首页布局 + TabBar + 登录流程"
|
||
```
|
||
|
||
---
|
||
|
||
## Chunk 3: Phase 2 — 健康数据录入 + 趋势图
|
||
|
||
### Task 13: 后端 — vital_signs 趋势查询 API
|
||
|
||
**Files:**
|
||
- Modify: `crates/erp-health/src/handler/health_data_handler.rs`
|
||
- Modify: `crates/erp-health/src/service/health_data_service.rs`
|
||
- Modify: `crates/erp-health/src/dto/health_data_dto.rs`
|
||
- Modify: `crates/erp-health/src/module.rs` (路由)
|
||
|
||
- [ ] **Step 1: 添加趋势查询 DTO**
|
||
|
||
在 `health_data_dto.rs` 新增:
|
||
|
||
```rust
|
||
#[derive(Deserialize, ToSchema)]
|
||
pub struct TrendQueryParams {
|
||
pub indicator: String, // "blood_pressure_systolic" 等
|
||
pub start_date: Option<chrono::NaiveDate>,
|
||
pub end_date: Option<chrono::NaiveDate>,
|
||
pub range: Option<String>, // "7d", "30d", "90d"
|
||
}
|
||
|
||
#[derive(Serialize, ToSchema)]
|
||
pub struct TrendResp {
|
||
pub indicator: String,
|
||
pub data_points: Vec<DataPoint>,
|
||
}
|
||
|
||
#[derive(Serialize, ToSchema)]
|
||
pub struct DataPoint {
|
||
pub date: String,
|
||
pub value: f64,
|
||
}
|
||
```
|
||
|
||
- [ ] **Step 2: 添加趋势查询 service 函数**
|
||
|
||
在 `health_data_service.rs` 新增 `get_vital_signs_trend()`,基于已有的 `get_indicator_timeseries()` 封装,支持 `range` 参数自动计算日期范围。
|
||
|
||
- [ ] **Step 3: 添加 handler**
|
||
|
||
```rust
|
||
pub async fn get_trend<S>(...) -> Result<Json<ApiResponse<TrendResp>>, AppError>
|
||
```
|
||
|
||
- [ ] **Step 4: 注册路由**
|
||
|
||
在 `module.rs` 的 `protected_routes()` 中添加 `GET /health/vital-signs/trend`。
|
||
|
||
- [ ] **Step 5: 验证**
|
||
|
||
Run: `cargo check -p erp-health`
|
||
|
||
- [ ] **Step 6: 提交**
|
||
|
||
```bash
|
||
git add crates/erp-health/src/
|
||
git commit -m "feat(health): 添加 vital_signs 趋势查询 API"
|
||
```
|
||
|
||
---
|
||
|
||
### Task 14: 小程序 — 健康数据录入页
|
||
|
||
**Files:**
|
||
- Create: `apps/miniprogram/src/pages/health/index.tsx`
|
||
- Create: `apps/miniprogram/src/pages/health/index.scss`
|
||
- Create: `apps/miniprogram/src/pages/health/input/index.tsx`
|
||
- Create: `apps/miniprogram/src/pages/health/input/index.scss`
|
||
- Create: `apps/miniprogram/src/services/health.ts`
|
||
|
||
- [ ] **Step 1: health service**
|
||
|
||
```typescript
|
||
// services/health.ts
|
||
import { api } from './request';
|
||
|
||
export interface VitalSignInput {
|
||
indicator_type: string;
|
||
value: number;
|
||
measured_at?: string;
|
||
note?: string;
|
||
}
|
||
|
||
export interface TodaySummary {
|
||
blood_pressure?: { systolic: number; diastolic: number; status: string };
|
||
heart_rate?: { value: number; status: string };
|
||
blood_sugar?: { value: number; status: string };
|
||
weight?: { value: number; status: string };
|
||
}
|
||
|
||
export async function getTodaySummary() {
|
||
return api.get<TodaySummary>('/health/vital-signs?date=today');
|
||
}
|
||
|
||
export async function inputVitalSign(data: VitalSignInput) {
|
||
return api.post('/health/vital-signs', data);
|
||
}
|
||
|
||
export async function getTrend(indicator: string, range: string) {
|
||
return api.get<{ indicator: string; data_points: { date: string; value: number }[] }>(
|
||
`/health/vital-signs/trend?indicator=${indicator}&range=${range}`
|
||
);
|
||
}
|
||
```
|
||
|
||
- [ ] **Step 2: 健康数据首页**
|
||
|
||
展示今日健康数据概览(2×2 卡片网格)+ 最近趋势缩略图 + "录入数据" 按钮。
|
||
|
||
- [ ] **Step 3: 数据录入页**
|
||
|
||
表单:选择指标类型(Picker)→ 输入数值 → 选择测量时间(DateTimePicker)→ 备注(可选)→ 提交。
|
||
提交成功后 `Taro.navigateBack()` 并刷新上一页数据。
|
||
|
||
- [ ] **Step 4: 注册页面路由**
|
||
|
||
`app.config.ts` 中添加 `pages/health/input/index`。
|
||
|
||
- [ ] **Step 5: 验证**
|
||
|
||
微信开发者工具中确认录入表单可操作,提交后数据出现在健康首页。
|
||
|
||
- [ ] **Step 6: 提交**
|
||
|
||
```bash
|
||
git add apps/miniprogram/src/pages/health/ apps/miniprogram/src/services/health.ts apps/miniprogram/src/app.config.ts
|
||
git commit -m "feat(miniprogram): 实现健康数据录入页面"
|
||
```
|
||
|
||
---
|
||
|
||
### Task 15: 小程序 — 趋势图组件
|
||
|
||
**Files:**
|
||
- Create: `apps/miniprogram/src/components/TrendChart/index.tsx`
|
||
- Create: `apps/miniprogram/src/pages/health/trend/index.tsx`
|
||
- Create: `apps/miniprogram/src/pages/health/trend/index.scss`
|
||
|
||
- [ ] **Step 1: TrendChart 组件**
|
||
|
||
使用 `echarts-taro3-react` 渲染折线图。接收 `data: { date: string; value: number }[]` 和 `title: string`。
|
||
|
||
- [ ] **Step 2: 趋势详情页**
|
||
|
||
顶部:指标名称 + 时间范围切换(7天/30天/90天)
|
||
中部:TrendChart 折线图
|
||
底部:数据表格(日期 + 数值)
|
||
|
||
- [ ] **Step 3: 注册路由**
|
||
|
||
`app.config.ts` 添加 `pages/health/trend/index`。
|
||
|
||
- [ ] **Step 4: 验证**
|
||
|
||
切换时间范围,图表数据刷新。
|
||
|
||
- [ ] **Step 5: 提交**
|
||
|
||
```bash
|
||
git add apps/miniprogram/src/components/TrendChart/ apps/miniprogram/src/pages/health/trend/ apps/miniprogram/src/app.config.ts
|
||
git commit -m "feat(miniprogram): 实现健康趋势图页面"
|
||
```
|
||
|
||
---
|
||
|
||
### Task 16: health store + 首页数据联动
|
||
|
||
**Files:**
|
||
- Create: `apps/miniprogram/src/stores/health.ts`
|
||
- Modify: `apps/miniprogram/src/pages/index/index.tsx` (对接真实数据)
|
||
|
||
- [ ] **Step 1: health store**
|
||
|
||
```typescript
|
||
// stores/health.ts
|
||
import { create } from 'zustand';
|
||
import * as healthApi from '../services/health';
|
||
|
||
interface HealthState {
|
||
todaySummary: healthApi.TodaySummary | null;
|
||
loading: boolean;
|
||
refreshToday: () => Promise<void>;
|
||
}
|
||
|
||
export const useHealthStore = create<HealthState>((set) => ({
|
||
todaySummary: null,
|
||
loading: false,
|
||
refreshToday: async () => {
|
||
set({ loading: true });
|
||
try {
|
||
const data = await healthApi.getTodaySummary();
|
||
set({ todaySummary: data, loading: false });
|
||
} catch { set({ loading: false }); }
|
||
},
|
||
}));
|
||
```
|
||
|
||
- [ ] **Step 2: 首页接入真实数据**
|
||
|
||
替换首页静态数据,从 `useHealthStore().todaySummary` 读取。`useDidShow` 生命周期触发 `refreshToday()`。
|
||
|
||
- [ ] **Step 3: 提交**
|
||
|
||
```bash
|
||
git add apps/miniprogram/src/stores/health.ts apps/miniprogram/src/pages/index/
|
||
git commit -m "feat(miniprogram): 首页对接真实健康数据 API"
|
||
```
|
||
|
||
---
|
||
|
||
## Chunk 4: Phase 3 — 预约挂号
|
||
|
||
### Task 17: 后端 — 排班查询 API 适配
|
||
|
||
**Files:**
|
||
- Modify: `crates/erp-health/src/handler/health_data_handler.rs` 或对应的排班 handler
|
||
- Modify: `crates/erp-health/src/dto/health_data_dto.rs`
|
||
|
||
- [ ] **Step 1: 确认排班 API 支持按科室/医生查询**
|
||
|
||
检查现有 `GET /health/doctor-schedules` 是否支持 `department_id` 和 `doctor_id` 查询参数。如不支持,添加相应过滤。
|
||
|
||
- [ ] **Step 2: 添加"可用时段"聚合**
|
||
|
||
新增 DTO 和 handler:输入医生 + 日期范围 → 返回每日可用时段及剩余名额。
|
||
|
||
- [ ] **Step 3: 验证**
|
||
|
||
Run: `cargo check -p erp-health`
|
||
|
||
- [ ] **Step 4: 提交**
|
||
|
||
```bash
|
||
git add crates/erp-health/src/
|
||
git commit -m "feat(health): 排班查询支持科室/医生过滤 + 可用时段聚合"
|
||
```
|
||
|
||
---
|
||
|
||
### Task 18: 小程序 — 预约服务 + 列表页
|
||
|
||
**Files:**
|
||
- Create: `apps/miniprogram/src/services/appointment.ts`
|
||
- Modify: `apps/miniprogram/src/pages/appointment/index.tsx`
|
||
- Create: `apps/miniprogram/src/pages/appointment/index.scss`
|
||
|
||
- [ ] **Step 1: appointment service**
|
||
|
||
```typescript
|
||
// services/appointment.ts
|
||
import { api } from './request';
|
||
|
||
export interface Appointment {
|
||
id: string; doctor_name: string; department: string;
|
||
date: string; time_slot: string; status: string;
|
||
}
|
||
|
||
export async function listAppointments(page = 1) {
|
||
return api.get<{ data: Appointment[]; total: number }>(`/health/appointments?page=${page}`);
|
||
}
|
||
|
||
export async function createAppointment(data: {
|
||
doctor_id: string; schedule_id: string; patient_id: string;
|
||
}) {
|
||
return api.post('/health/appointments', data);
|
||
}
|
||
|
||
export async function cancelAppointment(id: string) {
|
||
return api.put(`/health/appointments/${id}/cancel`);
|
||
}
|
||
|
||
export async function getDoctorSchedules(doctorId: string, startDate: string, endDate: string) {
|
||
return api.get(`/health/doctor-schedules?doctor_id=${doctorId}&start_date=${startDate}&end_date=${endDate}`);
|
||
}
|
||
```
|
||
|
||
- [ ] **Step 2: 预约列表页**
|
||
|
||
显示预约记录列表(按时间倒序),每项包含医生名、科室、日期、时段、状态标签。支持下拉刷新 + 上拉加载更多。
|
||
|
||
- [ ] **Step 3: 提交**
|
||
|
||
```bash
|
||
git add apps/miniprogram/src/services/appointment.ts apps/miniprogram/src/pages/appointment/
|
||
git commit -m "feat(miniprogram): 实现预约列表页"
|
||
```
|
||
|
||
---
|
||
|
||
### Task 19: 小程序 — 新建预约页
|
||
|
||
**Files:**
|
||
- Create: `apps/miniprogram/src/pages/appointment/create/index.tsx`
|
||
- Create: `apps/miniprogram/src/pages/appointment/create/index.scss`
|
||
- Create: `apps/miniprogram/src/pages/appointment/detail/index.tsx`
|
||
|
||
- [ ] **Step 1: 新建预约页 — 步骤流程**
|
||
|
||
4 步向导:
|
||
1. 选择科室(Picker)
|
||
2. 选择医生(列表,显示头像+姓名+职称+科室)
|
||
3. 选择日期和时段(周视图日历 + 时段列表)
|
||
4. 确认预约(显示摘要 + 提交按钮)
|
||
|
||
- [ ] **Step 2: 预约详情页**
|
||
|
||
展示预约详情 + 取消预约按钮 + 导航到体检中心(地图)。
|
||
|
||
- [ ] **Step 3: 注册路由**
|
||
|
||
`app.config.ts` 添加 `pages/appointment/create/index` 和 `pages/appointment/detail/index`。
|
||
|
||
- [ ] **Step 4: 验证**
|
||
|
||
完整走通:选科室 → 选医生 → 选时段 → 确认 → 查看详情 → 取消。
|
||
|
||
- [ ] **Step 5: 提交**
|
||
|
||
```bash
|
||
git add apps/miniprogram/src/pages/appointment/ apps/miniprogram/src/app.config.ts
|
||
git commit -m "feat(miniprogram): 实现新建预约和预约详情页"
|
||
```
|
||
|
||
---
|
||
|
||
## Chunk 5: Phase 4 — 报告查询 + 家庭管理
|
||
|
||
### Task 20: 小程序 — 报告服务 + 列表/详情页
|
||
|
||
**Files:**
|
||
- Create: `apps/miniprogram/src/services/report.ts`
|
||
- Create: `apps/miniprogram/src/pages/report/index.tsx`
|
||
- Modify: `apps/miniprogram/src/app.config.ts`
|
||
|
||
- [ ] **Step 1: report service**
|
||
|
||
```typescript
|
||
import { api } from './request';
|
||
|
||
export interface LabReport {
|
||
id: string; title: string; type: string; date: string; status: string;
|
||
indicators?: LabIndicator[];
|
||
}
|
||
|
||
export interface LabIndicator {
|
||
name: string; value: number; unit: string; reference_min: number; reference_max: number;
|
||
status: 'normal' | 'high' | 'low';
|
||
}
|
||
|
||
export async function listReports(page = 1) {
|
||
return api.get<{ data: LabReport[]; total: number }>(`/health/lab-reports?page=${page}`);
|
||
}
|
||
|
||
export async function getReportDetail(id: string) {
|
||
return api.get<LabReport>(`/health/lab-reports/${id}`);
|
||
}
|
||
```
|
||
|
||
- [ ] **Step 2: 报告列表页**
|
||
|
||
卡片列表:报告名称 + 类型标签 + 日期。下拉刷新 + 上拉分页。
|
||
|
||
- [ ] **Step 3: 报告详情页**
|
||
|
||
基本信息卡 + 指标列表(正常灰色、异常红色高亮 + 箭头)+ 附件预览区。
|
||
|
||
- [ ] **Step 4: 提交**
|
||
|
||
```bash
|
||
git add apps/miniprogram/src/services/report.ts apps/miniprogram/src/pages/report/
|
||
git commit -m "feat(miniprogram): 实现报告查询列表和详情页"
|
||
```
|
||
|
||
---
|
||
|
||
### Task 21: 小程序 — 家庭管理(就诊人切换)
|
||
|
||
**Files:**
|
||
- Create: `apps/miniprogram/src/components/FamilyPicker/index.tsx`
|
||
- Create: `apps/miniprogram/src/pages/profile/family/index.tsx`
|
||
- Create: `apps/miniprogram/src/pages/profile/family-add/index.tsx`
|
||
- Modify: `apps/miniprogram/src/pages/profile/index.tsx`
|
||
|
||
- [ ] **Step 1: FamilyPicker 组件**
|
||
|
||
顶部下拉选择器:显示当前就诊人姓名 + 头像,点击展开列表切换。切换后更新 `auth store` 的 `currentPatient` + `Taro.setStorageSync('current_patient_id', id)`。
|
||
|
||
- [ ] **Step 2: 就诊人管理页**
|
||
|
||
列表显示已添加的就诊人(本人 + 家属),支持添加新就诊人。
|
||
|
||
- [ ] **Step 3: 添加就诊人页**
|
||
|
||
表单:姓名 + 与本人关系(Picker)+ 性别 + 出生日期 + 身份证号(可选)。提交 `POST /health/patients`。
|
||
|
||
- [ ] **Step 4: 首页/健康/预约页接入 FamilyPicker**
|
||
|
||
在这些页面顶部添加 FamilyPicker,切换就诊人后重新拉取数据。
|
||
|
||
- [ ] **Step 5: 注册路由并提交**
|
||
|
||
```bash
|
||
git add apps/miniprogram/src/components/FamilyPicker/ apps/miniprogram/src/pages/profile/family/ apps/miniprogram/src/pages/profile/family-add/
|
||
git commit -m "feat(miniprogram): 实现家庭管理 + 就诊人切换"
|
||
```
|
||
|
||
---
|
||
|
||
## Chunk 6: Phase 5 — 随访 + 资讯 + 用药提醒
|
||
|
||
### Task 22: 后端 — articles 表 + API
|
||
|
||
**Files:**
|
||
- Create: `crates/erp-server/migration/src/m20260423_000002_articles.rs`
|
||
- Create: `crates/erp-health/src/entity/article.rs`
|
||
- Create: `crates/erp-health/src/dto/article_dto.rs`
|
||
- Create: `crates/erp-health/src/handler/article_handler.rs`
|
||
- Create: `crates/erp-health/src/service/article_service.rs`
|
||
|
||
- [ ] **Step 1: 创建 articles 迁移**
|
||
|
||
表结构:`id, tenant_id, title, summary, content(富文本), cover_image, category, author, published_at, created_at, updated_at, deleted_at, version`
|
||
|
||
- [ ] **Step 2: Entity + DTO + Service + Handler**
|
||
|
||
参照现有 health_data 的模式创建完整 CRUD。公开接口只需 `list` 和 `detail`。
|
||
|
||
- [ ] **Step 3: 注册路由和权限**
|
||
|
||
- [ ] **Step 4: 验证**
|
||
|
||
Run: `cargo check -p erp-health`
|
||
|
||
- [ ] **Step 5: 提交**
|
||
|
||
```bash
|
||
git add crates/erp-health/src/ crates/erp-server/migration/
|
||
git commit -m "feat(health): 添加健康资讯 articles 表和 API"
|
||
```
|
||
|
||
---
|
||
|
||
### Task 23: 小程序 — 随访功能
|
||
|
||
**Files:**
|
||
- Create: `apps/miniprogram/src/services/followup.ts`
|
||
- Create: `apps/miniprogram/src/pages/followup/index.tsx`
|
||
- Create: `apps/miniprogram/src/pages/followup/detail/index.tsx`
|
||
|
||
- [ ] **Step 1: followup service**
|
||
|
||
- [ ] **Step 2: 随访任务列表页**
|
||
|
||
按状态分组:待完成 / 已完成 / 已过期。每项显示任务名 + 截止日期 + 状态。
|
||
|
||
- [ ] **Step 3: 随访详情/填写页**
|
||
|
||
动态表单渲染(后端定义字段)→ 提交 → 标记完成。
|
||
|
||
- [ ] **Step 4: 首页待办随访接入真实数据**
|
||
|
||
- [ ] **Step 5: 提交**
|
||
|
||
```bash
|
||
git add apps/miniprogram/src/services/followup.ts apps/miniprogram/src/pages/followup/
|
||
git commit -m "feat(miniprogram): 实现随访任务列表和填写页"
|
||
```
|
||
|
||
---
|
||
|
||
### Task 24: 小程序 — 健康资讯
|
||
|
||
**Files:**
|
||
- Create: `apps/miniprogram/src/services/article.ts`
|
||
- Modify: `apps/miniprogram/src/pages/article/index.tsx`
|
||
- Create: `apps/miniprogram/src/pages/article/detail/index.tsx`
|
||
|
||
- [ ] **Step 1: article service**
|
||
|
||
- [ ] **Step 2: 资讯列表页**
|
||
|
||
缩略图 + 标题 + 摘要 + 时间,下拉刷新 + 分页。
|
||
|
||
- [ ] **Step 3: 资讯详情页**
|
||
|
||
使用 Taro `RichText` 渲染富文本内容。
|
||
|
||
- [ ] **Step 4: 提交**
|
||
|
||
```bash
|
||
git add apps/miniprogram/src/services/article.ts apps/miniprogram/src/pages/article/
|
||
git commit -m "feat(miniprogram): 实现健康资讯列表和详情页"
|
||
```
|
||
|
||
---
|
||
|
||
### Task 25: 小程序 — 用药提醒
|
||
|
||
**Files:**
|
||
- Create: `apps/miniprogram/src/pages/profile/medication/index.tsx`
|
||
- Create: `apps/miniprogram/src/utils/medication-reminder.ts`
|
||
|
||
- [ ] **Step 1: 用药提醒工具**
|
||
|
||
本地 storage 存储提醒规则:`{ id, name, frequency, times: string[], enabled }`。
|
||
|
||
- [ ] **Step 2: 用药提醒管理页**
|
||
|
||
列表展示已添加的提醒 + 添加/编辑/删除/开关。
|
||
|
||
- [ ] **Step 3: 提交**
|
||
|
||
```bash
|
||
git add apps/miniprogram/src/pages/profile/medication/ apps/miniprogram/src/utils/medication-reminder.ts
|
||
git commit -m "feat(miniprogram): 实现用药提醒管理页"
|
||
```
|
||
|
||
---
|
||
|
||
## Chunk 7: Phase 6 — 打磨 + 真机测试 + 提审
|
||
|
||
### Task 26: "我的" 页面完善
|
||
|
||
**Files:**
|
||
- Modify: `apps/miniprogram/src/pages/profile/index.tsx`
|
||
- Create: `apps/miniprogram/src/pages/profile/settings/index.tsx`
|
||
|
||
- [ ] **Step 1: 个人中心页**
|
||
|
||
展示头像 + 姓名 + 手机号。功能入口:就诊人管理、我的报告、我的随访、用药提醒、设置。
|
||
|
||
- [ ] **Step 2: 设置页**
|
||
|
||
清除缓存、关于我们、隐私政策、退出登录。
|
||
|
||
- [ ] **Step 3: 提交**
|
||
|
||
```bash
|
||
git add apps/miniprogram/src/pages/profile/
|
||
git commit -m "feat(miniprogram): 完善个人中心页"
|
||
```
|
||
|
||
---
|
||
|
||
### Task 27: 空状态 + 错误处理 + Loading
|
||
|
||
**Files:**
|
||
- Create: `apps/miniprogram/src/components/EmptyState/index.tsx`
|
||
- Create: `apps/miniprogram/src/components/ErrorState/index.tsx`
|
||
- Create: `apps/miniprogram/src/components/Loading/index.tsx`
|
||
|
||
- [ ] **Step 1: 通用空状态组件**
|
||
|
||
显示图标 + 文案 + 操作按钮(如"去预约")。
|
||
|
||
- [ ] **Step 2: 通用错误组件**
|
||
|
||
网络错误 / 服务器错误 / 无权限,带重试按钮。
|
||
|
||
- [ ] **Step 3: 各页面接入**
|
||
|
||
所有列表页添加空状态、错误状态、Loading 态。
|
||
|
||
- [ ] **Step 4: 提交**
|
||
|
||
```bash
|
||
git add apps/miniprogram/src/components/EmptyState/ apps/miniprogram/src/components/ErrorState/ apps/miniprogram/src/components/Loading/
|
||
git commit -m "feat(miniprogram): 添加空状态/错误/Loading 通用组件"
|
||
```
|
||
|
||
---
|
||
|
||
### Task 28: 分包 + 性能优化
|
||
|
||
- [ ] **Step 1: 配置分包**
|
||
|
||
`app.config.ts` 中定义 subPackages:
|
||
- `health/` — 健康数据相关页面
|
||
- `appointment/` — 预约相关
|
||
- `report/` — 报告相关
|
||
- `followup/` — 随访相关
|
||
- `article/` — 资讯相关
|
||
|
||
主包保留:首页 + 登录 + 我的 + 公共组件。
|
||
|
||
- [ ] **Step 2: 图表库按需引入**
|
||
|
||
echarts 只引入折线图模块,减小体积。
|
||
|
||
- [ ] **Step 3: 提交**
|
||
|
||
```bash
|
||
git add apps/miniprogram/src/app.config.ts
|
||
git commit -m "perf(miniprogram): 配置分包加载 + 图表按需引入"
|
||
```
|
||
|
||
---
|
||
|
||
### Task 29: 真机测试 + 提审准备
|
||
|
||
- [ ] **Step 1: 真机调试**
|
||
|
||
通过微信开发者工具预览/真机调试,在多款真机上验证。
|
||
|
||
- [ ] **Step 2: 检查清单**
|
||
|
||
- [ ] 登录流程正常(微信授权 + 手机号绑定)
|
||
- [ ] 健康数据可录入并查看趋势
|
||
- [ ] 预约可创建/取消
|
||
- [ ] 报告可查看
|
||
- [ ] 随访可填写
|
||
- [ ] 就诊人可切换
|
||
- [ ] 无白屏、无 JS 报错
|
||
- [ ] 包体积 < 2MB(主包)
|
||
- [ ] 隐私政策和用户协议已配置
|
||
|
||
- [ ] **Step 3: 构建生产版本**
|
||
|
||
```bash
|
||
pnpm build:weapp
|
||
```
|
||
|
||
- [ ] **Step 4: 提交最终版本**
|
||
|
||
```bash
|
||
git add -A
|
||
git commit -m "release(miniprogram): v1.0.0 提审版本"
|
||
git push
|
||
```
|