From d4cf78f398674ebcfd0f271ae5e6a443dc7aa417 Mon Sep 17 00:00:00 2001 From: kola-web Date: Sat, 11 Jul 2026 09:22:38 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=9F=8B=E7=82=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../documents/igg4-tracking-implementation-plan.md | 310 +++++ api.md | 1419 -------------------- api_doctor_msg_task.md | 572 -------- doc/api.md | 1419 ++++++++++++++++++++ doc/api_doctor_msg_task.md | 572 ++++++++ doc/track.md | 216 +++ src/api/request.ts | 2 +- src/app.ts | 2 +- src/doctor/pages/d_changeDoctor/index.ts | 4 + src/doctor/pages/d_createTask/index.ts | 2 + src/doctor/pages/d_customExport/index.ts | 1 - src/doctor/pages/d_home/index.ts | 4 + src/doctor/pages/d_interactive/index.ts | 3 + src/doctor/pages/d_interactiveDoctor/index.ts | 2 + src/doctor/pages/d_invite/index.ts | 2 + src/doctor/pages/d_my/index.ts | 1 + src/doctor/pages/d_patient/index.ts | 3 + src/doctor/pages/d_patientDetail/index.ts | 1 + src/doctor/pages/d_taskDetail/index.ts | 1 + src/doctor/pages/d_taskList/index.ts | 3 + src/doctor/pages/d_userInfo/index.ts | 1 + src/gift/pages/record/index.ts | 4 + src/gift/pages/recordDetail/index.ts | 5 + src/gift/pages/recordList/index.ts | 3 + src/images/avatar1.png | Bin 0 -> 6769 bytes src/pages/cancellation/index.ts | 5 +- src/pages/caseReport/index.ts | 5 + src/pages/certReslove/index.ts | 2 +- src/pages/changeUser/index.ts | 4 +- src/pages/doctorDetail/index.ts | 1 + src/pages/doctorDetailBak/index.ts | 4 +- src/pages/familyScan/index.ts | 3 +- src/pages/feedback/index.ts | 6 +- src/pages/getUserInfo/index.ts | 12 +- src/pages/index/index.ts | 7 + src/pages/interactivePatient/index.ts | 7 + src/pages/liveResult/index.ts | 2 +- src/pages/my/index.ts | 11 + src/pages/mySave/index.ts | 1 + src/pages/personalInformation/index.ts | 1 + src/pages/qaForm/index.ts | 1 + src/pages/qaFormDetail/index.ts | 1 + src/pages/repository/index.ts | 7 + src/pages/repositoryDetail/index.ts | 1 + src/pages/smallPage/index.ts | 8 +- src/pages/storyDetail/index.ts | 4 +- src/pages/storyEnterResult/index.ts | 2 +- src/pages/thePublic/index.ts | 2 +- src/pages/uploadCert/index.ts | 4 +- src/pages/vipLogin/index.ts | 8 +- src/pages/vipLoginReject/index.ts | 2 +- typings/index.d.ts | 2 +- 52 files changed, 2639 insertions(+), 2026 deletions(-) create mode 100644 .trae/documents/igg4-tracking-implementation-plan.md delete mode 100644 api.md delete mode 100644 api_doctor_msg_task.md create mode 100644 doc/api.md create mode 100644 doc/api_doctor_msg_task.md create mode 100644 doc/track.md create mode 100644 src/images/avatar1.png diff --git a/.trae/documents/igg4-tracking-implementation-plan.md b/.trae/documents/igg4-tracking-implementation-plan.md new file mode 100644 index 0000000..c2139d1 --- /dev/null +++ b/.trae/documents/igg4-tracking-implementation-plan.md @@ -0,0 +1,310 @@ +# IGG4 小程序埋点实施计划 + +## 概要 + +基于 `doc/track.md` 文档和信达项目的成熟埋点模式,为 IGG4 项目实施页面级 PV 埋点和点击级事件埋点。采用信达项目已验证的 `PG_` / `BTN_` 双层命名体系,复用现有 `app.mpBehavior()` 基础设施。 + +## 现状分析 + +| 维度 | 现状 | +|------|------| +| 埋点函数 | `app.mpBehavior({ PageName, doctor? })` — 仅 1 处调用 (`MINI_PROGRAM_VISIT`) | +| API 接口 | 患者端 `?r=igg4/mp-behavior/add`,医生端 `?r=igg4/doctor/mp-behavior/add` | +| 类型签名 | `{ PageName: string; doctor?: boolean }` — 需扩展以支持 `detailId` 等可选参数 | +| 页面级埋点 | 完全未实现(track.md 中 25+ 页面均未添加调用) | +| 点击级埋点 | 完全未实现 | +| 命名规范 | 无(信达项目使用 `PG_`/`BTN_` 前缀命名体系) | + +## 命名规范(参照信达项目) + +| 类别 | 前缀 | 格式 | 示例 | +|------|------|------|------| +| 页面浏览(患者端) | `PG_` | `PG_Patient{功能名}` | `PG_PatientHome`、`PG_PatientRepository` | +| 页面浏览(医生端) | `PG_` | `PG_Doctor{功能名}` | `PG_DoctorHome`、`PG_DoctorPatient` | +| 点击事件(患者端) | `BTN_` | `BTN_Patient{功能名}{操作}` | `BTN_PatientHomeDoctorCard`、`BTN_PatientMyVip` | +| 点击事件(医生端) | `BTN_` | `BTN_Doctor{功能名}{操作}` | `BTN_DoctorHomeInvite`、`BTN_DoctorPatientDetail` | + +### PageName 与 track.md 页面对照表 + +**患者端页面级埋点(PG_):** + +| track.md 页面路径 | PageName | +|-------------------|----------| +| pages/index/index | `PG_PatientHome` | +| gift/pages/recordList/index | `PG_PatientRecordList` | +| gift/pages/record/index | `PG_PatientRecordAdd` | +| gift/pages/recordDetail/index | `PG_PatientRecordDetail` | +| pages/interactivePatient/index | `PG_PatientInteractive` | +| pages/doctorDetail/index | `PG_PatientDoctorDetail` | +| pages/repository/index | `PG_PatientRepository` | +| pages/repositoryDetail/index | `PG_PatientRepositoryDetail` | +| pages/my/index | `PG_PatientMy` | +| pages/qaFormDetail/index | `PG_PatientQaFormDetail` | +| pages/qaForm/index | `PG_PatientQaForm` | +| pages/caseReport/index | `PG_PatientCaseReport` | +| pages/personalInformation/index | `PG_PatientPersonalInfo` | +| pages/cancellation/index | `PG_PatientCancellation` | +| pages/mySave/index | `PG_PatientMySave` | +| pages/feedback/index | `PG_PatientFeedback` | + +**医生端页面级埋点(PG_):** + +| track.md 页面路径 | PageName | +|-------------------|----------| +| doctor/pages/d_home/index | `PG_DoctorHome` | +| doctor/pages/d_invite/index | `PG_DoctorInvite` | +| doctor/pages/d_patient/index | `PG_DoctorPatient` | +| doctor/pages/d_patientDetail/index | `PG_DoctorPatientDetail` | +| doctor/pages/d_taskList/index | `PG_DoctorTaskList` | +| doctor/pages/d_taskDetail/index | `PG_DoctorTaskDetail` | +| doctor/pages/d_createTask/index | `PG_DoctorCreateTask` | +| doctor/pages/d_interactive/index | `PG_DoctorInteractive` | +| doctor/pages/d_interactiveDoctor/index | `PG_DoctorInteractiveDoctor` | +| doctor/pages/d_my/index | `PG_DoctorMy` | +| doctor/pages/d_userInfo/index | `PG_DoctorUserInfo` | +| doctor/pages/d_changeDoctor/index | `PG_DoctorChangeDoctor` | + +## 实施步骤 + +### 第 1 步:扩展 mpBehavior 类型签名 + +**文件**: `src/app.ts` + `typings/index.d.ts` + +扩展 `mpBehavior` 方法签名,支持可选的 `detailId` 参数(用于详情页等场景): + +```ts +// typings/index.d.ts +mpBehavior: (data: { PageName: string; doctor?: boolean; detailId?: string }) => void + +// src/app.ts — 实现签名同步更新 +mpBehavior(data: { PageName: string; doctor?: boolean; detailId?: string }) { + // ... 现有逻辑不变,detailId 会随 data 对象一起 POST 到后端 +} +``` + +> 说明:与信达项目一致,`detailId` 等额外字段作为 POST data 的一部分直接发送给后端,无需在 `mpBehavior` 函数内做特殊处理。 + +### 第 2 步:实施患者端页面级埋点(16 个页面) + +在每个页面的 `onShow` 中(有 `waitLogin` 的在 `waitLogin().then()` 内),调用 `app.mpBehavior()`。 + +**通用模式:** + +```ts +// 患者端页面(无 waitLogin) +onShow() { + app.mpBehavior({ PageName: 'PG_PatientXxx' }) +} + +// 患者端页面(有 waitLogin) +onShow() { + app.waitLogin().then(() => { + app.mpBehavior({ PageName: 'PG_PatientXxx' }) + // ... 原有业务逻辑 + }) +} +``` + +**修改文件清单:** + +| # | 文件路径 | PageName | 嵌入位置 | +|---|---------|----------|---------| +| 1 | `src/pages/index/index.ts` | `PG_PatientHome` | `onShow` → `waitLogin().then()` 内首行 | +| 2 | `src/gift/pages/recordList/index.ts` | `PG_PatientRecordList` | `onShow` → `waitLogin().then()` 内首行 | +| 3 | `src/gift/pages/record/index.ts` | `PG_PatientRecordAdd` | `onShow` → `waitLogin().then()` 内首行 | +| 4 | `src/gift/pages/recordDetail/index.ts` | `PG_PatientRecordDetail` | `onShow` → `waitLogin().then()` 内首行,带 `detailId` | +| 5 | `src/pages/interactivePatient/index.ts` | `PG_PatientInteractive` | `onLoad` → `waitLogin().then()` 内首行 | +| 6 | `src/pages/doctorDetail/index.ts` | `PG_PatientDoctorDetail` | `onShow` → `waitLogin().then()` 内首行,带 `detailId` | +| 7 | `src/pages/repository/index.ts` | `PG_PatientRepository` | `onShow` → `waitLogin().then()` 内首行 | +| 8 | `src/pages/repositoryDetail/index.ts` | `PG_PatientRepositoryDetail` | `onShow` → `waitLogin().then()` 内首行,带 `detailId` | +| 9 | `src/pages/my/index.ts` | `PG_PatientMy` | `onShow` → `waitLogin().then()` 内首行 | +| 10 | `src/pages/qaFormDetail/index.ts` | `PG_PatientQaFormDetail` | `onShow` → `waitLogin().then()` 内首行,带 `detailId` | +| 11 | `src/pages/qaForm/index.ts` | `PG_PatientQaForm` | `onShow` → `waitLogin().then()` 内首行 | +| 12 | `src/pages/caseReport/index.ts` | `PG_PatientCaseReport` | `onShow` → `waitLogin().then()` 内首行 | +| 13 | `src/pages/personalInformation/index.ts` | `PG_PatientPersonalInfo` | `onShow` → `waitLogin().then()` 内首行 | +| 14 | `src/pages/cancellation/index.ts` | `PG_PatientCancellation` | `onShow` → `waitLogin().then()` 内首行 | +| 15 | `src/pages/mySave/index.ts` | `PG_PatientMySave` | `onShow` → `waitLogin().then()` 内首行 | +| 16 | `src/pages/feedback/index.ts` | `PG_PatientFeedback` | `onShow` → `waitLogin().then()` 内首行 | + +### 第 3 步:实施医生端页面级埋点(12 个页面) + +医生端埋点需传入 `doctor: true`,API 路径切换为 `?r=igg4/doctor/mp-behavior/add`。 + +**通用模式:** + +```ts +// 医生端页面 +onShow() { + app.waitLogin().then(() => { + app.mpBehavior({ doctor: true, PageName: 'PG_DoctorXxx' }) + // ... 原有业务逻辑 + }) +} +``` + +**修改文件清单:** + +| # | 文件路径 | PageName | 嵌入位置 | +|---|---------|----------|---------| +| 1 | `src/doctor/pages/d_home/index.ts` | `PG_DoctorHome` | `onLoad` → `waitLogin().then()` 内首行 | +| 2 | `src/doctor/pages/d_invite/index.ts` | `PG_DoctorInvite` | `onShow` → `waitLogin().then()` 内首行 | +| 3 | `src/doctor/pages/d_patient/index.ts` | `PG_DoctorPatient` | `onShow` → `waitLogin().then()` 内首行 | +| 4 | `src/doctor/pages/d_patientDetail/index.ts` | `PG_DoctorPatientDetail` | `onShow` → `waitLogin().then()` 内首行,带 `detailId` | +| 5 | `src/doctor/pages/d_taskList/index.ts` | `PG_DoctorTaskList` | `onShow` → `waitLogin().then()` 内首行 | +| 6 | `src/doctor/pages/d_taskDetail/index.ts` | `PG_DoctorTaskDetail` | `onShow` → `waitLogin().then()` 内首行,带 `detailId` | +| 7 | `src/doctor/pages/d_createTask/index.ts` | `PG_DoctorCreateTask` | `onShow` → `waitLogin().then()` 内首行 | +| 8 | `src/doctor/pages/d_interactive/index.ts` | `PG_DoctorInteractive` | `onShow` → `waitLogin().then()` 内首行 | +| 9 | `src/doctor/pages/d_interactiveDoctor/index.ts` | `PG_DoctorInteractiveDoctor` | `onShow` → `waitLogin().then()` 内首行,带 `detailId` | +| 10 | `src/doctor/pages/d_my/index.ts` | `PG_DoctorMy` | `onShow` → `waitLogin().then()` 内首行 | +| 11 | `src/doctor/pages/d_userInfo/index.ts` | `PG_DoctorUserInfo` | `onShow` → `waitLogin().then()` 内首行 | +| 12 | `src/doctor/pages/d_changeDoctor/index.ts` | `PG_DoctorChangeDoctor` | `onShow` → `waitLogin().then()` 内首行 | + +### 第 4 步:实施点击级埋点(BTN_) + +在关键交互的事件处理函数首行,插入 `app.mpBehavior()` 调用。 + +#### 患者端点击埋点 + +**首页 — `src/pages/index/index.ts`** + +| 方法 | PageName | 说明 | +|------|----------|------| +| `routerTo(e)` 中 doctor 类卡片 | `BTN_PatientHomeDoctorCard` | 迷你医生卡片点击 | +| `routerTo(e)` 中功能入口 | `BTN_PatientHomeFunctionCard` | 功能卡片跳转 | +| `handleNextVisit()` | `BTN_PatientHomeNextVisit` | 下次复诊入口 | +| `handleArticleView(e)` | `BTN_PatientHomeArticle` | 文章点击 | +| `handleArticleSave(e)` | `BTN_PatientHomeArticleSave` | 文章收藏 | +| `handleToastOk()`(绑定医生确认) | `BTN_PatientHomeBindDoctor` | 绑定医生弹窗确认 | +| `handlePublic()` | `BTN_PatientHomeFollowPublic` | 关注公众号 | + +**我的页面 — `src/pages/my/index.ts`** + +| 方法 | PageName | 说明 | +|------|----------|------| +| `routerVipTo()` | `BTN_PatientMyVip` | VIP 认证入口 | +| `handleMyHealthRecord(e)` | `BTN_PatientMyHealthRecord` | 健康档案 | +| `handleQaForm()` | `BTN_PatientMyQaForm` | 健康问卷 | +| `routerTo(e)` 中 mySave | `BTN_PatientMySave` | 我的收藏 | +| `routerTo(e)` 中 personalInfo | `BTN_PatientMyPersonalInfo` | 个人信息 | +| `routerTo(e)` 中 feedback | `BTN_PatientMyFeedback` | 问题反馈 | +| `handleMiniDoctor()` | `BTN_PatientMyMiniDoctor` | 迷你医生 | + +**医患互动 — `src/pages/interactivePatient/index.ts`** + +| 方法 | PageName | 说明 | +|------|----------|------| +| `handleHot(e)` | `BTN_PatientInteractiveHotQuestion` | 热门问题点击 | +| `handleQuestion(e)` | `BTN_PatientInteractiveQuestion` | 快捷问题点击 | +| `handleConfirm()` | `BTN_PatientInteractiveSend` | 发送消息 | +| `handleAdl()` | `BTN_PatientInteractiveAdl` | ADL 评估入口 | +| `handleQol()` | `BTN_PatientInteractiveQol` | QoL 入口 | +| `handleDoctorDetail()` | `BTN_PatientInteractiveDoctorDetail` | 查看医生详情 | + +**知识库 — `src/pages/repository/index.ts`** + +| 方法 | PageName | 说明 | +|------|----------|------| +| `tabChange(e)` | `BTN_PatientRepositoryTab` | Tab 切换 | +| `handleSearch()` | `BTN_PatientRepositorySearch` | 搜索 | +| `handleCate(e)` | `BTN_PatientRepositoryCategory` | 分类筛选 | +| `handleDetail(e)` | `BTN_PatientRepositoryArticle` | 文章详情 | +| `handleStar(e)` | `BTN_PatientRepositoryStar` | 点赞 | +| `handleToggleSave(e)` | `BTN_PatientRepositorySave` | 收藏 | + +**就诊记录列表 — `src/gift/pages/recordList/index.ts`** + +| 方法 | PageName | 说明 | +|------|----------|------| +| 新增就诊记录入口 | `BTN_PatientRecordListAdd` | 新增记录按钮 | +| 点击记录项 | `BTN_PatientRecordListItem` | 记录列表项点击 | + +**就诊记录新增 — `src/gift/pages/record/index.ts`** + +| 方法 | PageName | 说明 | +|------|----------|------| +| 提交/保存按钮 | `BTN_PatientRecordAddSubmit` | 保存记录 | + +**医生详情 — `src/pages/doctorDetail/index.ts`** + +| 方法 | PageName | 说明 | +|------|----------|------| +| 查看互动 | `BTN_PatientDoctorDetailInteractive` | 进入互动页 | + +#### 医生端点击埋点 + +**医生首页 — `src/doctor/pages/d_home/index.ts`** + +| 方法 | PageName | 说明 | +|------|----------|------| +| `handlePatient(e)` | `BTN_DoctorHomePatient` | 患者列表入口 | +| `handleInvite()` | `BTN_DoctorHomeInvite` | 邀约按钮 | +| `handleSelectYear1()` | `BTN_DoctorHomeSelectYear` | 年份筛选 | + +**邀约患者 — `src/doctor/pages/d_invite/index.ts`** + +| 方法 | PageName | 说明 | +|------|----------|------| +| 发送邀约按钮 | `BTN_DoctorInviteSend` | 发送邀约 | + +**患者列表 — `src/doctor/pages/d_patient/index.ts`** + +| 方法 | PageName | 说明 | +|------|----------|------| +| 搜索 | `BTN_DoctorPatientSearch` | 搜索患者 | +| 点击患者项 | `BTN_DoctorPatientItem` | 患者列表项 | + +**互动列表 — `src/doctor/pages/d_interactive/index.ts`** + +| 方法 | PageName | 说明 | +|------|----------|------| +| 搜索 | `BTN_DoctorInteractiveSearch` | 搜索互动 | +| 点击互动项 | `BTN_DoctorInteractiveItem` | 互动列表项 | + +**互动页 — `src/doctor/pages/d_interactiveDoctor/index.ts`** + +| 方法 | PageName | 说明 | +|------|----------|------| +| 发送消息 | `BTN_DoctorInteractiveSend` | 发送消息 | + +**群发列表 — `src/doctor/pages/d_taskList/index.ts`** + +| 方法 | PageName | 说明 | +|------|----------|------| +| 新增群发 | `BTN_DoctorTaskListAdd` | 新增群发入口 | +| 点击群发项 | `BTN_DoctorTaskListItem` | 群发列表项 | + +**群发新增 — `src/doctor/pages/d_createTask/index.ts`** + +| 方法 | PageName | 说明 | +|------|----------|------| +| 提交群发 | `BTN_DoctorCreateTaskSubmit` | 创建群发 | + +**切换医生 — `src/doctor/pages/d_changeDoctor/index.ts`** + +| 方法 | PageName | 说明 | +|------|----------|------| +| 选择医生 | `BTN_DoctorChangeDoctorSelect` | 切换医生选择 | + +> **注意**:以上点击埋点 PageName 是基于代码探索的预定义清单。实施时需逐页确认实际的方法名和交互行为,如有差异需现场调整。 + +### 第 5 步:更新 doc/track.md 文档 + +将完整的 PageName 对照表(页面级 + 点击级)更新到 `doc/track.md`,作为埋点实施的参考文档。 + +## 假设与决策 + +1. **命名规范**:采用信达项目的 `PG_/BTN_` 前缀体系,患者端用 `Patient` 前缀,医生端用 `Doctor` 前缀。这样命名清晰且便于后端区分数据来源。 +2. **detailId 参数**:扩展 `mpBehavior` 类型签名以支持可选 `detailId`,用于详情页场景。实际在 JS 层该字段会随 data 对象一起 POST,无需函数内额外处理。 +3. **页面级埋点位置**:有 `waitLogin` 的页面在 `.then()` 内首行调用;无 `waitLogin` 的在 `onShow` 首行调用。确保用户登录后才上报,避免无效数据。 +4. **点击级埋点位置**:在事件处理函数首行调用 `mpBehavior`,先上报再执行业务逻辑(与信达项目一致)。 +5. **医生端 `doctor: true`**:所有医生端埋点均传入 `doctor: true`,确保 API 路径正确切换。 +6. **MINI_PROGRAM_VISIT 保留**:`app.ts` 中现有的 `MINI_PROGRAM_VISIT` 埋点保留不变,它记录小程序整体打开事件,与页面级 PV 埋点互不冲突。 +7. **无集中常量文件**:PageName 采用硬编码字符串(与信达项目一致),不创建额外的常量/枚举文件,避免增加维护成本。 + +## 验证步骤 + +1. 编译检查:确保 `pnpm run lint:fix` 无新增错误 +2. 逐页验证:在微信开发者工具中打开每个页面,检查 console 中 mpBehavior POST 请求是否正常发出 +3. 参数验证:确认患者端请求路径为 `?r=igg4/mp-behavior/add`,医生端为 `?r=igg4/doctor/mp-behavior/add` +4. doctor 参数验证:确认 `doctor` 字段在发送前被正确删除(不出现在 POST body 中) +5. detailId 验证:确认详情页的 `detailId` 正确传入 POST body diff --git a/api.md b/api.md deleted file mode 100644 index 6d52f27..0000000 --- a/api.md +++ /dev/null @@ -1,1419 +0,0 @@ -# 就诊记录接口文档 - -## 通用说明 - -### 响应格式 - -所有接口返回 JSON,严格遵循以下格式: - -```json -{ - "code": 0, - "message": "success", - "data": {} -} -``` - -- `code`:0 表示成功,非 0 表示失败 -- `message`:成功时为 "success",失败时为错误描述 -- `data`:业务数据,失败时为 null - -### 数据命名规则 - -`data` 中所有字段使用**小驼峰**命名法(如 `visitDate`、`igG4Value`)。 - -### 登录校验 - -所有接口需通过请求头 `loginState` 或请求参数 `loginState` 传递登录态,未登录返回 code=403。 - -### 错误码 - -| code | 说明 | -|------|------| -| 0 | 成功 | -| 1 | 参数缺失 | -| 2 | 记录不存在 | -| 3 | 操作失败 | -| 403 | 需要登录 | - ---- - -## 一、患者端接口 - -模块路由前缀:`igg4/medical-visit` - ---- - -### 1.1 保存草稿 - -- **路由**:`?r=igg4/medical-visit/save-draft` -- **请求方式**:POST -- **说明**:创建或更新草稿记录。传入 `id` 时更新已有草稿,不传时新建草稿。图片列表支持新增、更新、逻辑删除的 diff 处理。使用数据库事务。 - -#### 请求参数 - -| 参数 | 类型 | 必填 | 说明 | -|------|------|------|------| -| id | int | 否 | 已有草稿 ID,更新时必传 | -| visitDate | string | 是 | 本次就诊时间,格式 YYYY-MM-DD | -| nextVisitDate | string | 否 | 下次就诊时间,格式 YYYY-MM-DD | -| oralHormoneDosage | float | 否 | 口服激素每日用量(片) | -| manualIgG4Value | float | 否 | 患者手动录入的IgG4数值(冗余字段,单位mg/dL) | -| medicationsUsed | array | 否 | 本次就诊已使用的药物(多选),值为常量ID数组,如 [1,2,3],见附录G | -| immunosuppressantName | array | 否 | 正在使用的免疫抑制剂名称(多选),值为常量ID数组,如 [1,5],见附录G | -| medicationsUsedOtherText | string | 否 | 本次就诊已使用药物选择"其他"(99)时的补充文本 | -| immunosuppressantNameOtherText | string | 否 | 正在使用的免疫抑制剂名称选择"其他"(99)时的补充文本 | -| images | array | 否 | 图片列表 | - -#### images 每项参数 - -| 参数 | 类型 | 必填 | 说明 | -|------|------|------|------| -| imageUrl | string | 是 | 图片 URL | -| imageType | string | 是 | 图片类型标识,见枚举表 | - -#### imageType 枚举 - -| 值 | 说明 | -|------|------| -| outpatientRecord | 门诊病历及处方 | -| labReport | 检验报告 | -| imagingExam | 影像学检查 | -| pathology | 病理诊断及活检 | -| immuneFunction | 外周血免疫功能评估 | - -#### 请求示例 - -```json -{ - "id": 0, - "visitDate": "2026-06-29", - "nextVisitDate": "2026-09-29", - "oralHormoneDosage": 4, - "manualIgG4Value": 135.0, - "medicationsUsed": [2, 3], - "immunosuppressantName": [1, 7], - "medicationsUsedOtherText": null, - "immunosuppressantNameOtherText": null, - "images": [ - { - "imageUrl": "https://oss.example.com/img001.jpg", - "imageType": "labReport" - }, - { - "imageUrl": "https://oss.example.com/img002.jpg", - "imageType": "outpatientRecord" - } - ] -} -``` - -#### 响应示例 - -```json -{ - "code": 0, - "message": "success", - "data": { - "id": 1, - "recordStatus": 1 - } -} -``` - -#### 业务逻辑说明 - -1. 若传入 `id`,校验记录存在、属于当前患者、为草稿状态(recordStatus=1),否则报错 -2. 若未传 `id`,新建主记录,设置 recordStatus=1(草稿)、status=1(有效) -3. 保存 CreateWorkerId/CreateTime/UpdateWorkerId/UpdateTime -4. 图片 diff 处理:通过 RecordId + ImageUrl 匹配已有图片记录 - - 已存在 → 更新 ImageType,重置 OcrStatus 为待解析(0),清空 OcrText/OcrParsedData/指标字段 - - 不存在 → 插入新图片记录(OcrStatus 默认为 0) - - 已有但本次未传入 → 逻辑删除(status=100) -5. 最终将所有检验报告图片的指标值和门诊病历图片的病历文本聚合到主表(后出现的值覆盖先出现的值) -6. `manualIgG4Value` 参数写入主表 `ManualIgG4Value` 字段,作为冗余存储,不影响 OCR 解析产生的主数据 `IgG4Value` - ---- - -### 1.1.0 保存图片记录 - -- **路由**:`?r=igg4/medical-visit/save-image` -- **请求方式**:POST -- **说明**:仅保存单张图片记录到就诊记录图片表,不更新主记录字段,不触发指标聚合。前端需先创建草稿获取 RecordId 后再调用此接口。使用数据库事务。 - -#### 请求参数 - -| 参数 | 类型 | 必填 | 说明 | -|------|------|------|------| -| recordId | int | 是 | 已有草稿记录 ID | -| imageUrl | string | 是 | 图片 URL | -| imageType | string | 是 | 图片类型标识,见枚举表 | - -#### imageType 枚举 - -同 [1.1 images.imageType](#imagetype-枚举) - -#### 请求示例 - -```json -{ - "recordId": 1, - "imageUrl": "https://oss.example.com/img001.jpg", - "imageType": "labReport" -} -``` - -#### 响应示例 - -```json -{ - "code": 0, - "message": "success", - "data": { - "imageId": 102, - "recordId": 1, - "imageUrl": "https://oss.example.com/img001.jpg", - "imageType": "labReport", - "ocrStatus": 0 - } -} -``` - -#### 业务逻辑说明 - -1. 校验 recordId 对应的记录存在且属于当前患者,否则报错"就诊记录不存在"或"就诊记录不属于当前患者" -2. 校验记录状态为草稿(recordStatus=1),否则报错"仅草稿状态的记录可添加图片" -3. 将 imageType 字符串转为数据库整型值,无效则报错"无效的图片类型" -4. 根据 RecordId + ImageUrl 判断图片是否已存在: - - 已存在:更新 ImageType,重置 OcrStatus 为待解析(0),清空 OcrText、OcrParsedData 及对应指标/文本字段 - - 不存在:新建图片记录(含 CreateWorkerId/CreateTime),OcrStatus 默认为待解析(0) -5. **不触发主表指标聚合**(与 saveDraft 不同),聚合在调用 saveDraft 或 submit 时发生 -6. 小程序端仅存储原始图片,OCR 解析由后台管理员涂抹图片后触发,返回 ocrStatus 表示当前解析状态 - ---- - -### 1.1.1 删除单个图片 - -- **路由**:`?r=igg4/medical-visit/delete-image` -- **请求方式**:POST -- **说明**:逻辑删除指定图片记录,设置 Status=100,记录操作人和操作时间。使用数据库事务。 - -#### 请求参数 - -| 参数 | 类型 | 必填 | 说明 | -|------|------|------|------| -| imageId | int | 是 | 图片记录 ID | - -#### 请求示例 - -```json -{ - "imageId": 102 -} -``` - -#### 响应示例 - -```json -{ - "code": 0, - "message": "success", - "data": true -} -``` - -#### 业务逻辑说明 - -1. 校验 imageId 必传,否则报错"图片记录ID不能为空" -2. 校验管理员已登录,获取当前操作人 workerId -3. 校验图片记录存在且有效(Status=1),否则报错"图片记录不存在" -4. 逻辑删除:设置 Status=100(已删除),记录 UpdateWorkerId/UpdateTime -5. 返回 true - ---- - -### 1.2 提交就诊记录 - -- **路由**:`?r=igg4/medical-visit/submit` -- **请求方式**:POST -- **说明**:将草稿状态的记录提交,提交后不可再编辑。使用数据库事务。 - -#### 请求参数 - -| 参数 | 类型 | 必填 | 说明 | -|------|------|------|------| -| id | int | 是 | 草稿记录 ID | - -#### 请求示例 - -```json -{ - "id": 1 -} -``` - -#### 响应示例 - -```json -{ - "code": 0, - "message": "success", - "data": true -} -``` - -#### 业务逻辑说明 - -1. 校验记录存在、属于当前患者 -2. 校验记录状态为草稿(recordStatus=1),否则报错"仅草稿状态的记录可提交" -3. 更新 recordStatus=2(已提交),记录 UpdateWorkerId/UpdateTime - ---- - -### 1.3 获取就诊记录详情 - -- **路由**:`?r=igg4/medical-visit/detail` -- **请求方式**:GET -- **说明**:获取单条就诊记录详情,包含主记录所有指标数据和按类型分组的图片列表。 - -#### 请求参数 - -| 参数 | 类型 | 必填 | 说明 | -|------|------|------|------| -| id | int | 是 | 就诊记录 ID | - -#### 响应示例 - -```json -{ - "code": 0, - "message": "success", - "data": { - "id": 1, - "visitDate": "2026-06-29", - "nextVisitDate": "2026-09-29", - "recordStatus": 2, - "igG4Value": 135.0, - "manualIgG4Value": 135.0, - "displayIgG4Value": 135.0, - "totalIgGValue": 1200.0, - "igEValue": 50.0, - "eosCount": 0.3, - "esrValue": 20.0, - "crpValue": 5.0, - "oralHormoneDosage": 4.0, - "medicationsUsed": [2, 3], - "immunosuppressantName": [1, 7], - "medicationsUsedOtherText": null, - "immunosuppressantNameOtherText": null, - "medicalRecordTime": "2026-06-29 09:30:00", - "prescriptionTime": "2026-06-29 10:15:00", - "reportTime": "2026-06-28 14:20:00", - "chiefComplaint": "反复腹痛3月", - "medicalHistory": "现病史:患者3月前无明显诱因出现腹痛...", - "diagnosis": "IgG4相关性疾病", - "treatmentPlan": "激素治疗,定期复查", - "prescription": "甲泼尼龙片 4mg 每日1次 口服 30片", - "clinicalDiagnosis": "IgG4相关性疾病", - "images": { - "outpatientRecord": [ - { - "id": 101, - "imageUrl": "https://...", - "maskedImageUrl": "https://...masked.jpg", - "ocrStatus": 2, - "ocrParsedData": "门诊病历文本...", - "medicalRecordTime": "2026-06-29 09:30:00", - "prescriptionTime": "2026-06-29 10:15:00", - "reportTime": null - } - ], - "labReport": [ - { - "id": 102, - "imageUrl": "https://...", - "maskedImageUrl": "https://...masked.jpg", - "ocrStatus": 2, - "ocrParsedData": { - "reportTime": "2026-06-28", - "indicators": { - "igG4": {"value": 135.0, "unit": "mg/dL"}, - "totalIgG": {"value": 1200.0, "unit": "mg/dL"}, - "igE": {"value": 50.0, "unit": "IU/mL"}, - "eos": {"value": 0.3, "unit": "10^9/L"}, - "esr": {"value": 20.0, "unit": "mm/h"}, - "crp": {"value": 5.0, "unit": "mg/L"} - } - }, - "medicalRecordTime": null, - "prescriptionTime": null, - "reportTime": "2026-06-28 14:20:00" - } - ], - "imagingExam": [ - { - "id": 103, - "imageUrl": "https://...", - "maskedImageUrl": null, - "ocrStatus": 0, - "ocrParsedData": null - } - ], - "pathology": [], - "immuneFunction": [] - } - } -} -``` - -#### images 字段说明 - -- 固定返回 5 种图片类型的分组,无数据时为空数组 -- 每张图片包含 `id`、`imageUrl`、`maskedImageUrl`、`ocrStatus`、`ocrParsedData`、`medicalRecordTime`、`prescriptionTime`、`reportTime` -- `maskedImageUrl`:涂抹后图片 URL,后台管理员未涂抹时为 null -- `ocrStatus`:OCR 解析状态,0-待解析,1-解析中,2-解析完成,3-解析失败 -- `ocrParsedData`:检验报告类型为包含 `reportTime` 和 `indicators` 的结构化 JSON 对象,门诊病历类型为包含 `medicalRecordTime` 和 `prescriptionTime` 的结构化 JSON 对象,其他类型为拼接文本字符串,无 OCR 数据时为 null -- `medicalRecordTime`:病历时间(图片类型=门诊病历且识别为门诊病历时有值),格式 YYYY-MM-DD 或 YYYY-MM-DD HH:mm:ss -- `prescriptionTime`:处方时间(图片类型=门诊病历且识别为处方时有值),格式 YYYY-MM-DD 或 YYYY-MM-DD HH:mm:ss -- `reportTime`:检查报告时间(图片类型=检验报告时有值),格式 YYYY-MM-DD 或 YYYY-MM-DD HH:mm:ss - -#### 主记录字段说明 - -- `displayIgG4Value`:展示用 IgG4 数值,优先取 manualIgG4Value,为空则取 igG4Value;均为空时为 null -- `medicalRecordTime`:病历时间(从门诊病历图片聚合),格式 YYYY-MM-DD 或 YYYY-MM-DD HH:mm:ss,无数据时为 null -- `prescriptionTime`:处方时间(从处方图片聚合),格式 YYYY-MM-DD 或 YYYY-MM-DD HH:mm:ss,无数据时为 null -- `reportTime`:检查报告时间(从检验报告图片聚合),格式 YYYY-MM-DD 或 YYYY-MM-DD HH:mm:ss,无数据时为 null - ---- - -### 1.4 就诊记录列表 - -- **路由**:`?r=igg4/medical-visit/list` -- **请求方式**:GET -- **说明**:获取当前患者的就诊记录列表,支持分页和年份/次数筛选。 - -#### 请求参数 - -| 参数 | 类型 | 必填 | 说明 | -|------|------|------|------| -| page | int | 否 | 页码,默认 1 | -| pageSize | int | 否 | 每页条数,默认 10 | -| year | int | 否 | 按就诊年份筛选(快捷方式,等同于yearStart=year&yearEnd=year) | -| yearStart | int | 否 | 按就诊年份范围筛选-起始年份,优先级高于year | -| yearEnd | int | 否 | 按就诊年份范围筛选-结束年份,优先级高于year | - -#### 响应示例 - -```json -{ - "code": 0, - "message": "success", - "data": { - "page": 1, - "pages": 5, - "totalCount": 50, - "list": [ - { - "id": 1, - "visitDate": "2026-06-29", - "nextVisitDate": "2026-09-29", - "recordStatus": 2, - "igG4Value": 135.0, - "manualIgG4Value": 135.0, - "displayIgG4Value": 135.0, - "medicationsUsed": [2, 3], - "immunosuppressantName": [1, 7], - "medicationsUsedOtherText": null, - "immunosuppressantNameOtherText": null, - "lastIgG4Value": 120.0, - "change": 15.0, - "medicalRecordTime": "2026-06-29 09:30:00", - "prescriptionTime": "2026-06-29 10:15:00", - "reportTime": "2026-06-28 14:20:00" - } - ] - } -} -``` - -#### 说明 - -- 列表按 VisitDate 降序排列 -- 同时传入 `year` 和 `count` 时,先按年份筛选再取最近 N 条 -- `lastIgG4Value`:上一次就诊的 IgG4 值,float 类型;无上一次记录时为 null -- `change`:本次与上一次 IgG4 值的差值(本次 - 上次),float 类型;任一值为 null 时为 null -- `manualIgG4Value`:患者手动录入的 IgG4 数值(冗余字段),未录入时为 null -- `displayIgG4Value`:展示用 IgG4 数值,优先取 manualIgG4Value,为空则取 igG4Value;均为空时为 null -- `medicalRecordTime`:病历时间(从门诊病历图片聚合),格式 YYYY-MM-DD 或 YYYY-MM-DD HH:mm:ss,无数据时为 null -- `prescriptionTime`:处方时间(从处方图片聚合),格式 YYYY-MM-DD 或 YYYY-MM-DD HH:mm:ss,无数据时为 null -- `reportTime`:检查报告时间(从检验报告图片聚合),格式 YYYY-MM-DD 或 YYYY-MM-DD HH:mm:ss,无数据时为 null -- `medicationsUsed`:本次就诊已使用的药物(多选),值为常量ID数组,见附录G;未选择时为 null -- `immunosuppressantName`:正在使用的免疫抑制剂名称(多选),值为常量ID数组,见附录G;未选择时为 null -- `medicationsUsedOtherText`:本次就诊已使用药物选择"其他"(99)时的补充文本,未选择"其他"时为 null -- `immunosuppressantNameOtherText`:正在使用的免疫抑制剂名称选择"其他"(99)时的补充文本,未选择"其他"时为 null - -- 年份筛选优先级:传入 `yearStart`+`yearEnd` 时优先按范围筛选,忽略 `year` 参数;仅传 `yearStart` 取 >= 起始年份;仅传 `yearEnd` 取 <= 结束年份;仅传 `year` 则按单年份筛选 - ---- - -### 1.5 删除就诊记录 - -- **路由**:`?r=igg4/medical-visit/delete` -- **请求方式**:POST -- **说明**:逻辑删除就诊记录及其所有图片。使用数据库事务。 - -#### 请求参数 - -| 参数 | 类型 | 必填 | 说明 | -|------|------|------|------| -| id | int | 是 | 就诊记录 ID | - -#### 响应示例 - -```json -{ - "code": 0, - "message": "success", - "data": true -} -``` - -#### 业务逻辑说明 - -1. 校验记录存在、属于当前患者 -2. 将主记录 status 设为 100(删除),记录 UpdateWorkerId/UpdateTime -3. 将该记录下所有图片 status 设为 100(删除) - ---- - -### 1.6 图片字段历史列表 - -- **路由**:`?r=igg4/medical-visit/image-history` -- **请求方式**:GET -- **说明**:查询指定图片类型的历史列表,返回每次就诊中该类型图片的 URL,按就诊日期降序排列。仅返回已提交的记录。 - -#### 请求参数 - -| 参数 | 类型 | 必填 | 说明 | -|------|------|------|------| -| imageField | string | 是 | 图片类型标识 | -| year | int | 否 | 按就诊年份筛选(快捷方式,等同于yearStart=year&yearEnd=year) | -| yearStart | int | 否 | 按就诊年份范围筛选-起始年份,优先级高于year | -| yearEnd | int | 否 | 按就诊年份范围筛选-结束年份,优先级高于year | -| page | int | 否 | 页码,默认 1 | -| pageSize | int | 否 | 每页条数,默认 10 | - -#### imageField 枚举 - -| 值 | 说明 | -|------|------| -| outpatientRecord | 门诊病历及处方 | -| labReport | 检验报告 | -| imagingExam | 影像学检查 | -| pathology | 病理诊断及活检 | -| immuneFunction | 外周血免疫功能评估 | - -#### 响应示例 - -```json -{ - "code": 0, - "message": "success", - "data": { - "page": 1, - "pages": 5, - "totalCount": 50, - "list": [ - { - "visitDate": "2026-06-29", - "imageUrls": [ - "https://picsissiok-10049618.cos.ap-shanghai.myqcloud.com/0e3a32a7612090359a9ca36117d0f2db_17835667161658.jpg" - ], - "ocrStatus": 2 - }, - { - "visitDate": "2026-03-15", - "imageUrls": [ - "https://...", - ], - "ocrStatus": 0 - } - ] - } -} -``` - -- 分页按就诊记录维度,每页包含对应就诊记录中该类型的所有图片 URL 数组 - --> imageUrls :图片 URL 数组 - ---- - -### 1.7 指标字段历史列表 - -- **路由**:`?r=igg4/medical-visit/indicator-history` -- **请求方式**:GET -- **说明**:查询指定指标字段的历史数据列表,返回每次就诊中该指标的值,按就诊日期降序排列。仅返回已提交的记录。 - -#### 请求参数 - -| 参数 | 类型 | 必填 | 说明 | -|------|------|------|------| -| indicatorField | string | 是 | 指标字段标识 | -| year | int | 否 | 按就诊年份筛选(快捷方式,等同于yearStart=year&yearEnd=year) | -| yearStart | int | 否 | 按就诊年份范围筛选-起始年份,优先级高于year | -| yearEnd | int | 否 | 按就诊年份范围筛选-结束年份,优先级高于year | - -#### indicatorField 枚举 - -| 值 | 说明 | 单位 | -|------|------|------| -| igG4 | IgG4(免疫球蛋白G4亚类) | mg/dL | -| totalIgG | 总IgG(免疫球蛋白G) | mg/dL | -| igE | IgE(免疫球蛋白E) | IU/mL | -| eos | EOS#(嗜酸细胞绝对计数) | 10^9/L | -| esr | ESR(红细胞沉降率/血沉) | mm/h | -| crp | CRP(C-反应蛋白) | mg/L | - -#### 响应示例 - -```json -{ - "code": 0, - "message": "success", - "data": { - "unit": "mg/dL", - "list": [ - { - "visitDate": "2026-06-29", - "value": 135.0 - }, - { - "visitDate": "2026-03-15", - "value": 260.0 - } - ] - } -} -``` - ---- - -### 1.8 OCR 图片解析 - -- **路由**:`?r=igg4/medical-visit/ocr-parse` -- **请求方式**:POST -- **说明**:对图片进行阿里云 OCR 文字识别。检验报告类型自动提取指标数值并做单位换算,其他类型仅返回拼接文本。 - -#### 请求参数 - -| 参数 | 类型 | 必填 | 说明 | -|------|------|------|------| -| imageUrl | string | 是 | 图片 URL(需为阿里云上海 OSS 地址) | -| imageType | string | 是 | 图片类型标识 | - -#### imageType 枚举 - -同 [1.1 images.imageType](#imagetype-枚举) - -#### 响应示例 — 检验报告类型(imageType=labReport) - -```json -{ - "code": 0, - "message": "success", - "data": { - "ocrText": "IgG4 1.35 g/L\n总IgG 12.0 g/L\nIgE 50 IU/mL\nESR 20 mm/h\nCRP 5 mg/L", - "ocrParsedData": { - "reportTime": "2026-06-28 14:20:00", - "indicators": { - "igG4": {"value": 135.0, "unit": "mg/dL"}, - "totalIgG": {"value": 1200.0, "unit": "mg/dL"}, - "igE": {"value": 50.0, "unit": "IU/mL"}, - "eos": {"value": null, "unit": "10^9/L"}, - "esr": {"value": 20.0, "unit": "mm/h"}, - "crp": {"value": 5.0, "unit": "mg/L"} - } - } - } -} -``` - -#### 响应示例 — 门诊病历类型(imageType=outpatientRecord) - -```json -{ - "code": 0, - "message": "success", - "data": { - "ocrText": "患者XXX,男,45岁\n主诉:反复腹痛3月\n现病史:患者3月前无明显诱因出现腹痛\n诊断:IgG4相关性疾病\n处理意见:激素治疗,定期复查", - "ocrParsedData": { - "chiefComplaint": "反复腹痛3月", - "medicalHistory": "患者3月前无明显诱因出现腹痛", - "diagnosis": "IgG4相关性疾病", - "treatmentPlan": "激素治疗,定期复查", - "prescription": "甲泼尼龙片 4mg 每日1次 口服 30片", - "clinicalDiagnosis": "IgG4相关性疾病" - } - } -} -``` - -#### 响应示例 — 其他类型(如 imageType=imagingExam) - -```json -{ - "code": 0, - "message": "success", - "data": { - "ocrText": "影像学检查报告文本...", - "ocrParsedData": "影像学检查报告文本..." - } -} -``` - -#### OCR 指标识别规则 - -| 指标 | 关键词匹配 | 单位换算 | -|------|-----------|---------| -| IgG4 | `IgG4`、`免疫球蛋白G4`、`免疫球蛋白G4亚类` | 若为 g/L 则 ×100 → mg/dL | -| 总IgG | `IgG`(独立,非IgG1-5/IgG4/IgE)、`免疫球蛋白G` | 若为 g/L 则 ×100 → mg/dL | -| IgE | `IgE`、`免疫球蛋白E` | 不换算,保持 IU/mL | -| EOS# | `EOS#`、`嗜酸细胞绝对计数`、`嗜酸性粒细胞绝对值` | 不换算,保持 10^9/L | -| ESR | `ESR`、`红细胞沉降率`、`血沉` | 不换算,保持 mm/h | -| CRP | `CRP`、`C-反应蛋白`、`C反应蛋白` | 不换算,保持 mg/L | - -#### 门诊病历 OCR 识别规则 - -| 字段 | 关键词匹配 | -|------|-----------| -| 主诉 | `主诉` | -| 病史 | `现病史`、`既往史`、`病史` | -| 诊断 | `诊断`、`Imp`、`印象` | -| 处理意见 | `处理意见`、`医嘱`、`处理`、`治疗方案` | - ---- - -### 1.9 保存复诊提醒配置 - -- **路由**:`?r=igg4/medical-visit/save-reminder-config` -- **请求方式**:POST -- **说明**:患者配置是否开启复诊提醒。开启后,定时任务将在复诊日期前7天发送微信Push通知。使用数据库事务。 - -#### 请求参数 - -| 参数 | 类型 | 必填 | 说明 | -|------|------|------|------| -| reminderEnabled | int | 是 | 是否开启复诊提醒:1-开启,2-关闭 | - -#### 请求示例 - -```json -{ - "reminderEnabled": 1 -} -``` - -#### 响应示例 - -```json -{ - "code": 0, - "message": "success", - "data": true -} -``` - -#### 业务逻辑说明 - -1. 校验 reminderEnabled 参数必填,值只能为1(开启)或2(关闭),否则报错"reminderEnabled参数无效" -2. 查询当前患者是否已有配置记录 -3. 已有配置:更新 ReminderEnabled,记录 UpdateWorkerId/UpdateTime -4. 无配置:新建配置记录,设置 PatientId、ReminderEnabled、Status=1,记录 CreateWorkerId/CreateTime/UpdateWorkerId/UpdateTime -5. 每个患者只保留一条有效配置记录(通过 PatientId 唯一约束保证) - ---- - -### 1.10 获取复诊提醒配置 - -- **路由**:`?r=igg4/medical-visit/get-reminder-config` -- **请求方式**:GET -- **说明**:获取当前患者的复诊提醒配置。未配置过时返回默认值(关闭)。 - -#### 请求参数 - -无 - -#### 响应示例 - -```json -{ - "code": 0, - "message": "success", - "data": { - "reminderEnabled": 2 - } -} -``` - -#### 说明 - -- `reminderEnabled`:1-开启,2-关闭。患者未配置过时默认返回2(关闭) -- 配置数据来源于 `t_medical_visit_reminder_config` 表 - ---- - -### 1.11 获取最近就诊记录 - -- **路由**:`?r=igg4/medical-visit/get-latest-record` -- **请求方式**:GET -- **说明**:获取当前患者按就诊日期最近的一条就诊记录详情,包含草稿和已提交记录。无记录时 data 为 null。 - -#### 请求参数 - -无 - -#### 响应示例 — 有记录时 - -同 [1.3 获取就诊记录详情](#13-获取就诊记录详情) 的 data 格式。 - -#### 响应示例 — 无记录时 - -```json -{ - "code": 0, - "message": "success", - "data": null -} -``` - -#### 说明 - -- 返回当前患者按就诊日期(VisitDate)降序最近的一条就诊记录详情 -- 不限制记录状态,草稿(recordStatus=1)和已提交(recordStatus=2)均可能返回 -- 同一天多条记录时,返回 ID 最大的那条 -- 返回格式与详情接口完全一致,包含图片分组等完整信息 - ---- - -## 二、医生端接口 - -模块路由前缀:`igg4/doctor/medical-visit` - -医生端所有接口均为**只读**,且只能查看**已提交**(recordStatus=2)的记录,草稿对医生不可见。所有接口需额外传入 `patientId` 参数指定查看的患者。 - ---- - -### 2.1 就诊记录列表 - -- **路由**:`?r=igg4/doctor/medical-visit/list` -- **请求方式**:GET -- **说明**:医生查看指定患者的已提交就诊记录列表。 - -#### 请求参数 - -| 参数 | 类型 | 必填 | 说明 | -|------|------|------|------| -| patientId | int | 是 | 患者 ID | -| page | int | 否 | 页码,默认 1 | -| pageSize | int | 否 | 每页条数,默认 10 | -| year | int | 否 | 按就诊年份筛选(快捷方式,等同于yearStart=year&yearEnd=year) | -| yearStart | int | 否 | 按就诊年份范围筛选-起始年份,优先级高于year | -| yearEnd | int | 否 | 按就诊年份范围筛选-结束年份,优先级高于year | - -#### 响应示例 - -同 [1.4 就诊记录列表](#14-就诊记录列表),但仅返回已提交的记录。 - ---- - -### 2.2 就诊记录详情 - -- **路由**:`?r=igg4/doctor/medical-visit/detail` -- **请求方式**:GET -- **说明**:医生查看指定患者的某条就诊记录详情。 - -#### 请求参数 - -| 参数 | 类型 | 必填 | 说明 | -|------|------|------|------| -| id | int | 是 | 就诊记录 ID | -| patientId | int | 是 | 患者 ID | - -#### 响应示例 - -同 [1.3 获取就诊记录详情](#13-获取就诊记录详情)。 - ---- - -### 2.3 图片字段历史列表 - -- **路由**:`?r=igg4/doctor/medical-visit/image-history` -- **请求方式**:GET -- **说明**:医生查看指定患者的某种图片类型历史列表。 - -#### 请求参数 - -| 参数 | 类型 | 必填 | 说明 | -|------|------|------|------| -| patientId | int | 是 | 患者 ID | -| imageField | string | 是 | 图片类型标识 | -| year | int | 否 | 按就诊年份筛选(快捷方式,等同于yearStart=year&yearEnd=year) | -| yearStart | int | 否 | 按就诊年份范围筛选-起始年份,优先级高于year | -| yearEnd | int | 否 | 按就诊年份范围筛选-结束年份,优先级高于year | - -#### imageField 枚举 - -同 [1.6 imageField 枚举](#imagefield-枚举) - -#### 响应示例 - -同 [1.6 图片字段历史列表](#16-图片字段历史列表),仅返回已提交记录的数据。 - ---- - -### 2.4 指标字段历史列表 - -- **路由**:`?r=igg4/doctor/medical-visit/indicator-history` -- **请求方式**:GET -- **说明**:医生查看指定患者的某个指标字段历史数据趋势。 - -#### 请求参数 - -| 参数 | 类型 | 必填 | 说明 | -|------|------|------|------| -| patientId | int | 是 | 患者 ID | -| indicatorField | string | 是 | 指标字段标识 | -| year | int | 否 | 按就诊年份筛选(快捷方式,等同于yearStart=year&yearEnd=year) | -| yearStart | int | 否 | 按就诊年份范围筛选-起始年份,优先级高于year | -| yearEnd | int | 否 | 按就诊年份范围筛选-结束年份,优先级高于year | - -#### indicatorField 枚举 - -同 [1.7 indicatorField 枚举](#indicatorfield-枚举) - -#### 响应示例 - -同 [1.7 指标字段历史列表](#17-指标字段历史列表),仅返回已提交记录的数据。 - ---- - -### 2.5 导出就诊记录PPT - -- **路由**:`?r=igg4/doctor/medical-visit/export-ppt` -- **请求方式**:POST -- **说明**:医生导出指定患者的就诊记录PPT文件,包含5个模块:患者基本信息、主诉与诊断、检验报告指标趋势、就诊记录处方、激素用量。仅包含已提交的记录。 - -#### 请求参数 - -| 参数 | 类型 | 必填 | 说明 | -|------|------|------|------| -| patientId | int | 是 | 患者 ID | - -#### 响应 - -直接返回PPT文件流(Content-Type: application/vnd.openxmlformats-officedocument.presentationml.presentation),浏览器触发下载。文件名格式:`就诊记录_{patientId}_{timestamp}.pptx`。 - -#### PPT内容结构 - -| 页码 | 模块 | 说明 | -|------|------|------| -| 1 | 01. 患者基本信息 | 姓名(脱敏)、性别、年龄段、首次发病时间、首次发病部位、是否确诊IgG4 | -| 2+ | 02. 就诊记录病历:主诉与诊断 | 每页5条,展示就诊时间/主诉/病史/诊断/处理意见 | -| N+ | 03. 检验报告(实验室核心血清学指标趋势追踪) | 每页10条,表格展示6项指标 | -| N+ | 04. 就诊记录处方 | 每页3条,展示处方信息 | -| N+ | 05. 激素用量 | 每页10条,表格展示日期+用量 | - -#### 数据脱敏规则 - -- 患者姓名:2字显示"张*",3字及以上显示"张*丰"(保留首尾字符) -- 年龄:转换为年龄段(18-44岁/45-59岁/60-74岁/75岁以上) - -#### 业务逻辑说明 - -1. 校验 patientId 必传 -2. 查询患者基本信息(TZdPatientInfo + 健康问卷最新答案) -3. 查询已提交就诊记录列表(RecordStatus=2, Status=1) -4. 查询用药记录(TZdPatientMedicationRecord) -5. 生成PPT临时文件并返回文件流 -6. 返回后自动删除临时文件 - ---- - -## 三、后台管理员接口 - -模块路由前缀:`medical-visit-record` - -后台管理员负责对小程序用户上传的图片进行涂抹处理,涂抹后上传涂抹图片并同步触发 OCR 解析。所有 POST 接口使用数据库事务。 - ---- - -### 3.1 就诊记录列表 - -- **路由**:`?r=medical-visit-record/list` -- **请求方式**:GET -- **说明**:后台管理就诊记录列表,以图片为主表(一张图一条数据),支持按提交人姓名和图片类型筛选,仅展示已提交的记录。 - -#### 请求参数 - -| 参数 | 类型 | 必填 | 说明 | -|------|------|------|------| -| submitterName | string | 否 | 提交人姓名(患者姓名模糊搜索) | -| imageType | string | 否 | 图片类型标识,不传则返回全部,见枚举表 | -| page | int | 否 | 页码,默认 1 | -| pageSize | int | 否 | 每页条数,默认 10 | - -#### imageType 枚举 - -同 [1.1 images.imageType](#imagetype-枚举) - -#### 响应示例 - -```json -{ - "code": 0, - "message": "success", - "data": { - "page": 1, - "pages": 5, - "totalCount": 50, - "list": [ - { - "id": 102, - "submitterName": "张三", - "recordTime": "2026-06-29 14:20:00", - "visitDate": "2026-06-29", - "nextVisitDate": "2026-09-29", - "imageType": "labReport", - "imageUrl": "https://oss.example.com/img001.jpg", - "maskedImageUrl": "https://oss.example.com/img001_masked.jpg", - "igG4Value": 135.0, - "manualIgG4Value": 135.0, - "displayIgG4Value": 135.0, - "chiefComplaint": null, - "medicalHistory": null, - "diagnosis": null, - "treatmentPlan": null, - "medicalRecordTime": null, - "prescriptionTime": null, - "reportTime": "2026-06-28 14:20:00", - "prescription": null, - "clinicalDiagnosis": null, - "oralHormoneDosage": 4.0, - "medicationsUsed": [2, 3], - "immunosuppressantName": [1, 7], - "medicationsUsedOtherText": null, - "immunosuppressantNameOtherText": null - }, - { - "id": 103, - "submitTime": "2026-06-29 10:30:00", - "submitterName": "张三", - "recordTime": "2026-06-29 15:00:00", - "visitDate": "2026-06-29", - "nextVisitDate": "2026-09-29", - "imageType": "outpatientRecord", - "imageUrl": "https://oss.example.com/img002.jpg", - "maskedImageUrl": "https://oss.example.com/img002_masked.jpg", - "igG4Value": null, - "manualIgG4Value": 135.0, - "displayIgG4Value": 135.0, - "chiefComplaint": "反复腹痛3月", - "medicalHistory": "患者3月前无明显诱因出现腹痛", - "diagnosis": "IgG4相关性疾病", - "treatmentPlan": "激素治疗,定期复查", - "medicalRecordTime": "2026-06-29 09:30:00", - "prescriptionTime": "2026-06-29 10:15:00", - "reportTime": null, - "prescription": "甲泼尼龙片 4mg 每日1次 口服 30片", - "clinicalDiagnosis": "IgG4相关性疾病", - "oralHormoneDosage": 4.0, - "medicationsUsed": [2, 3], - "immunosuppressantName": [1, 7], - "medicationsUsedOtherText": null, - "immunosuppressantNameOtherText": null - } - ] - } -} -``` - -#### 字段说明 - -| 字段 | 类型 | 说明 | -|------|------|------| -| id | int | 图片记录 ID | -| submitterName | string | 提交人姓名(患者姓名) | -| recordTime | string | 记录时间(图片创建时间) | -| visitDate | string | 就诊时间 | -| nextVisitDate | string | 复诊时间 | -| imageType | string | 图片类型标识(camelCase) | -| imageUrl | string | 患者提交的图片 URL | -| maskedImageUrl | string | 后台处理后的图片 URL,未涂抹时为 null | -| igG4Value | float | IgG4 数值(mg/dL),仅检验报告类型有值 | -| manualIgG4Value | float | 患者手动录入的 IgG4 数值(冗余字段,mg/dL),未录入时为 null | -| displayIgG4Value | float | 展示用 IgG4 数值,优先取 manualIgG4Value,为空则取 igG4Value;均为空时为 null | -| chiefComplaint | string | 主诉内容,仅门诊病历类型有值 | -| medicalHistory | string | 现病史/既往史/病史,仅门诊病历类型有值 | -| diagnosis | string | 诊断,仅门诊病历类型有值 | -| treatmentPlan | string | 处理意见/医嘱/治疗方案,仅门诊病历类型有值 | -| medicalRecordTime | string | 病历时间(图片类型=门诊病历时有值),格式 YYYY-MM-DD 或 YYYY-MM-DD HH:mm:ss | -| prescriptionTime | string | 处方时间(图片类型=门诊病历时有值),格式 YYYY-MM-DD 或 YYYY-MM-DD HH:mm:ss | -| reportTime | string | 检查报告时间(图片类型=检验报告时有值),格式 YYYY-MM-DD 或 YYYY-MM-DD HH:mm:ss | -| prescription | string | 处方内容,仅门诊病历类型有值 | -| clinicalDiagnosis | string | 临床诊断,仅处方类型图片有值;未解析到时为 null | -| oralHormoneDosage | float | 激素用量(片/天) | -| medicationsUsed | array | 本次就诊已使用的药物(多选),值为常量ID数组,见附录G;未选择时为 null | -| immunosuppressantName | array | 正在使用的免疫抑制剂名称(多选),值为常量ID数组,见附录G;未选择时为 null | -| medicationsUsedOtherText | string | 本次就诊已使用药物选择"其他"(99)时的补充文本,未选择"其他"时为 null | -| immunosuppressantNameOtherText | string | 正在使用的免疫抑制剂名称选择"其他"(99)时的补充文本,未选择"其他"时为 null | - -#### 业务逻辑说明 - -1. 以图片表(t_iggfour_medical_visit_record_image)为主表,一张图一条数据 -2. JOIN 就诊记录表获取 VisitDate、NextVisitDate、OralHormoneDosage,且约束 RecordStatus=2(已提交) -3. JOIN 患者表获取患者姓名(submitterName) -4. 提交人姓名筛选:患者姓名模糊匹配(LIKE) -5. 图片类型筛选:imageType 参数传入 camelCase 标识,内部转为整型后 WHERE 匹配 -6. 仅展示已提交记录(RecordStatus=2),草稿不在列表中显示 -7. 按图片创建时间(CreateTime)降序排列 - ---- - -### 3.2 上传涂抹图片并解析 - -- **路由**:`?r=medical-visit-record/upload-masked-image` -- **请求方式**:POST -- **说明**:管理员上传涂抹后的图片 URL,保存后同步触发 OCR 解析。涂抹后立即执行 OCR,无需异步任务。使用数据库事务。 - -#### 请求参数 - -| 参数 | 类型 | 必填 | 说明 | -|------|------|------|------| -| imageId | int | 是 | 图片记录 ID | -| maskedImageUrl | string | 是 | 涂抹后图片 URL | - -#### 请求示例 - -```json -{ - "imageId": 102, - "maskedImageUrl": "https://oss.example.com/img001_masked.jpg" -} -``` - -#### 响应示例 — 检验报告类型(imageType=labReport) - -```json -{ - "code": 0, - "message": "success", - "data": { - "imageId": 102, - "maskedImageUrl": "https://oss.example.com/img001_masked.jpg", - "ocrStatus": 2, - "ocrText": "IgG4 1.35 g/L\n总IgG 12.0 g/L\nIgE 50 IU/mL\nESR 20 mm/h\nCRP 5 mg/L", - "ocrParsedData": { - "reportTime": "2026-06-28 14:20:00", - "indicators": { - "igG4": {"value": 135.0, "unit": "mg/dL"}, - "totalIgG": {"value": 1200.0, "unit": "mg/dL"}, - "igE": {"value": 50.0, "unit": "IU/mL"}, - "eos": {"value": null, "unit": "10^9/L"}, - "esr": {"value": 20.0, "unit": "mm/h"}, - "crp": {"value": 5.0, "unit": "mg/L"} - } - }, - "igG4Value": 322, - "totalIgGValue": 1370, - "igEValue": null, - "eosCount": null, - "esrValue": null, - "crpValue": null, - "chiefComplaint": null, - "medicalHistory": null, - "diagnosis": null, - "treatmentPlan": null, - "prescription": null, - "clinicalDiagnosis": null, - "medicalRecordTime": null, - "prescriptionTime": null, - "reportTime": "2026-06-28 14:20:00" - } -} -``` - -#### 响应示例 — 门诊病历类型(imageType=outpatientRecord) - -```json -{ - "code": 0, - "message": "success", - "data": { - "imageId": 103, - "maskedImageUrl": "https://oss.example.com/img002_masked.jpg", - "ocrStatus": 2, - "ocrText": "患者XXX,男,45岁\n主诉:反复腹痛3月\n诊断:IgG4相关性疾病\n处理意见:激素治疗,定期复查", - "ocrParsedData": { - "medicalRecordTime": "2026-06-29 09:30:00", - "prescriptionTime": "2026-06-29 10:15:00", - "chiefComplaint": "反复腹痛3月", - "medicalHistory": "患者3月前无明显诱因出现腹痛", - "diagnosis": "IgG4相关性疾病", - "treatmentPlan": "激素治疗,定期复查", - "prescription": "甲泼尼龙片 4mg 每日1次 口服 30片", - "clinicalDiagnosis": "IgG4相关性疾病" - }, - "igG4Value": null, - "totalIgGValue": null, - "igEValue": null, - "eosCount": null, - "esrValue": null, - "crpValue": null, - "chiefComplaint": "反复腹痛3月", - "medicalHistory": "患者3月前无明显诱因出现腹痛", - "diagnosis": "IgG4相关性疾病", - "treatmentPlan": "激素治疗,定期复查", - "prescription": "甲泼尼龙片 4mg 每日1次 口服 30片", - "clinicalDiagnosis": "IgG4相关性疾病", - "medicalRecordTime": "2026-06-29 09:30:00", - "prescriptionTime": "2026-06-29 10:15:00", - "reportTime": null - } -} -``` - -#### 响应示例 — OCR 解析失败 - -```json -{ - "code": 0, - "message": "success", - "data": { - "imageId": 104, - "maskedImageUrl": "https://oss.example.com/img003_masked.jpg", - "ocrStatus": 3, - "ocrText": null, - "ocrParsedData": null, - "igG4Value": null, - "totalIgGValue": null, - "igEValue": null, - "eosCount": null, - "esrValue": null, - "crpValue": null, - "chiefComplaint": null, - "medicalHistory": null, - "diagnosis": null, - "treatmentPlan": null, - "prescription": null, - "clinicalDiagnosis": null, - "medicalRecordTime": null, - "prescriptionTime": null, - "reportTime": null - } -} -``` - -#### 业务逻辑说明 - -1. 校验 imageId 对应的图片记录存在,否则报错"图片记录不存在" -2. 校验管理员已登录,获取当前操作人 workerId -3. **事务1**:保存 MaskedImageUrl,设置 OcrStatus=1(解析中),清空旧的 OcrText/OcrParsedData/指标字段/时间字段(MedicalRecordTime/PrescriptionTime/ReportTime),记录 UpdateWorkerId/UpdateTime -4. 事务1提交后,同步调用 OCR 服务:`LabReportOcrService::recognizeByType($maskedImageUrl, $imageTypeKey)` -5. 根据 imageType 类型处理 OCR 结果: - - 检验报告(labReport):解析指标值写入图片记录的独立指标字段(IgG4Value/TotalIgGValue 等),时间字段写入 ReportTime - - 门诊病历(outpatientRecord):解析文本写入图片记录的病历文本字段(ChiefComplaint/MedicalHistory 等),时间字段写入 MedicalRecordTime/PrescriptionTime - - 其他类型:原始文本写入 OcrText,OcrParsedData 存原文 -6. **事务2**:写入 OCR 解析结果,设置 OcrStatus=2(解析完成),记录 UpdateWorkerId/UpdateTime -7. 若 OCR 调用抛异常,**事务2回退**:设置 OcrStatus=3(解析失败),记录 UpdateWorkerId/UpdateTime -8. 返回包含 maskedImageUrl、ocrStatus、ocrText、ocrParsedData、指标字段 的结果数据 -9. igG4Value - IgG4 指标值(单位:mg/dL) -10. totalIgGValue - 总 IgG 指标值(单位:mg/dL) -11. igEValue - IgE 指标值(单位:IU/mL) -12. eosCount - eos 指标值(单位:10^9/L) -13. esrValue - ESR 指标值(单位:mm/h) -14. crpValue - CRP 指标值(单位:mg/L) -15. chiefComplaint - 主诉 -16. medicalHistory - 病史 -17. diagnosis - 诊断 -18. treatmentPlan - 处理意见 -19. prescription - 处方 -20. medicalRecordTime - 病历时间(门诊病历图片识别为门诊病历时,从OCR解析获取) -21. prescriptionTime - 处方时间(门诊病历图片识别为处方时,从OCR解析获取) -22. reportTime - 检查报告时间(检验报告图片,从OCR解析获取) -23. ocrParsedData 结构说明:检验报告返回 `{reportTime, indicators: {...}}`,门诊病历返回 `{medicalRecordTime, prescriptionTime, chiefComplaint, ...}` - - - ---- - -#### ocrStatus 枚举 - -| 值 | 说明 | -|------|------| -| 0 | 待解析(小程序用户已上传原图,后台尚未涂抹) | -| 1 | 解析中(后台已上传涂抹图片,OCR 正在执行) | -| 2 | 解析完成 | -| 3 | 解析失败 | - ---- - -## 附录 - -### A. 记录状态枚举 - -| 值 | 常量名 | 说明 | -|------|------|------| -| 1 | RECORD_STATUS_DRAFT | 草稿 | -| 2 | RECORD_STATUS_SUBMITTED | 已提交 | - -### B. 数据状态枚举 - -| 值 | 常量名 | 说明 | -|------|------|------| -| 1 | STATUS_ACTIVE | 有效 | -| 100 | STATUS_DELETED | 已删除 | - -### C. 口服激素用量预设选项(片/天) - -| 值 | 说明 | -|------|------| -| 1 | 1片/天 | -| 2 | 2片/天 | -| 4 | 4片/天 | -| 6 | 6片/天 | -| 8 | 8片/天 | - -### D. 检验指标单位换算 - -| 指标 | 原始单位 | 目标单位 | 换算公式 | -|------|---------|---------|---------| -| IgG4 | g/L | mg/dL | 值 × 100 | -| 总IgG | g/L | mg/dL | 值 × 100 | -| IgE | — | IU/mL | 不换算 | -| EOS# | — | 10^9/L | 不换算 | -| ESR | — | mm/h | 不换算 | -| CRP | — | mg/L | 不换算 | - -### E. 数据库表结构 - -#### t_iggfour_medical_visit_record 就诊记录主表 - -| 字段名 | 类型 | 说明 | -|--------|------|------| -| Id | int AUTO_INCREMENT PK | 主键 | -| UserId | varchar(40) NOT NULL | 用户 ID | -| PatientId | int NOT NULL | 患者 ID | -| VisitDate | date NOT NULL | 就诊日期 | -| NextVisitDate | date DEFAULT NULL | 下次复诊日期 | -| IgG4Value | decimal(10,2) DEFAULT NULL | IgG4 数值(OCR 解析) | -| ManualIgG4Value | decimal(10,2) DEFAULT NULL | IgG4 数值(患者手动录入,冗余字段) | -| TotalIgGValue | decimal(10,2) DEFAULT NULL | 总 IgG 数值 | -| IgEValue | decimal(10,2) DEFAULT NULL | IgE 数值 | -| EosCount | decimal(10,2) DEFAULT NULL | EOS# 计数 | -| ESRValue | decimal(10,2) DEFAULT NULL | ESR 数值 | -| CRPValue | decimal(10,2) DEFAULT NULL | CRP 数值 | -| OralHormoneDosage | decimal(10,2) DEFAULT NULL | 口服激素每日用量(片) | -| MedicationsUsed | varchar(255) DEFAULT NULL | 本次就诊已使用的药物(JSON数组,多选),见附录G | -| ImmunosuppressantName | varchar(255) DEFAULT NULL | 正在使用的免疫抑制剂名称(JSON数组,多选),见附录G | -| MedicationsUsedOtherText | varchar(500) DEFAULT NULL | 本次就诊已使用药物-其他-补充文本 | -| ImmunosuppressantNameOtherText | varchar(500) DEFAULT NULL | 正在使用的免疫抑制剂名称-其他-补充文本 | -| MedicalRecordTime | varchar(30) DEFAULT NULL | 门诊病历时间 | -| PrescriptionTime | varchar(30) DEFAULT NULL | 处方时间 | -| ReportTime | varchar(30) DEFAULT NULL | 检查报告时间 | -| ChiefComplaint | text DEFAULT NULL | 主诉 | -| MedicalHistory | text DEFAULT NULL | 病史 | -| Diagnosis | text DEFAULT NULL | 诊断 | -| TreatmentPlan | text DEFAULT NULL | 处理意见 | -| Prescription | text DEFAULT NULL | 处方内容 | -| ClinicalDiagnosis | varchar(500) DEFAULT NULL | 临床诊断(从处方图片解析) | -| RecordStatus | tinyint NOT NULL DEFAULT 1 | 记录状态:1-草稿,2-已提交 | -| LastRecordId | int DEFAULT NULL | 上一条记录 ID | -| Status | tinyint NOT NULL DEFAULT 1 | 数据状态:1-有效,100-删除 | -| CreateWorkerId | int NOT NULL DEFAULT 0 | 创建人 | -| CreateTime | datetime NOT NULL | 创建时间 | -| UpdateWorkerId | int NOT NULL DEFAULT 0 | 更新人 | -| UpdateTime | datetime NOT NULL | 更新时间 | - -#### t_iggfour_medical_visit_record_image 就诊记录图片表 - -| 字段名 | 类型 | 说明 | -|--------|------|------| -| Id | int AUTO_INCREMENT PK | 主键 | -| RecordId | int NOT NULL | 关联就诊记录 ID | -| ImageType | tinyint NOT NULL | 图片类型:1-门诊病历,2-检验报告,3-影像检查,4-其他 | -| ImageUrl | varchar(500) NOT NULL | 原始图片 URL | -| MaskedImageUrl | varchar(500) DEFAULT NULL | 涂抹后图片 URL | -| OcrStatus | tinyint NOT NULL DEFAULT 0 | OCR 状态:0-未解析,1-解析中,2-解析完成,3-解析失败 | -| OcrText | text DEFAULT NULL | OCR 原始文本 | -| OcrParsedData | text DEFAULT NULL | OCR 解析结果(JSON) | -| IgG4Value | decimal(10,2) DEFAULT NULL | IgG4 数值 | -| TotalIgGValue | decimal(10,2) DEFAULT NULL | 总 IgG 数值 | -| IgEValue | decimal(10,2) DEFAULT NULL | IgE 数值 | -| EosCount | decimal(10,2) DEFAULT NULL | EOS# 计数 | -| ESRValue | decimal(10,2) DEFAULT NULL | ESR 数值 | -| CRPValue | decimal(10,2) DEFAULT NULL | CRP 数值 | -| ChiefComplaint | text DEFAULT NULL | 主诉(从门诊病历图片解析) | -| MedicalHistory | text DEFAULT NULL | 病史(从门诊病历图片解析) | -| Diagnosis | text DEFAULT NULL | 诊断(从门诊病历图片解析) | -| TreatmentPlan | text DEFAULT NULL | 处理意见(从门诊病历图片解析) | -| Prescription | text DEFAULT NULL | 从本图OCR解析的处方内容,仅图片类型=1时有值 | -| ClinicalDiagnosis | varchar(500) DEFAULT NULL | 临床诊断(从处方图片解析) | -| MedicalRecordTime | varchar(30) DEFAULT NULL | 门诊病历时间 | -| PrescriptionTime | varchar(30) DEFAULT NULL | 处方时间 | -| ReportTime | varchar(30) DEFAULT NULL | 检查报告时间 | -| SortOrder | int NOT NULL DEFAULT 0 | 排序序号 | -| Status | tinyint NOT NULL DEFAULT 1 | 数据状态:1-有效,100-删除 | -| CreateWorkerId | int NOT NULL DEFAULT 0 | 创建人 | -| CreateTime | datetime NOT NULL | 创建时间 | -| UpdateWorkerId | int NOT NULL DEFAULT 0 | 更新人 | -| UpdateTime | datetime NOT NULL | 更新时间 | - -#### t_medical_visit_reminder_config 复诊提醒配置表 - -| 字段名 | 类型 | 说明 | -|--------|------|------| -| Id | int AUTO_INCREMENT PK | 主键 | -| PatientId | int NOT NULL | 患者 ID(唯一索引) | -| ReminderEnabled | tinyint NOT NULL DEFAULT 2 | 是否开启复诊提醒:1-开启,2-关闭 | -| Status | tinyint NOT NULL DEFAULT 1 | 数据状态:1-有效,100-删除 | -| CreateWorkerId | int DEFAULT NULL | 创建人 | -| CreateTime | datetime DEFAULT NULL | 创建时间 | -| UpdateWorkerId | int DEFAULT NULL | 更新人 | -| UpdateTime | datetime DEFAULT NULL | 更新时间 | - - -### G. 药物选项枚举 - -#### MedicationsUsed 本次就诊已使用的药物(多选) - -| 值 | 常量名 | 说明 | -|------|------|------| -| 1 | MED_USED_NO_HORMONE | 没有使用激素 | -| 2 | MED_USED_HORMONE | 激素 | -| 3 | MED_USED_IMMUNOSUPPRESSANT | 免疫抑制剂 | -| 4 | MED_USED_CD19 | 靶向CD19生物制剂(伊奈利珠单抗) | -| 5 | MED_USED_CD20 | 靶向CD20生物制剂(利妥昔单抗等) | -| 99 | MED_USED_OTHER | 其他 | - -#### ImmunosuppressantName 正在使用的免疫抑制剂名称(多选) - -| 值 | 常量名 | 说明 | -|------|------|------| -| 1 | IMMUNOSUPPRESSANT_MMF | 吗替麦考酚酯(骁悉、麦考芬) | -| 2 | IMMUNOSUPPRESSANT_AZA | 替唑嘌呤 | -| 3 | IMMUNOSUPPRESSANT_CYC | 环磷酰胺 | -| 4 | IMMUNOSUPPRESSANT_LEF | 来氟米特 | -| 5 | IMMUNOSUPPRESSANT_MTX | 甲氨蝶呤 | -| 6 | IMMUNOSUPPRESSANT_CYC_A | 环孢素 A | -| 7 | IMMUNOSUPPRESSANT_TAC | 他克莫司 | -| 8 | IMMUNOSUPPRESSANT_IGU | 艾拉莫德 | -| 99 | IMMUNOSUPPRESSANT_OTHER | 其他 | - -#### 复诊提醒配置枚举 - -| 值 | 常量名 | 说明 | -|------|------|------| -| 1 | REMINDER_ENABLED | 开启复诊提醒 | -| 2 | REMINDER_DISABLED | 关闭复诊提醒 | -| 7 | REMINDER_DAYS_BEFORE | 提前提醒天数(天) | diff --git a/api_doctor_msg_task.md b/api_doctor_msg_task.md deleted file mode 100644 index 607cff9..0000000 --- a/api_doctor_msg_task.md +++ /dev/null @@ -1,572 +0,0 @@ -# 医生消息任务接口文档 - -## 通用说明 - -### 响应格式 - -所有接口返回 JSON,严格遵循以下格式: - -```json -{ - "code": 0, - "message": "success", - "data": {} -} -``` - -- `code`:0 表示成功,非 0 表示失败 -- `message`:成功时为 "success",失败时为错误描述 -- `data`:业务数据,失败时为 null - -### 数据命名规则 - -`data` 中所有字段使用**小驼峰**命名法(如 `patientNum`、`sendTime`)。 - -### 登录校验 - -所有接口需通过请求头 `loginState` 或请求参数 `loginState` 传递登录态,未登录返回 code=403。本模块所有接口需医生身份登录。 - -### 错误码 - -| code | 说明 | -|------|------| -| 0 | 成功 | -| 1 | 参数缺失或业务异常 | -| 403 | 需要登录 | - ---- - -## 一、筛选患者人数 - -- **路由**:`?r=igg4/doctor/task/filter-patient-num` -- **请求方式**:GET -- **说明**:根据筛选条件获取符合条件的患者人数 - -### 请求参数 - -| 参数 | 类型 | 必填 | 说明 | -|------|------|------|------| -| SelectAll | int | 否 | 全选:0-否,1-是;为1时跳过其余筛选条件 | -| BindStartDate | string | 否 | 绑定日期开始,格式 YYYY-MM-DD | -| BindEndDate | string | 否 | 绑定日期结束,格式 YYYY-MM-DD | -| ConfirmedIgg4 | int | 否 | 确诊IGG4-RD:0-全部,1-是,2-否 | -| MedicationType | string | 否 | 正在使用的药物,逗号分隔选项值(如"2,3"),空或0表示全部。可选值见下面枚举表 | - -#### ConfirmedIgg4 枚举 - -| 值 | 说明 | -|----|------| -| 0 | 全部 | -| 1 | 是(确诊患者) | -| 2 | 否(非确诊患者,含未填写和疑似) | - -#### MedicationType 枚举 - -| 值 | 说明 | -|----|------| -| 0 | 全部 | -| 2 | 激素 | -| 3 | 免疫抑制剂 | -| 4 | 靶向CD19生物制剂(伊奈利珠单抗) | -| 5 | 靶向CD20生物制剂(利妥昔单抗等) | - -### 请求示例 - -``` -?r=igg4/doctor/task/filter-patient-num&SelectAll=0&BindStartDate=2026-01-01&BindEndDate=2026-06-30&ConfirmedIgg4=1&MedicationType=2,3 -``` - -### 响应示例 - -```json -{ - "code": 0, - "data": { - "PatientNum": "1" - } -} -``` - -### 业务逻辑说明 - -1. 基础条件:患者状态有效、属于当前医生、有绑定用户 -2. SelectAll=1 时跳过所有筛选直接返回 -3. 绑定时间范围:按 `InviteTime` 字段筛选,使用 BETWEEN 逻辑 -4. 确诊IGG4-RD:选"是"时匹配 `IsSuspectedPatient=2`,选"否"时排除 `IsSuspectedPatient=2`(保留未填写和疑似患者) -5. 药物筛选:关联 `t_patient_health_questionnaire_latest` 表(QuestionNo=4),使用 `FIND_IN_SET` 匹配多选答案,多个选项值之间为 OR 关系 - ---- - -## 二、获取任务模板 - -- **路由**:`?r=igg4/doctor/task/get-template` -- **请求方式**:GET -- **说明**:获取所有消息推送模板,按模板类型分组 - -### 请求参数 - -无 - -### 响应示例 - -```json -{ - "code": 0, - "data": [ - { - "templateType": 1, - "templateTypeText": "复诊提醒", - "templateList": [ - { - "id": 1, - "templateType": 1, - "interactMsgContent": "互动消息内容", - "templateIndex": "模板index", - "templateContent": "模板内容JSON" - } - ] - } - ] -} -``` - -#### TemplateType 枚举 - -| 值 | 说明 | -|----|------| -| 1 | 复诊提醒 | -| 2 | 激素风险提醒 | - -### 业务逻辑说明 - -1. 查询所有模板记录,按 `TemplateType` 升序、`Id` 升序排列 -2. 按 `TemplateType` 分组返回,每组包含类型编号、类型文本和模板列表 - ---- - -## 三、创建任务 - -- **路由**:`?r=igg4/doctor/task/create` -- **请求方式**:POST -- **说明**:创建消息推送任务,使用数据库事务 - -### 请求参数 - -| 参数 | 类型 | 必填 | 说明 | -|------|------|------|------| -| FilterCondition | object | 否 | 筛选条件JSON对象,结构同"筛选患者人数"接口参数 | -| PushTemplateId | int | 是 | 推送模板ID | -| IsSendNow | int | 是 | 是否立即发送:0-否,1-是 | -| SendTime | string | 条件必填 | 发送时间(IsSendNow=0时必填),格式 YYYY-MM-DD HH:mm:ss | -| PatientNum | int | 是 | 患者人数 | - -#### FilterCondition 结构 - -| 字段 | 类型 | 说明 | -|------|------|------| -| SelectAll | int | 全选:0-否,1-是 | -| BindStartDate | string | 绑定日期开始 | -| BindEndDate | string | 绑定日期结束 | -| ConfirmedIgg4 | int | 确诊IGG4-RD:0-全部,1-是,2-否 | -| MedicationType | string | 正在使用的药物,逗号分隔 | - -### 请求示例 - -```json -{ - "FilterCondition": { - "SelectAll": 0, - "BindStartDate": "2026-01-01", - "BindEndDate": "2026-06-30", - "ConfirmedIgg4": 1, - "MedicationType": "2" - }, - "PushTemplateId": 2, - "IsSendNow": 1, - "SendTime": "", - "PatientNum": 25 -} -``` - -### 响应示例(成功) - -```json -{ - "code": 0, - "data": "创建成功" -} -``` - -### 响应示例(失败) - -```json -{ - "code": 1, - "data": "每个医生每天只能创建一次任务" -} -``` - -### 业务逻辑说明 - -1. 校验医生存在(逻辑删除标记 `DeleteTime` 为空) -2. 校验模板存在 -3. 每个医生每天只能创建一次任务(当天已有状态为待发送/发送中/暂停/已发送/已停止的任务则不可再创建) -4. IsSendNow=1 时,SendTime 自动设为当前时间 -5. 自动生成 IdNumber(`YmdHis` + 3位随机数) -6. IsDoctorCreate=1(医生端创建),CreateWorkerId 为空 -7. 生成模板消息内容(调用 `transformTemplateContent` 转化模板变量) -8. 保存任务后,自动调用 `generateUserRecord` 生成用户发送记录 -9. 更新任务的 ActualPatientNum 和 IsInsertUser 字段 - ---- - -## 四、获取任务列表 - -- **路由**:`?r=igg4/doctor/task/list` -- **请求方式**:GET -- **说明**:获取当前医生的任务列表,支持分页,按创建时间降序排列 - -### 请求参数 - -| 参数 | 类型 | 必填 | 说明 | -|------|------|------|------| -| count | int | 否 | 每页条数,默认10 | -| page | int | 否 | 页码,从1开始 | - -### 请求示例 - -``` -?r=igg4/doctor/task/list&count=10&page=1 -``` - -### 响应示例 - -```json -{ - "code": 0, - "data": { - "list": [ - { - "Id": 1, - "IdNumber": "20260702143025123", - "DoctorId": 5, - "FilterCondition": { - "SelectAll": 0, - "BindStartDate": "2026-01-01", - "BindEndDate": "2026-06-30", - "ConfirmedIgg4": 1, - "MedicationType": "2" - }, - "TemplateType": 1, - "CreateTime": "2026-07-02 14:30:25", - "IsSendNow": 1, - "SendTime": "2026-07-02 14:30:25", - "Status": 4, - "PatientNum": 25, - "ActualPatientNum": 23 - } - ], - "pages": 3, - "count": 28, - "page": 1 - } -} -``` - -### 响应字段说明 -| 字段 | 类型 | 说明 | -|------|------|------| -| Id | int | 任务ID | -| IdNumber | string | 任务编号 | -| DoctorId | int | 医生ID | -| FilterCondition | object | 筛选条件JSON对象 | -| TemplateType | int | 模板类型 | -| CreateTime | string | 创建时间 | -| IsSendNow | int | 是否立即发送:0-否,1-是 | -| SendTime | string | 发送时间 | -| Status | int | 任务状态 | -| PatientNum | int | 患者人数 | -| ActualPatientNum | int | 实际发送患者人数 | - -#### FilterCondition 结构说明 - -| 字段 | 类型 | 说明 | -|------|------|------| -| SelectAll | int | 全选:0-否,1-是 | -| BindStartDate | string | 绑定日期开始 | -| BindEndDate | string | 绑定日期结束 | -| ConfirmedIgg4 | int | 确诊IGG4-RD:0-全部,1-是,2-否 | -| MedicationType | string | 正在使用的药物,逗号分隔 | - -#### TemplateType 枚举 - -| 值 | 说明 | -|----|------| -| 1 | 复诊提醒 | -| 2 | 激素风险提醒 | - -#### Status 枚举 - -| 值 | 说明 | -|----|------| -| 1 | 待发送 | -| 2 | 发送中 | -| 3 | 暂停 | -| 4 | 已发送 | -| 5 | 已停止 | -| 6 | 已取消 | - -### 业务逻辑说明 - -1. 仅查询 `DeleteTime` 为空的任务 -2. FilterCondition 字段从 JSON 字符串解码为数组返回 -3. 返回字段包含:Id, IdNumber, DoctorId, FilterCondition, TemplateType, CreateTime, IsSendNow, SendTime, Status, PatientNum, ActualPatientNum -4. 分页参数:pages 为总页数,count 为总记录数,page 为当前页码(从1开始) - ---- - -## 五、获取任务详情 - -- **路由**:`?r=igg4/doctor/task/detail` -- **请求方式**:GET -- **说明**:获取单个任务的详细信息,包含发送统计 - -### 请求参数 - -| 参数 | 类型 | 必填 | 说明 | -|------|------|------|------| -| TaskId | int | 是 | 任务ID | - -### 请求示例 - -``` -?r=igg4/doctor/task/detail&TaskId=1 -``` - -### 响应示例 - -```json -{ - "code": 0, - "data": { - "Id": 1, - "IdNumber": "20260702143025123", - "DoctorId": 5, - "FilterCondition": { - "SelectAll": 0, - "BindStartDate": "2026-01-01", - "BindEndDate": "2026-06-30", - "ConfirmedIgg4": 1, - "MedicationType": "2" - }, - "TemplateType": 1, - "PushTemplateId": 2, - "TemplateMsgContent": "{...}", - "InteractMsgContent": "互动消息内容", - "IsSendNow": 1, - "SendTime": "2026-07-02 14:30:25", - "PatientNum": 25, - "ActualPatientNum": 23, - "IsInsertUser": 1, - "Status": 4, - "IsDoctorCreate": 1, - "WorkerId": "", - "DeleteTime": null, - "CreateTime": "2026-07-02 14:30:25", - "UpdateTime": "2026-07-02 14:30:30", - "SendDetail": { - "TaskId": 1, - "SumSendCount": 23, - "SendCount": 20, - "UnSendCount": 3, - "InteractSendSuccessCount": 18, - "InteractSendFailCount": 2, - "PushSendSuccessCount": 16, - "PushSendFailCount": 4, - "PushClickCount": 10, - "InteractReadCount": 15, - "InteractUnReadCount": 5, - "PushUnClickCount": 10 - } - } -} -``` - -#### SendDetail 字段说明 - -| 字段 | 说明 | -|------|------| -| sumSendCount | 总人数(去重) | -| sendCount | 已发送人数 | -| unSendCount | 未发送人数 | -| InteractSendSuccessCount | 互动消息发送成功人数 | -| InteractSendFailCount | 互动消息发送失败人数(派生值:SendCount - InteractSendSuccessCount) | -| PushSendSuccessCount | Push消息发送成功人数 | -| PushSendFailCount | Push消息发送失败人数 | -| PushClickCount | Push消息点击人数 | -| InteractReadCount | 互动消息已读人数 | -| InteractUnReadCount | 互动消息未读人数(派生值:sendCount - InteractReadCount) | -| PushUnClickCount | Push消息未点击人数(派生值:sendCount - PushClickCount) | - -### 业务逻辑说明 - -1. 校验任务存在且 `DeleteTime` 为空,否则抛出"任务不存在" -2. FilterCondition 从 JSON 字符串解码为数组 -3. 根据 PushTemplateId 查询模板,补充 TemplateType 和 InteractMsgContent 字段 -4. 通过 `TZdDoctorMsgTaskUserMessage::taskDetail` 获取发送统计数据,包含派生的失败/未读/未点击人数 - ---- - -## 六、删除任务 - -- **路由**:`?r=igg4/doctor/task/delete` -- **请求方式**:POST -- **说明**:逻辑删除已取消的任务,使用数据库事务 - -### 请求参数 - -| 参数 | 类型 | 必填 | 说明 | -|------|------|------|------| -| TaskId | int | 是 | 任务ID | - -### 请求示例 - -```json -{ - "TaskId": 1 -} -``` - -### 响应示例(成功) - -```json -{ - "code": 0, - "data": "删除成功" -} -``` - -### 响应示例(失败) - -```json -{ - "code": 1, - "msg": "当前任务状态不能删除", -} -``` - -### 业务逻辑说明 - -1. 校验任务存在、属于当前医生且 `DeleteTime` 为空,否则抛出"任务不存在" -2. 只有状态为"已取消"(Status=6)的任务才能删除 -3. 设置 `DeleteTime` 为当前时间(软删除) - ---- - -## 七、停止任务 - -- **路由**:`?r=igg4/doctor/task/stop` -- **请求方式**:POST -- **说明**:停止正在发送中或暂停的任务,使用数据库事务 - -### 请求参数 - -| 参数 | 类型 | 必填 | 说明 | -|------|------|------|------| -| TaskId | int | 是 | 任务ID | - -### 请求示例 - -```json -{ - "TaskId": 1 -} -``` - -### 响应示例(成功) - -```json -{ - "code": 0, - "data": "停止成功" -} -``` - -### 响应示例(失败) - -```json -{ - "code": 1, - "msg": "当前任务状态不能停止", -} -``` - -### 业务逻辑说明 - -1. 校验任务存在、属于当前医生且 `DeleteTime` 为空,否则抛出"任务不存在" -2. 只有状态为"发送中"(Status=2)或"暂停"(Status=3)的任务才能停止 -3. 将状态更新为"已停止"(Status=5) - ---- - -## 八、取消任务 - -- **路由**:`?r=igg4/doctor/task/cancel` -- **请求方式**:POST -- **说明**:取消待发送的任务,使用数据库事务 - -### 请求参数 - -| 参数 | 类型 | 必填 | 说明 | -|------|------|------|------| -| TaskId | int | 是 | 任务ID | - -### 请求示例 - -```json -{ - "TaskId": 1 -} -``` - -### 响应示例(成功) - -```json -{ - "code": 0, - "data": "取消成功" -} -``` - -### 响应示例(失败) - -```json -{ - "code": 1, - "msg": "当前任务状态不能取消", -} -``` - -### 业务逻辑说明 - -1. 校验任务存在、属于当前医生且 `DeleteTime` 为空,否则抛出"任务不存在" -2. 只有状态为"待发送"(Status=1)的任务才能取消 -3. 将状态更新为"已取消"(Status=6) - ---- - -## 附录 - -### 附录A:任务状态流转 - -``` -待发送(1) ──发送调度──> 发送中(2) ──发送完成──> 已发送(4) - │ │ ↑ - │取消 │ │暂停 - ↓ ↓ │ -已取消(6) <────────── 暂停(3)─┘ - │ │ - │删除(软删) │停止 - ↓ ↓ -(DeleteTime非空) 已停止(5) -``` diff --git a/doc/api.md b/doc/api.md new file mode 100644 index 0000000..6d52f27 --- /dev/null +++ b/doc/api.md @@ -0,0 +1,1419 @@ +# 就诊记录接口文档 + +## 通用说明 + +### 响应格式 + +所有接口返回 JSON,严格遵循以下格式: + +```json +{ + "code": 0, + "message": "success", + "data": {} +} +``` + +- `code`:0 表示成功,非 0 表示失败 +- `message`:成功时为 "success",失败时为错误描述 +- `data`:业务数据,失败时为 null + +### 数据命名规则 + +`data` 中所有字段使用**小驼峰**命名法(如 `visitDate`、`igG4Value`)。 + +### 登录校验 + +所有接口需通过请求头 `loginState` 或请求参数 `loginState` 传递登录态,未登录返回 code=403。 + +### 错误码 + +| code | 说明 | +|------|------| +| 0 | 成功 | +| 1 | 参数缺失 | +| 2 | 记录不存在 | +| 3 | 操作失败 | +| 403 | 需要登录 | + +--- + +## 一、患者端接口 + +模块路由前缀:`igg4/medical-visit` + +--- + +### 1.1 保存草稿 + +- **路由**:`?r=igg4/medical-visit/save-draft` +- **请求方式**:POST +- **说明**:创建或更新草稿记录。传入 `id` 时更新已有草稿,不传时新建草稿。图片列表支持新增、更新、逻辑删除的 diff 处理。使用数据库事务。 + +#### 请求参数 + +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| id | int | 否 | 已有草稿 ID,更新时必传 | +| visitDate | string | 是 | 本次就诊时间,格式 YYYY-MM-DD | +| nextVisitDate | string | 否 | 下次就诊时间,格式 YYYY-MM-DD | +| oralHormoneDosage | float | 否 | 口服激素每日用量(片) | +| manualIgG4Value | float | 否 | 患者手动录入的IgG4数值(冗余字段,单位mg/dL) | +| medicationsUsed | array | 否 | 本次就诊已使用的药物(多选),值为常量ID数组,如 [1,2,3],见附录G | +| immunosuppressantName | array | 否 | 正在使用的免疫抑制剂名称(多选),值为常量ID数组,如 [1,5],见附录G | +| medicationsUsedOtherText | string | 否 | 本次就诊已使用药物选择"其他"(99)时的补充文本 | +| immunosuppressantNameOtherText | string | 否 | 正在使用的免疫抑制剂名称选择"其他"(99)时的补充文本 | +| images | array | 否 | 图片列表 | + +#### images 每项参数 + +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| imageUrl | string | 是 | 图片 URL | +| imageType | string | 是 | 图片类型标识,见枚举表 | + +#### imageType 枚举 + +| 值 | 说明 | +|------|------| +| outpatientRecord | 门诊病历及处方 | +| labReport | 检验报告 | +| imagingExam | 影像学检查 | +| pathology | 病理诊断及活检 | +| immuneFunction | 外周血免疫功能评估 | + +#### 请求示例 + +```json +{ + "id": 0, + "visitDate": "2026-06-29", + "nextVisitDate": "2026-09-29", + "oralHormoneDosage": 4, + "manualIgG4Value": 135.0, + "medicationsUsed": [2, 3], + "immunosuppressantName": [1, 7], + "medicationsUsedOtherText": null, + "immunosuppressantNameOtherText": null, + "images": [ + { + "imageUrl": "https://oss.example.com/img001.jpg", + "imageType": "labReport" + }, + { + "imageUrl": "https://oss.example.com/img002.jpg", + "imageType": "outpatientRecord" + } + ] +} +``` + +#### 响应示例 + +```json +{ + "code": 0, + "message": "success", + "data": { + "id": 1, + "recordStatus": 1 + } +} +``` + +#### 业务逻辑说明 + +1. 若传入 `id`,校验记录存在、属于当前患者、为草稿状态(recordStatus=1),否则报错 +2. 若未传 `id`,新建主记录,设置 recordStatus=1(草稿)、status=1(有效) +3. 保存 CreateWorkerId/CreateTime/UpdateWorkerId/UpdateTime +4. 图片 diff 处理:通过 RecordId + ImageUrl 匹配已有图片记录 + - 已存在 → 更新 ImageType,重置 OcrStatus 为待解析(0),清空 OcrText/OcrParsedData/指标字段 + - 不存在 → 插入新图片记录(OcrStatus 默认为 0) + - 已有但本次未传入 → 逻辑删除(status=100) +5. 最终将所有检验报告图片的指标值和门诊病历图片的病历文本聚合到主表(后出现的值覆盖先出现的值) +6. `manualIgG4Value` 参数写入主表 `ManualIgG4Value` 字段,作为冗余存储,不影响 OCR 解析产生的主数据 `IgG4Value` + +--- + +### 1.1.0 保存图片记录 + +- **路由**:`?r=igg4/medical-visit/save-image` +- **请求方式**:POST +- **说明**:仅保存单张图片记录到就诊记录图片表,不更新主记录字段,不触发指标聚合。前端需先创建草稿获取 RecordId 后再调用此接口。使用数据库事务。 + +#### 请求参数 + +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| recordId | int | 是 | 已有草稿记录 ID | +| imageUrl | string | 是 | 图片 URL | +| imageType | string | 是 | 图片类型标识,见枚举表 | + +#### imageType 枚举 + +同 [1.1 images.imageType](#imagetype-枚举) + +#### 请求示例 + +```json +{ + "recordId": 1, + "imageUrl": "https://oss.example.com/img001.jpg", + "imageType": "labReport" +} +``` + +#### 响应示例 + +```json +{ + "code": 0, + "message": "success", + "data": { + "imageId": 102, + "recordId": 1, + "imageUrl": "https://oss.example.com/img001.jpg", + "imageType": "labReport", + "ocrStatus": 0 + } +} +``` + +#### 业务逻辑说明 + +1. 校验 recordId 对应的记录存在且属于当前患者,否则报错"就诊记录不存在"或"就诊记录不属于当前患者" +2. 校验记录状态为草稿(recordStatus=1),否则报错"仅草稿状态的记录可添加图片" +3. 将 imageType 字符串转为数据库整型值,无效则报错"无效的图片类型" +4. 根据 RecordId + ImageUrl 判断图片是否已存在: + - 已存在:更新 ImageType,重置 OcrStatus 为待解析(0),清空 OcrText、OcrParsedData 及对应指标/文本字段 + - 不存在:新建图片记录(含 CreateWorkerId/CreateTime),OcrStatus 默认为待解析(0) +5. **不触发主表指标聚合**(与 saveDraft 不同),聚合在调用 saveDraft 或 submit 时发生 +6. 小程序端仅存储原始图片,OCR 解析由后台管理员涂抹图片后触发,返回 ocrStatus 表示当前解析状态 + +--- + +### 1.1.1 删除单个图片 + +- **路由**:`?r=igg4/medical-visit/delete-image` +- **请求方式**:POST +- **说明**:逻辑删除指定图片记录,设置 Status=100,记录操作人和操作时间。使用数据库事务。 + +#### 请求参数 + +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| imageId | int | 是 | 图片记录 ID | + +#### 请求示例 + +```json +{ + "imageId": 102 +} +``` + +#### 响应示例 + +```json +{ + "code": 0, + "message": "success", + "data": true +} +``` + +#### 业务逻辑说明 + +1. 校验 imageId 必传,否则报错"图片记录ID不能为空" +2. 校验管理员已登录,获取当前操作人 workerId +3. 校验图片记录存在且有效(Status=1),否则报错"图片记录不存在" +4. 逻辑删除:设置 Status=100(已删除),记录 UpdateWorkerId/UpdateTime +5. 返回 true + +--- + +### 1.2 提交就诊记录 + +- **路由**:`?r=igg4/medical-visit/submit` +- **请求方式**:POST +- **说明**:将草稿状态的记录提交,提交后不可再编辑。使用数据库事务。 + +#### 请求参数 + +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| id | int | 是 | 草稿记录 ID | + +#### 请求示例 + +```json +{ + "id": 1 +} +``` + +#### 响应示例 + +```json +{ + "code": 0, + "message": "success", + "data": true +} +``` + +#### 业务逻辑说明 + +1. 校验记录存在、属于当前患者 +2. 校验记录状态为草稿(recordStatus=1),否则报错"仅草稿状态的记录可提交" +3. 更新 recordStatus=2(已提交),记录 UpdateWorkerId/UpdateTime + +--- + +### 1.3 获取就诊记录详情 + +- **路由**:`?r=igg4/medical-visit/detail` +- **请求方式**:GET +- **说明**:获取单条就诊记录详情,包含主记录所有指标数据和按类型分组的图片列表。 + +#### 请求参数 + +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| id | int | 是 | 就诊记录 ID | + +#### 响应示例 + +```json +{ + "code": 0, + "message": "success", + "data": { + "id": 1, + "visitDate": "2026-06-29", + "nextVisitDate": "2026-09-29", + "recordStatus": 2, + "igG4Value": 135.0, + "manualIgG4Value": 135.0, + "displayIgG4Value": 135.0, + "totalIgGValue": 1200.0, + "igEValue": 50.0, + "eosCount": 0.3, + "esrValue": 20.0, + "crpValue": 5.0, + "oralHormoneDosage": 4.0, + "medicationsUsed": [2, 3], + "immunosuppressantName": [1, 7], + "medicationsUsedOtherText": null, + "immunosuppressantNameOtherText": null, + "medicalRecordTime": "2026-06-29 09:30:00", + "prescriptionTime": "2026-06-29 10:15:00", + "reportTime": "2026-06-28 14:20:00", + "chiefComplaint": "反复腹痛3月", + "medicalHistory": "现病史:患者3月前无明显诱因出现腹痛...", + "diagnosis": "IgG4相关性疾病", + "treatmentPlan": "激素治疗,定期复查", + "prescription": "甲泼尼龙片 4mg 每日1次 口服 30片", + "clinicalDiagnosis": "IgG4相关性疾病", + "images": { + "outpatientRecord": [ + { + "id": 101, + "imageUrl": "https://...", + "maskedImageUrl": "https://...masked.jpg", + "ocrStatus": 2, + "ocrParsedData": "门诊病历文本...", + "medicalRecordTime": "2026-06-29 09:30:00", + "prescriptionTime": "2026-06-29 10:15:00", + "reportTime": null + } + ], + "labReport": [ + { + "id": 102, + "imageUrl": "https://...", + "maskedImageUrl": "https://...masked.jpg", + "ocrStatus": 2, + "ocrParsedData": { + "reportTime": "2026-06-28", + "indicators": { + "igG4": {"value": 135.0, "unit": "mg/dL"}, + "totalIgG": {"value": 1200.0, "unit": "mg/dL"}, + "igE": {"value": 50.0, "unit": "IU/mL"}, + "eos": {"value": 0.3, "unit": "10^9/L"}, + "esr": {"value": 20.0, "unit": "mm/h"}, + "crp": {"value": 5.0, "unit": "mg/L"} + } + }, + "medicalRecordTime": null, + "prescriptionTime": null, + "reportTime": "2026-06-28 14:20:00" + } + ], + "imagingExam": [ + { + "id": 103, + "imageUrl": "https://...", + "maskedImageUrl": null, + "ocrStatus": 0, + "ocrParsedData": null + } + ], + "pathology": [], + "immuneFunction": [] + } + } +} +``` + +#### images 字段说明 + +- 固定返回 5 种图片类型的分组,无数据时为空数组 +- 每张图片包含 `id`、`imageUrl`、`maskedImageUrl`、`ocrStatus`、`ocrParsedData`、`medicalRecordTime`、`prescriptionTime`、`reportTime` +- `maskedImageUrl`:涂抹后图片 URL,后台管理员未涂抹时为 null +- `ocrStatus`:OCR 解析状态,0-待解析,1-解析中,2-解析完成,3-解析失败 +- `ocrParsedData`:检验报告类型为包含 `reportTime` 和 `indicators` 的结构化 JSON 对象,门诊病历类型为包含 `medicalRecordTime` 和 `prescriptionTime` 的结构化 JSON 对象,其他类型为拼接文本字符串,无 OCR 数据时为 null +- `medicalRecordTime`:病历时间(图片类型=门诊病历且识别为门诊病历时有值),格式 YYYY-MM-DD 或 YYYY-MM-DD HH:mm:ss +- `prescriptionTime`:处方时间(图片类型=门诊病历且识别为处方时有值),格式 YYYY-MM-DD 或 YYYY-MM-DD HH:mm:ss +- `reportTime`:检查报告时间(图片类型=检验报告时有值),格式 YYYY-MM-DD 或 YYYY-MM-DD HH:mm:ss + +#### 主记录字段说明 + +- `displayIgG4Value`:展示用 IgG4 数值,优先取 manualIgG4Value,为空则取 igG4Value;均为空时为 null +- `medicalRecordTime`:病历时间(从门诊病历图片聚合),格式 YYYY-MM-DD 或 YYYY-MM-DD HH:mm:ss,无数据时为 null +- `prescriptionTime`:处方时间(从处方图片聚合),格式 YYYY-MM-DD 或 YYYY-MM-DD HH:mm:ss,无数据时为 null +- `reportTime`:检查报告时间(从检验报告图片聚合),格式 YYYY-MM-DD 或 YYYY-MM-DD HH:mm:ss,无数据时为 null + +--- + +### 1.4 就诊记录列表 + +- **路由**:`?r=igg4/medical-visit/list` +- **请求方式**:GET +- **说明**:获取当前患者的就诊记录列表,支持分页和年份/次数筛选。 + +#### 请求参数 + +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| page | int | 否 | 页码,默认 1 | +| pageSize | int | 否 | 每页条数,默认 10 | +| year | int | 否 | 按就诊年份筛选(快捷方式,等同于yearStart=year&yearEnd=year) | +| yearStart | int | 否 | 按就诊年份范围筛选-起始年份,优先级高于year | +| yearEnd | int | 否 | 按就诊年份范围筛选-结束年份,优先级高于year | + +#### 响应示例 + +```json +{ + "code": 0, + "message": "success", + "data": { + "page": 1, + "pages": 5, + "totalCount": 50, + "list": [ + { + "id": 1, + "visitDate": "2026-06-29", + "nextVisitDate": "2026-09-29", + "recordStatus": 2, + "igG4Value": 135.0, + "manualIgG4Value": 135.0, + "displayIgG4Value": 135.0, + "medicationsUsed": [2, 3], + "immunosuppressantName": [1, 7], + "medicationsUsedOtherText": null, + "immunosuppressantNameOtherText": null, + "lastIgG4Value": 120.0, + "change": 15.0, + "medicalRecordTime": "2026-06-29 09:30:00", + "prescriptionTime": "2026-06-29 10:15:00", + "reportTime": "2026-06-28 14:20:00" + } + ] + } +} +``` + +#### 说明 + +- 列表按 VisitDate 降序排列 +- 同时传入 `year` 和 `count` 时,先按年份筛选再取最近 N 条 +- `lastIgG4Value`:上一次就诊的 IgG4 值,float 类型;无上一次记录时为 null +- `change`:本次与上一次 IgG4 值的差值(本次 - 上次),float 类型;任一值为 null 时为 null +- `manualIgG4Value`:患者手动录入的 IgG4 数值(冗余字段),未录入时为 null +- `displayIgG4Value`:展示用 IgG4 数值,优先取 manualIgG4Value,为空则取 igG4Value;均为空时为 null +- `medicalRecordTime`:病历时间(从门诊病历图片聚合),格式 YYYY-MM-DD 或 YYYY-MM-DD HH:mm:ss,无数据时为 null +- `prescriptionTime`:处方时间(从处方图片聚合),格式 YYYY-MM-DD 或 YYYY-MM-DD HH:mm:ss,无数据时为 null +- `reportTime`:检查报告时间(从检验报告图片聚合),格式 YYYY-MM-DD 或 YYYY-MM-DD HH:mm:ss,无数据时为 null +- `medicationsUsed`:本次就诊已使用的药物(多选),值为常量ID数组,见附录G;未选择时为 null +- `immunosuppressantName`:正在使用的免疫抑制剂名称(多选),值为常量ID数组,见附录G;未选择时为 null +- `medicationsUsedOtherText`:本次就诊已使用药物选择"其他"(99)时的补充文本,未选择"其他"时为 null +- `immunosuppressantNameOtherText`:正在使用的免疫抑制剂名称选择"其他"(99)时的补充文本,未选择"其他"时为 null + +- 年份筛选优先级:传入 `yearStart`+`yearEnd` 时优先按范围筛选,忽略 `year` 参数;仅传 `yearStart` 取 >= 起始年份;仅传 `yearEnd` 取 <= 结束年份;仅传 `year` 则按单年份筛选 + +--- + +### 1.5 删除就诊记录 + +- **路由**:`?r=igg4/medical-visit/delete` +- **请求方式**:POST +- **说明**:逻辑删除就诊记录及其所有图片。使用数据库事务。 + +#### 请求参数 + +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| id | int | 是 | 就诊记录 ID | + +#### 响应示例 + +```json +{ + "code": 0, + "message": "success", + "data": true +} +``` + +#### 业务逻辑说明 + +1. 校验记录存在、属于当前患者 +2. 将主记录 status 设为 100(删除),记录 UpdateWorkerId/UpdateTime +3. 将该记录下所有图片 status 设为 100(删除) + +--- + +### 1.6 图片字段历史列表 + +- **路由**:`?r=igg4/medical-visit/image-history` +- **请求方式**:GET +- **说明**:查询指定图片类型的历史列表,返回每次就诊中该类型图片的 URL,按就诊日期降序排列。仅返回已提交的记录。 + +#### 请求参数 + +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| imageField | string | 是 | 图片类型标识 | +| year | int | 否 | 按就诊年份筛选(快捷方式,等同于yearStart=year&yearEnd=year) | +| yearStart | int | 否 | 按就诊年份范围筛选-起始年份,优先级高于year | +| yearEnd | int | 否 | 按就诊年份范围筛选-结束年份,优先级高于year | +| page | int | 否 | 页码,默认 1 | +| pageSize | int | 否 | 每页条数,默认 10 | + +#### imageField 枚举 + +| 值 | 说明 | +|------|------| +| outpatientRecord | 门诊病历及处方 | +| labReport | 检验报告 | +| imagingExam | 影像学检查 | +| pathology | 病理诊断及活检 | +| immuneFunction | 外周血免疫功能评估 | + +#### 响应示例 + +```json +{ + "code": 0, + "message": "success", + "data": { + "page": 1, + "pages": 5, + "totalCount": 50, + "list": [ + { + "visitDate": "2026-06-29", + "imageUrls": [ + "https://picsissiok-10049618.cos.ap-shanghai.myqcloud.com/0e3a32a7612090359a9ca36117d0f2db_17835667161658.jpg" + ], + "ocrStatus": 2 + }, + { + "visitDate": "2026-03-15", + "imageUrls": [ + "https://...", + ], + "ocrStatus": 0 + } + ] + } +} +``` + +- 分页按就诊记录维度,每页包含对应就诊记录中该类型的所有图片 URL 数组 + +-> imageUrls :图片 URL 数组 + +--- + +### 1.7 指标字段历史列表 + +- **路由**:`?r=igg4/medical-visit/indicator-history` +- **请求方式**:GET +- **说明**:查询指定指标字段的历史数据列表,返回每次就诊中该指标的值,按就诊日期降序排列。仅返回已提交的记录。 + +#### 请求参数 + +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| indicatorField | string | 是 | 指标字段标识 | +| year | int | 否 | 按就诊年份筛选(快捷方式,等同于yearStart=year&yearEnd=year) | +| yearStart | int | 否 | 按就诊年份范围筛选-起始年份,优先级高于year | +| yearEnd | int | 否 | 按就诊年份范围筛选-结束年份,优先级高于year | + +#### indicatorField 枚举 + +| 值 | 说明 | 单位 | +|------|------|------| +| igG4 | IgG4(免疫球蛋白G4亚类) | mg/dL | +| totalIgG | 总IgG(免疫球蛋白G) | mg/dL | +| igE | IgE(免疫球蛋白E) | IU/mL | +| eos | EOS#(嗜酸细胞绝对计数) | 10^9/L | +| esr | ESR(红细胞沉降率/血沉) | mm/h | +| crp | CRP(C-反应蛋白) | mg/L | + +#### 响应示例 + +```json +{ + "code": 0, + "message": "success", + "data": { + "unit": "mg/dL", + "list": [ + { + "visitDate": "2026-06-29", + "value": 135.0 + }, + { + "visitDate": "2026-03-15", + "value": 260.0 + } + ] + } +} +``` + +--- + +### 1.8 OCR 图片解析 + +- **路由**:`?r=igg4/medical-visit/ocr-parse` +- **请求方式**:POST +- **说明**:对图片进行阿里云 OCR 文字识别。检验报告类型自动提取指标数值并做单位换算,其他类型仅返回拼接文本。 + +#### 请求参数 + +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| imageUrl | string | 是 | 图片 URL(需为阿里云上海 OSS 地址) | +| imageType | string | 是 | 图片类型标识 | + +#### imageType 枚举 + +同 [1.1 images.imageType](#imagetype-枚举) + +#### 响应示例 — 检验报告类型(imageType=labReport) + +```json +{ + "code": 0, + "message": "success", + "data": { + "ocrText": "IgG4 1.35 g/L\n总IgG 12.0 g/L\nIgE 50 IU/mL\nESR 20 mm/h\nCRP 5 mg/L", + "ocrParsedData": { + "reportTime": "2026-06-28 14:20:00", + "indicators": { + "igG4": {"value": 135.0, "unit": "mg/dL"}, + "totalIgG": {"value": 1200.0, "unit": "mg/dL"}, + "igE": {"value": 50.0, "unit": "IU/mL"}, + "eos": {"value": null, "unit": "10^9/L"}, + "esr": {"value": 20.0, "unit": "mm/h"}, + "crp": {"value": 5.0, "unit": "mg/L"} + } + } + } +} +``` + +#### 响应示例 — 门诊病历类型(imageType=outpatientRecord) + +```json +{ + "code": 0, + "message": "success", + "data": { + "ocrText": "患者XXX,男,45岁\n主诉:反复腹痛3月\n现病史:患者3月前无明显诱因出现腹痛\n诊断:IgG4相关性疾病\n处理意见:激素治疗,定期复查", + "ocrParsedData": { + "chiefComplaint": "反复腹痛3月", + "medicalHistory": "患者3月前无明显诱因出现腹痛", + "diagnosis": "IgG4相关性疾病", + "treatmentPlan": "激素治疗,定期复查", + "prescription": "甲泼尼龙片 4mg 每日1次 口服 30片", + "clinicalDiagnosis": "IgG4相关性疾病" + } + } +} +``` + +#### 响应示例 — 其他类型(如 imageType=imagingExam) + +```json +{ + "code": 0, + "message": "success", + "data": { + "ocrText": "影像学检查报告文本...", + "ocrParsedData": "影像学检查报告文本..." + } +} +``` + +#### OCR 指标识别规则 + +| 指标 | 关键词匹配 | 单位换算 | +|------|-----------|---------| +| IgG4 | `IgG4`、`免疫球蛋白G4`、`免疫球蛋白G4亚类` | 若为 g/L 则 ×100 → mg/dL | +| 总IgG | `IgG`(独立,非IgG1-5/IgG4/IgE)、`免疫球蛋白G` | 若为 g/L 则 ×100 → mg/dL | +| IgE | `IgE`、`免疫球蛋白E` | 不换算,保持 IU/mL | +| EOS# | `EOS#`、`嗜酸细胞绝对计数`、`嗜酸性粒细胞绝对值` | 不换算,保持 10^9/L | +| ESR | `ESR`、`红细胞沉降率`、`血沉` | 不换算,保持 mm/h | +| CRP | `CRP`、`C-反应蛋白`、`C反应蛋白` | 不换算,保持 mg/L | + +#### 门诊病历 OCR 识别规则 + +| 字段 | 关键词匹配 | +|------|-----------| +| 主诉 | `主诉` | +| 病史 | `现病史`、`既往史`、`病史` | +| 诊断 | `诊断`、`Imp`、`印象` | +| 处理意见 | `处理意见`、`医嘱`、`处理`、`治疗方案` | + +--- + +### 1.9 保存复诊提醒配置 + +- **路由**:`?r=igg4/medical-visit/save-reminder-config` +- **请求方式**:POST +- **说明**:患者配置是否开启复诊提醒。开启后,定时任务将在复诊日期前7天发送微信Push通知。使用数据库事务。 + +#### 请求参数 + +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| reminderEnabled | int | 是 | 是否开启复诊提醒:1-开启,2-关闭 | + +#### 请求示例 + +```json +{ + "reminderEnabled": 1 +} +``` + +#### 响应示例 + +```json +{ + "code": 0, + "message": "success", + "data": true +} +``` + +#### 业务逻辑说明 + +1. 校验 reminderEnabled 参数必填,值只能为1(开启)或2(关闭),否则报错"reminderEnabled参数无效" +2. 查询当前患者是否已有配置记录 +3. 已有配置:更新 ReminderEnabled,记录 UpdateWorkerId/UpdateTime +4. 无配置:新建配置记录,设置 PatientId、ReminderEnabled、Status=1,记录 CreateWorkerId/CreateTime/UpdateWorkerId/UpdateTime +5. 每个患者只保留一条有效配置记录(通过 PatientId 唯一约束保证) + +--- + +### 1.10 获取复诊提醒配置 + +- **路由**:`?r=igg4/medical-visit/get-reminder-config` +- **请求方式**:GET +- **说明**:获取当前患者的复诊提醒配置。未配置过时返回默认值(关闭)。 + +#### 请求参数 + +无 + +#### 响应示例 + +```json +{ + "code": 0, + "message": "success", + "data": { + "reminderEnabled": 2 + } +} +``` + +#### 说明 + +- `reminderEnabled`:1-开启,2-关闭。患者未配置过时默认返回2(关闭) +- 配置数据来源于 `t_medical_visit_reminder_config` 表 + +--- + +### 1.11 获取最近就诊记录 + +- **路由**:`?r=igg4/medical-visit/get-latest-record` +- **请求方式**:GET +- **说明**:获取当前患者按就诊日期最近的一条就诊记录详情,包含草稿和已提交记录。无记录时 data 为 null。 + +#### 请求参数 + +无 + +#### 响应示例 — 有记录时 + +同 [1.3 获取就诊记录详情](#13-获取就诊记录详情) 的 data 格式。 + +#### 响应示例 — 无记录时 + +```json +{ + "code": 0, + "message": "success", + "data": null +} +``` + +#### 说明 + +- 返回当前患者按就诊日期(VisitDate)降序最近的一条就诊记录详情 +- 不限制记录状态,草稿(recordStatus=1)和已提交(recordStatus=2)均可能返回 +- 同一天多条记录时,返回 ID 最大的那条 +- 返回格式与详情接口完全一致,包含图片分组等完整信息 + +--- + +## 二、医生端接口 + +模块路由前缀:`igg4/doctor/medical-visit` + +医生端所有接口均为**只读**,且只能查看**已提交**(recordStatus=2)的记录,草稿对医生不可见。所有接口需额外传入 `patientId` 参数指定查看的患者。 + +--- + +### 2.1 就诊记录列表 + +- **路由**:`?r=igg4/doctor/medical-visit/list` +- **请求方式**:GET +- **说明**:医生查看指定患者的已提交就诊记录列表。 + +#### 请求参数 + +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| patientId | int | 是 | 患者 ID | +| page | int | 否 | 页码,默认 1 | +| pageSize | int | 否 | 每页条数,默认 10 | +| year | int | 否 | 按就诊年份筛选(快捷方式,等同于yearStart=year&yearEnd=year) | +| yearStart | int | 否 | 按就诊年份范围筛选-起始年份,优先级高于year | +| yearEnd | int | 否 | 按就诊年份范围筛选-结束年份,优先级高于year | + +#### 响应示例 + +同 [1.4 就诊记录列表](#14-就诊记录列表),但仅返回已提交的记录。 + +--- + +### 2.2 就诊记录详情 + +- **路由**:`?r=igg4/doctor/medical-visit/detail` +- **请求方式**:GET +- **说明**:医生查看指定患者的某条就诊记录详情。 + +#### 请求参数 + +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| id | int | 是 | 就诊记录 ID | +| patientId | int | 是 | 患者 ID | + +#### 响应示例 + +同 [1.3 获取就诊记录详情](#13-获取就诊记录详情)。 + +--- + +### 2.3 图片字段历史列表 + +- **路由**:`?r=igg4/doctor/medical-visit/image-history` +- **请求方式**:GET +- **说明**:医生查看指定患者的某种图片类型历史列表。 + +#### 请求参数 + +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| patientId | int | 是 | 患者 ID | +| imageField | string | 是 | 图片类型标识 | +| year | int | 否 | 按就诊年份筛选(快捷方式,等同于yearStart=year&yearEnd=year) | +| yearStart | int | 否 | 按就诊年份范围筛选-起始年份,优先级高于year | +| yearEnd | int | 否 | 按就诊年份范围筛选-结束年份,优先级高于year | + +#### imageField 枚举 + +同 [1.6 imageField 枚举](#imagefield-枚举) + +#### 响应示例 + +同 [1.6 图片字段历史列表](#16-图片字段历史列表),仅返回已提交记录的数据。 + +--- + +### 2.4 指标字段历史列表 + +- **路由**:`?r=igg4/doctor/medical-visit/indicator-history` +- **请求方式**:GET +- **说明**:医生查看指定患者的某个指标字段历史数据趋势。 + +#### 请求参数 + +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| patientId | int | 是 | 患者 ID | +| indicatorField | string | 是 | 指标字段标识 | +| year | int | 否 | 按就诊年份筛选(快捷方式,等同于yearStart=year&yearEnd=year) | +| yearStart | int | 否 | 按就诊年份范围筛选-起始年份,优先级高于year | +| yearEnd | int | 否 | 按就诊年份范围筛选-结束年份,优先级高于year | + +#### indicatorField 枚举 + +同 [1.7 indicatorField 枚举](#indicatorfield-枚举) + +#### 响应示例 + +同 [1.7 指标字段历史列表](#17-指标字段历史列表),仅返回已提交记录的数据。 + +--- + +### 2.5 导出就诊记录PPT + +- **路由**:`?r=igg4/doctor/medical-visit/export-ppt` +- **请求方式**:POST +- **说明**:医生导出指定患者的就诊记录PPT文件,包含5个模块:患者基本信息、主诉与诊断、检验报告指标趋势、就诊记录处方、激素用量。仅包含已提交的记录。 + +#### 请求参数 + +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| patientId | int | 是 | 患者 ID | + +#### 响应 + +直接返回PPT文件流(Content-Type: application/vnd.openxmlformats-officedocument.presentationml.presentation),浏览器触发下载。文件名格式:`就诊记录_{patientId}_{timestamp}.pptx`。 + +#### PPT内容结构 + +| 页码 | 模块 | 说明 | +|------|------|------| +| 1 | 01. 患者基本信息 | 姓名(脱敏)、性别、年龄段、首次发病时间、首次发病部位、是否确诊IgG4 | +| 2+ | 02. 就诊记录病历:主诉与诊断 | 每页5条,展示就诊时间/主诉/病史/诊断/处理意见 | +| N+ | 03. 检验报告(实验室核心血清学指标趋势追踪) | 每页10条,表格展示6项指标 | +| N+ | 04. 就诊记录处方 | 每页3条,展示处方信息 | +| N+ | 05. 激素用量 | 每页10条,表格展示日期+用量 | + +#### 数据脱敏规则 + +- 患者姓名:2字显示"张*",3字及以上显示"张*丰"(保留首尾字符) +- 年龄:转换为年龄段(18-44岁/45-59岁/60-74岁/75岁以上) + +#### 业务逻辑说明 + +1. 校验 patientId 必传 +2. 查询患者基本信息(TZdPatientInfo + 健康问卷最新答案) +3. 查询已提交就诊记录列表(RecordStatus=2, Status=1) +4. 查询用药记录(TZdPatientMedicationRecord) +5. 生成PPT临时文件并返回文件流 +6. 返回后自动删除临时文件 + +--- + +## 三、后台管理员接口 + +模块路由前缀:`medical-visit-record` + +后台管理员负责对小程序用户上传的图片进行涂抹处理,涂抹后上传涂抹图片并同步触发 OCR 解析。所有 POST 接口使用数据库事务。 + +--- + +### 3.1 就诊记录列表 + +- **路由**:`?r=medical-visit-record/list` +- **请求方式**:GET +- **说明**:后台管理就诊记录列表,以图片为主表(一张图一条数据),支持按提交人姓名和图片类型筛选,仅展示已提交的记录。 + +#### 请求参数 + +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| submitterName | string | 否 | 提交人姓名(患者姓名模糊搜索) | +| imageType | string | 否 | 图片类型标识,不传则返回全部,见枚举表 | +| page | int | 否 | 页码,默认 1 | +| pageSize | int | 否 | 每页条数,默认 10 | + +#### imageType 枚举 + +同 [1.1 images.imageType](#imagetype-枚举) + +#### 响应示例 + +```json +{ + "code": 0, + "message": "success", + "data": { + "page": 1, + "pages": 5, + "totalCount": 50, + "list": [ + { + "id": 102, + "submitterName": "张三", + "recordTime": "2026-06-29 14:20:00", + "visitDate": "2026-06-29", + "nextVisitDate": "2026-09-29", + "imageType": "labReport", + "imageUrl": "https://oss.example.com/img001.jpg", + "maskedImageUrl": "https://oss.example.com/img001_masked.jpg", + "igG4Value": 135.0, + "manualIgG4Value": 135.0, + "displayIgG4Value": 135.0, + "chiefComplaint": null, + "medicalHistory": null, + "diagnosis": null, + "treatmentPlan": null, + "medicalRecordTime": null, + "prescriptionTime": null, + "reportTime": "2026-06-28 14:20:00", + "prescription": null, + "clinicalDiagnosis": null, + "oralHormoneDosage": 4.0, + "medicationsUsed": [2, 3], + "immunosuppressantName": [1, 7], + "medicationsUsedOtherText": null, + "immunosuppressantNameOtherText": null + }, + { + "id": 103, + "submitTime": "2026-06-29 10:30:00", + "submitterName": "张三", + "recordTime": "2026-06-29 15:00:00", + "visitDate": "2026-06-29", + "nextVisitDate": "2026-09-29", + "imageType": "outpatientRecord", + "imageUrl": "https://oss.example.com/img002.jpg", + "maskedImageUrl": "https://oss.example.com/img002_masked.jpg", + "igG4Value": null, + "manualIgG4Value": 135.0, + "displayIgG4Value": 135.0, + "chiefComplaint": "反复腹痛3月", + "medicalHistory": "患者3月前无明显诱因出现腹痛", + "diagnosis": "IgG4相关性疾病", + "treatmentPlan": "激素治疗,定期复查", + "medicalRecordTime": "2026-06-29 09:30:00", + "prescriptionTime": "2026-06-29 10:15:00", + "reportTime": null, + "prescription": "甲泼尼龙片 4mg 每日1次 口服 30片", + "clinicalDiagnosis": "IgG4相关性疾病", + "oralHormoneDosage": 4.0, + "medicationsUsed": [2, 3], + "immunosuppressantName": [1, 7], + "medicationsUsedOtherText": null, + "immunosuppressantNameOtherText": null + } + ] + } +} +``` + +#### 字段说明 + +| 字段 | 类型 | 说明 | +|------|------|------| +| id | int | 图片记录 ID | +| submitterName | string | 提交人姓名(患者姓名) | +| recordTime | string | 记录时间(图片创建时间) | +| visitDate | string | 就诊时间 | +| nextVisitDate | string | 复诊时间 | +| imageType | string | 图片类型标识(camelCase) | +| imageUrl | string | 患者提交的图片 URL | +| maskedImageUrl | string | 后台处理后的图片 URL,未涂抹时为 null | +| igG4Value | float | IgG4 数值(mg/dL),仅检验报告类型有值 | +| manualIgG4Value | float | 患者手动录入的 IgG4 数值(冗余字段,mg/dL),未录入时为 null | +| displayIgG4Value | float | 展示用 IgG4 数值,优先取 manualIgG4Value,为空则取 igG4Value;均为空时为 null | +| chiefComplaint | string | 主诉内容,仅门诊病历类型有值 | +| medicalHistory | string | 现病史/既往史/病史,仅门诊病历类型有值 | +| diagnosis | string | 诊断,仅门诊病历类型有值 | +| treatmentPlan | string | 处理意见/医嘱/治疗方案,仅门诊病历类型有值 | +| medicalRecordTime | string | 病历时间(图片类型=门诊病历时有值),格式 YYYY-MM-DD 或 YYYY-MM-DD HH:mm:ss | +| prescriptionTime | string | 处方时间(图片类型=门诊病历时有值),格式 YYYY-MM-DD 或 YYYY-MM-DD HH:mm:ss | +| reportTime | string | 检查报告时间(图片类型=检验报告时有值),格式 YYYY-MM-DD 或 YYYY-MM-DD HH:mm:ss | +| prescription | string | 处方内容,仅门诊病历类型有值 | +| clinicalDiagnosis | string | 临床诊断,仅处方类型图片有值;未解析到时为 null | +| oralHormoneDosage | float | 激素用量(片/天) | +| medicationsUsed | array | 本次就诊已使用的药物(多选),值为常量ID数组,见附录G;未选择时为 null | +| immunosuppressantName | array | 正在使用的免疫抑制剂名称(多选),值为常量ID数组,见附录G;未选择时为 null | +| medicationsUsedOtherText | string | 本次就诊已使用药物选择"其他"(99)时的补充文本,未选择"其他"时为 null | +| immunosuppressantNameOtherText | string | 正在使用的免疫抑制剂名称选择"其他"(99)时的补充文本,未选择"其他"时为 null | + +#### 业务逻辑说明 + +1. 以图片表(t_iggfour_medical_visit_record_image)为主表,一张图一条数据 +2. JOIN 就诊记录表获取 VisitDate、NextVisitDate、OralHormoneDosage,且约束 RecordStatus=2(已提交) +3. JOIN 患者表获取患者姓名(submitterName) +4. 提交人姓名筛选:患者姓名模糊匹配(LIKE) +5. 图片类型筛选:imageType 参数传入 camelCase 标识,内部转为整型后 WHERE 匹配 +6. 仅展示已提交记录(RecordStatus=2),草稿不在列表中显示 +7. 按图片创建时间(CreateTime)降序排列 + +--- + +### 3.2 上传涂抹图片并解析 + +- **路由**:`?r=medical-visit-record/upload-masked-image` +- **请求方式**:POST +- **说明**:管理员上传涂抹后的图片 URL,保存后同步触发 OCR 解析。涂抹后立即执行 OCR,无需异步任务。使用数据库事务。 + +#### 请求参数 + +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| imageId | int | 是 | 图片记录 ID | +| maskedImageUrl | string | 是 | 涂抹后图片 URL | + +#### 请求示例 + +```json +{ + "imageId": 102, + "maskedImageUrl": "https://oss.example.com/img001_masked.jpg" +} +``` + +#### 响应示例 — 检验报告类型(imageType=labReport) + +```json +{ + "code": 0, + "message": "success", + "data": { + "imageId": 102, + "maskedImageUrl": "https://oss.example.com/img001_masked.jpg", + "ocrStatus": 2, + "ocrText": "IgG4 1.35 g/L\n总IgG 12.0 g/L\nIgE 50 IU/mL\nESR 20 mm/h\nCRP 5 mg/L", + "ocrParsedData": { + "reportTime": "2026-06-28 14:20:00", + "indicators": { + "igG4": {"value": 135.0, "unit": "mg/dL"}, + "totalIgG": {"value": 1200.0, "unit": "mg/dL"}, + "igE": {"value": 50.0, "unit": "IU/mL"}, + "eos": {"value": null, "unit": "10^9/L"}, + "esr": {"value": 20.0, "unit": "mm/h"}, + "crp": {"value": 5.0, "unit": "mg/L"} + } + }, + "igG4Value": 322, + "totalIgGValue": 1370, + "igEValue": null, + "eosCount": null, + "esrValue": null, + "crpValue": null, + "chiefComplaint": null, + "medicalHistory": null, + "diagnosis": null, + "treatmentPlan": null, + "prescription": null, + "clinicalDiagnosis": null, + "medicalRecordTime": null, + "prescriptionTime": null, + "reportTime": "2026-06-28 14:20:00" + } +} +``` + +#### 响应示例 — 门诊病历类型(imageType=outpatientRecord) + +```json +{ + "code": 0, + "message": "success", + "data": { + "imageId": 103, + "maskedImageUrl": "https://oss.example.com/img002_masked.jpg", + "ocrStatus": 2, + "ocrText": "患者XXX,男,45岁\n主诉:反复腹痛3月\n诊断:IgG4相关性疾病\n处理意见:激素治疗,定期复查", + "ocrParsedData": { + "medicalRecordTime": "2026-06-29 09:30:00", + "prescriptionTime": "2026-06-29 10:15:00", + "chiefComplaint": "反复腹痛3月", + "medicalHistory": "患者3月前无明显诱因出现腹痛", + "diagnosis": "IgG4相关性疾病", + "treatmentPlan": "激素治疗,定期复查", + "prescription": "甲泼尼龙片 4mg 每日1次 口服 30片", + "clinicalDiagnosis": "IgG4相关性疾病" + }, + "igG4Value": null, + "totalIgGValue": null, + "igEValue": null, + "eosCount": null, + "esrValue": null, + "crpValue": null, + "chiefComplaint": "反复腹痛3月", + "medicalHistory": "患者3月前无明显诱因出现腹痛", + "diagnosis": "IgG4相关性疾病", + "treatmentPlan": "激素治疗,定期复查", + "prescription": "甲泼尼龙片 4mg 每日1次 口服 30片", + "clinicalDiagnosis": "IgG4相关性疾病", + "medicalRecordTime": "2026-06-29 09:30:00", + "prescriptionTime": "2026-06-29 10:15:00", + "reportTime": null + } +} +``` + +#### 响应示例 — OCR 解析失败 + +```json +{ + "code": 0, + "message": "success", + "data": { + "imageId": 104, + "maskedImageUrl": "https://oss.example.com/img003_masked.jpg", + "ocrStatus": 3, + "ocrText": null, + "ocrParsedData": null, + "igG4Value": null, + "totalIgGValue": null, + "igEValue": null, + "eosCount": null, + "esrValue": null, + "crpValue": null, + "chiefComplaint": null, + "medicalHistory": null, + "diagnosis": null, + "treatmentPlan": null, + "prescription": null, + "clinicalDiagnosis": null, + "medicalRecordTime": null, + "prescriptionTime": null, + "reportTime": null + } +} +``` + +#### 业务逻辑说明 + +1. 校验 imageId 对应的图片记录存在,否则报错"图片记录不存在" +2. 校验管理员已登录,获取当前操作人 workerId +3. **事务1**:保存 MaskedImageUrl,设置 OcrStatus=1(解析中),清空旧的 OcrText/OcrParsedData/指标字段/时间字段(MedicalRecordTime/PrescriptionTime/ReportTime),记录 UpdateWorkerId/UpdateTime +4. 事务1提交后,同步调用 OCR 服务:`LabReportOcrService::recognizeByType($maskedImageUrl, $imageTypeKey)` +5. 根据 imageType 类型处理 OCR 结果: + - 检验报告(labReport):解析指标值写入图片记录的独立指标字段(IgG4Value/TotalIgGValue 等),时间字段写入 ReportTime + - 门诊病历(outpatientRecord):解析文本写入图片记录的病历文本字段(ChiefComplaint/MedicalHistory 等),时间字段写入 MedicalRecordTime/PrescriptionTime + - 其他类型:原始文本写入 OcrText,OcrParsedData 存原文 +6. **事务2**:写入 OCR 解析结果,设置 OcrStatus=2(解析完成),记录 UpdateWorkerId/UpdateTime +7. 若 OCR 调用抛异常,**事务2回退**:设置 OcrStatus=3(解析失败),记录 UpdateWorkerId/UpdateTime +8. 返回包含 maskedImageUrl、ocrStatus、ocrText、ocrParsedData、指标字段 的结果数据 +9. igG4Value - IgG4 指标值(单位:mg/dL) +10. totalIgGValue - 总 IgG 指标值(单位:mg/dL) +11. igEValue - IgE 指标值(单位:IU/mL) +12. eosCount - eos 指标值(单位:10^9/L) +13. esrValue - ESR 指标值(单位:mm/h) +14. crpValue - CRP 指标值(单位:mg/L) +15. chiefComplaint - 主诉 +16. medicalHistory - 病史 +17. diagnosis - 诊断 +18. treatmentPlan - 处理意见 +19. prescription - 处方 +20. medicalRecordTime - 病历时间(门诊病历图片识别为门诊病历时,从OCR解析获取) +21. prescriptionTime - 处方时间(门诊病历图片识别为处方时,从OCR解析获取) +22. reportTime - 检查报告时间(检验报告图片,从OCR解析获取) +23. ocrParsedData 结构说明:检验报告返回 `{reportTime, indicators: {...}}`,门诊病历返回 `{medicalRecordTime, prescriptionTime, chiefComplaint, ...}` + + + +--- + +#### ocrStatus 枚举 + +| 值 | 说明 | +|------|------| +| 0 | 待解析(小程序用户已上传原图,后台尚未涂抹) | +| 1 | 解析中(后台已上传涂抹图片,OCR 正在执行) | +| 2 | 解析完成 | +| 3 | 解析失败 | + +--- + +## 附录 + +### A. 记录状态枚举 + +| 值 | 常量名 | 说明 | +|------|------|------| +| 1 | RECORD_STATUS_DRAFT | 草稿 | +| 2 | RECORD_STATUS_SUBMITTED | 已提交 | + +### B. 数据状态枚举 + +| 值 | 常量名 | 说明 | +|------|------|------| +| 1 | STATUS_ACTIVE | 有效 | +| 100 | STATUS_DELETED | 已删除 | + +### C. 口服激素用量预设选项(片/天) + +| 值 | 说明 | +|------|------| +| 1 | 1片/天 | +| 2 | 2片/天 | +| 4 | 4片/天 | +| 6 | 6片/天 | +| 8 | 8片/天 | + +### D. 检验指标单位换算 + +| 指标 | 原始单位 | 目标单位 | 换算公式 | +|------|---------|---------|---------| +| IgG4 | g/L | mg/dL | 值 × 100 | +| 总IgG | g/L | mg/dL | 值 × 100 | +| IgE | — | IU/mL | 不换算 | +| EOS# | — | 10^9/L | 不换算 | +| ESR | — | mm/h | 不换算 | +| CRP | — | mg/L | 不换算 | + +### E. 数据库表结构 + +#### t_iggfour_medical_visit_record 就诊记录主表 + +| 字段名 | 类型 | 说明 | +|--------|------|------| +| Id | int AUTO_INCREMENT PK | 主键 | +| UserId | varchar(40) NOT NULL | 用户 ID | +| PatientId | int NOT NULL | 患者 ID | +| VisitDate | date NOT NULL | 就诊日期 | +| NextVisitDate | date DEFAULT NULL | 下次复诊日期 | +| IgG4Value | decimal(10,2) DEFAULT NULL | IgG4 数值(OCR 解析) | +| ManualIgG4Value | decimal(10,2) DEFAULT NULL | IgG4 数值(患者手动录入,冗余字段) | +| TotalIgGValue | decimal(10,2) DEFAULT NULL | 总 IgG 数值 | +| IgEValue | decimal(10,2) DEFAULT NULL | IgE 数值 | +| EosCount | decimal(10,2) DEFAULT NULL | EOS# 计数 | +| ESRValue | decimal(10,2) DEFAULT NULL | ESR 数值 | +| CRPValue | decimal(10,2) DEFAULT NULL | CRP 数值 | +| OralHormoneDosage | decimal(10,2) DEFAULT NULL | 口服激素每日用量(片) | +| MedicationsUsed | varchar(255) DEFAULT NULL | 本次就诊已使用的药物(JSON数组,多选),见附录G | +| ImmunosuppressantName | varchar(255) DEFAULT NULL | 正在使用的免疫抑制剂名称(JSON数组,多选),见附录G | +| MedicationsUsedOtherText | varchar(500) DEFAULT NULL | 本次就诊已使用药物-其他-补充文本 | +| ImmunosuppressantNameOtherText | varchar(500) DEFAULT NULL | 正在使用的免疫抑制剂名称-其他-补充文本 | +| MedicalRecordTime | varchar(30) DEFAULT NULL | 门诊病历时间 | +| PrescriptionTime | varchar(30) DEFAULT NULL | 处方时间 | +| ReportTime | varchar(30) DEFAULT NULL | 检查报告时间 | +| ChiefComplaint | text DEFAULT NULL | 主诉 | +| MedicalHistory | text DEFAULT NULL | 病史 | +| Diagnosis | text DEFAULT NULL | 诊断 | +| TreatmentPlan | text DEFAULT NULL | 处理意见 | +| Prescription | text DEFAULT NULL | 处方内容 | +| ClinicalDiagnosis | varchar(500) DEFAULT NULL | 临床诊断(从处方图片解析) | +| RecordStatus | tinyint NOT NULL DEFAULT 1 | 记录状态:1-草稿,2-已提交 | +| LastRecordId | int DEFAULT NULL | 上一条记录 ID | +| Status | tinyint NOT NULL DEFAULT 1 | 数据状态:1-有效,100-删除 | +| CreateWorkerId | int NOT NULL DEFAULT 0 | 创建人 | +| CreateTime | datetime NOT NULL | 创建时间 | +| UpdateWorkerId | int NOT NULL DEFAULT 0 | 更新人 | +| UpdateTime | datetime NOT NULL | 更新时间 | + +#### t_iggfour_medical_visit_record_image 就诊记录图片表 + +| 字段名 | 类型 | 说明 | +|--------|------|------| +| Id | int AUTO_INCREMENT PK | 主键 | +| RecordId | int NOT NULL | 关联就诊记录 ID | +| ImageType | tinyint NOT NULL | 图片类型:1-门诊病历,2-检验报告,3-影像检查,4-其他 | +| ImageUrl | varchar(500) NOT NULL | 原始图片 URL | +| MaskedImageUrl | varchar(500) DEFAULT NULL | 涂抹后图片 URL | +| OcrStatus | tinyint NOT NULL DEFAULT 0 | OCR 状态:0-未解析,1-解析中,2-解析完成,3-解析失败 | +| OcrText | text DEFAULT NULL | OCR 原始文本 | +| OcrParsedData | text DEFAULT NULL | OCR 解析结果(JSON) | +| IgG4Value | decimal(10,2) DEFAULT NULL | IgG4 数值 | +| TotalIgGValue | decimal(10,2) DEFAULT NULL | 总 IgG 数值 | +| IgEValue | decimal(10,2) DEFAULT NULL | IgE 数值 | +| EosCount | decimal(10,2) DEFAULT NULL | EOS# 计数 | +| ESRValue | decimal(10,2) DEFAULT NULL | ESR 数值 | +| CRPValue | decimal(10,2) DEFAULT NULL | CRP 数值 | +| ChiefComplaint | text DEFAULT NULL | 主诉(从门诊病历图片解析) | +| MedicalHistory | text DEFAULT NULL | 病史(从门诊病历图片解析) | +| Diagnosis | text DEFAULT NULL | 诊断(从门诊病历图片解析) | +| TreatmentPlan | text DEFAULT NULL | 处理意见(从门诊病历图片解析) | +| Prescription | text DEFAULT NULL | 从本图OCR解析的处方内容,仅图片类型=1时有值 | +| ClinicalDiagnosis | varchar(500) DEFAULT NULL | 临床诊断(从处方图片解析) | +| MedicalRecordTime | varchar(30) DEFAULT NULL | 门诊病历时间 | +| PrescriptionTime | varchar(30) DEFAULT NULL | 处方时间 | +| ReportTime | varchar(30) DEFAULT NULL | 检查报告时间 | +| SortOrder | int NOT NULL DEFAULT 0 | 排序序号 | +| Status | tinyint NOT NULL DEFAULT 1 | 数据状态:1-有效,100-删除 | +| CreateWorkerId | int NOT NULL DEFAULT 0 | 创建人 | +| CreateTime | datetime NOT NULL | 创建时间 | +| UpdateWorkerId | int NOT NULL DEFAULT 0 | 更新人 | +| UpdateTime | datetime NOT NULL | 更新时间 | + +#### t_medical_visit_reminder_config 复诊提醒配置表 + +| 字段名 | 类型 | 说明 | +|--------|------|------| +| Id | int AUTO_INCREMENT PK | 主键 | +| PatientId | int NOT NULL | 患者 ID(唯一索引) | +| ReminderEnabled | tinyint NOT NULL DEFAULT 2 | 是否开启复诊提醒:1-开启,2-关闭 | +| Status | tinyint NOT NULL DEFAULT 1 | 数据状态:1-有效,100-删除 | +| CreateWorkerId | int DEFAULT NULL | 创建人 | +| CreateTime | datetime DEFAULT NULL | 创建时间 | +| UpdateWorkerId | int DEFAULT NULL | 更新人 | +| UpdateTime | datetime DEFAULT NULL | 更新时间 | + + +### G. 药物选项枚举 + +#### MedicationsUsed 本次就诊已使用的药物(多选) + +| 值 | 常量名 | 说明 | +|------|------|------| +| 1 | MED_USED_NO_HORMONE | 没有使用激素 | +| 2 | MED_USED_HORMONE | 激素 | +| 3 | MED_USED_IMMUNOSUPPRESSANT | 免疫抑制剂 | +| 4 | MED_USED_CD19 | 靶向CD19生物制剂(伊奈利珠单抗) | +| 5 | MED_USED_CD20 | 靶向CD20生物制剂(利妥昔单抗等) | +| 99 | MED_USED_OTHER | 其他 | + +#### ImmunosuppressantName 正在使用的免疫抑制剂名称(多选) + +| 值 | 常量名 | 说明 | +|------|------|------| +| 1 | IMMUNOSUPPRESSANT_MMF | 吗替麦考酚酯(骁悉、麦考芬) | +| 2 | IMMUNOSUPPRESSANT_AZA | 替唑嘌呤 | +| 3 | IMMUNOSUPPRESSANT_CYC | 环磷酰胺 | +| 4 | IMMUNOSUPPRESSANT_LEF | 来氟米特 | +| 5 | IMMUNOSUPPRESSANT_MTX | 甲氨蝶呤 | +| 6 | IMMUNOSUPPRESSANT_CYC_A | 环孢素 A | +| 7 | IMMUNOSUPPRESSANT_TAC | 他克莫司 | +| 8 | IMMUNOSUPPRESSANT_IGU | 艾拉莫德 | +| 99 | IMMUNOSUPPRESSANT_OTHER | 其他 | + +#### 复诊提醒配置枚举 + +| 值 | 常量名 | 说明 | +|------|------|------| +| 1 | REMINDER_ENABLED | 开启复诊提醒 | +| 2 | REMINDER_DISABLED | 关闭复诊提醒 | +| 7 | REMINDER_DAYS_BEFORE | 提前提醒天数(天) | diff --git a/doc/api_doctor_msg_task.md b/doc/api_doctor_msg_task.md new file mode 100644 index 0000000..607cff9 --- /dev/null +++ b/doc/api_doctor_msg_task.md @@ -0,0 +1,572 @@ +# 医生消息任务接口文档 + +## 通用说明 + +### 响应格式 + +所有接口返回 JSON,严格遵循以下格式: + +```json +{ + "code": 0, + "message": "success", + "data": {} +} +``` + +- `code`:0 表示成功,非 0 表示失败 +- `message`:成功时为 "success",失败时为错误描述 +- `data`:业务数据,失败时为 null + +### 数据命名规则 + +`data` 中所有字段使用**小驼峰**命名法(如 `patientNum`、`sendTime`)。 + +### 登录校验 + +所有接口需通过请求头 `loginState` 或请求参数 `loginState` 传递登录态,未登录返回 code=403。本模块所有接口需医生身份登录。 + +### 错误码 + +| code | 说明 | +|------|------| +| 0 | 成功 | +| 1 | 参数缺失或业务异常 | +| 403 | 需要登录 | + +--- + +## 一、筛选患者人数 + +- **路由**:`?r=igg4/doctor/task/filter-patient-num` +- **请求方式**:GET +- **说明**:根据筛选条件获取符合条件的患者人数 + +### 请求参数 + +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| SelectAll | int | 否 | 全选:0-否,1-是;为1时跳过其余筛选条件 | +| BindStartDate | string | 否 | 绑定日期开始,格式 YYYY-MM-DD | +| BindEndDate | string | 否 | 绑定日期结束,格式 YYYY-MM-DD | +| ConfirmedIgg4 | int | 否 | 确诊IGG4-RD:0-全部,1-是,2-否 | +| MedicationType | string | 否 | 正在使用的药物,逗号分隔选项值(如"2,3"),空或0表示全部。可选值见下面枚举表 | + +#### ConfirmedIgg4 枚举 + +| 值 | 说明 | +|----|------| +| 0 | 全部 | +| 1 | 是(确诊患者) | +| 2 | 否(非确诊患者,含未填写和疑似) | + +#### MedicationType 枚举 + +| 值 | 说明 | +|----|------| +| 0 | 全部 | +| 2 | 激素 | +| 3 | 免疫抑制剂 | +| 4 | 靶向CD19生物制剂(伊奈利珠单抗) | +| 5 | 靶向CD20生物制剂(利妥昔单抗等) | + +### 请求示例 + +``` +?r=igg4/doctor/task/filter-patient-num&SelectAll=0&BindStartDate=2026-01-01&BindEndDate=2026-06-30&ConfirmedIgg4=1&MedicationType=2,3 +``` + +### 响应示例 + +```json +{ + "code": 0, + "data": { + "PatientNum": "1" + } +} +``` + +### 业务逻辑说明 + +1. 基础条件:患者状态有效、属于当前医生、有绑定用户 +2. SelectAll=1 时跳过所有筛选直接返回 +3. 绑定时间范围:按 `InviteTime` 字段筛选,使用 BETWEEN 逻辑 +4. 确诊IGG4-RD:选"是"时匹配 `IsSuspectedPatient=2`,选"否"时排除 `IsSuspectedPatient=2`(保留未填写和疑似患者) +5. 药物筛选:关联 `t_patient_health_questionnaire_latest` 表(QuestionNo=4),使用 `FIND_IN_SET` 匹配多选答案,多个选项值之间为 OR 关系 + +--- + +## 二、获取任务模板 + +- **路由**:`?r=igg4/doctor/task/get-template` +- **请求方式**:GET +- **说明**:获取所有消息推送模板,按模板类型分组 + +### 请求参数 + +无 + +### 响应示例 + +```json +{ + "code": 0, + "data": [ + { + "templateType": 1, + "templateTypeText": "复诊提醒", + "templateList": [ + { + "id": 1, + "templateType": 1, + "interactMsgContent": "互动消息内容", + "templateIndex": "模板index", + "templateContent": "模板内容JSON" + } + ] + } + ] +} +``` + +#### TemplateType 枚举 + +| 值 | 说明 | +|----|------| +| 1 | 复诊提醒 | +| 2 | 激素风险提醒 | + +### 业务逻辑说明 + +1. 查询所有模板记录,按 `TemplateType` 升序、`Id` 升序排列 +2. 按 `TemplateType` 分组返回,每组包含类型编号、类型文本和模板列表 + +--- + +## 三、创建任务 + +- **路由**:`?r=igg4/doctor/task/create` +- **请求方式**:POST +- **说明**:创建消息推送任务,使用数据库事务 + +### 请求参数 + +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| FilterCondition | object | 否 | 筛选条件JSON对象,结构同"筛选患者人数"接口参数 | +| PushTemplateId | int | 是 | 推送模板ID | +| IsSendNow | int | 是 | 是否立即发送:0-否,1-是 | +| SendTime | string | 条件必填 | 发送时间(IsSendNow=0时必填),格式 YYYY-MM-DD HH:mm:ss | +| PatientNum | int | 是 | 患者人数 | + +#### FilterCondition 结构 + +| 字段 | 类型 | 说明 | +|------|------|------| +| SelectAll | int | 全选:0-否,1-是 | +| BindStartDate | string | 绑定日期开始 | +| BindEndDate | string | 绑定日期结束 | +| ConfirmedIgg4 | int | 确诊IGG4-RD:0-全部,1-是,2-否 | +| MedicationType | string | 正在使用的药物,逗号分隔 | + +### 请求示例 + +```json +{ + "FilterCondition": { + "SelectAll": 0, + "BindStartDate": "2026-01-01", + "BindEndDate": "2026-06-30", + "ConfirmedIgg4": 1, + "MedicationType": "2" + }, + "PushTemplateId": 2, + "IsSendNow": 1, + "SendTime": "", + "PatientNum": 25 +} +``` + +### 响应示例(成功) + +```json +{ + "code": 0, + "data": "创建成功" +} +``` + +### 响应示例(失败) + +```json +{ + "code": 1, + "data": "每个医生每天只能创建一次任务" +} +``` + +### 业务逻辑说明 + +1. 校验医生存在(逻辑删除标记 `DeleteTime` 为空) +2. 校验模板存在 +3. 每个医生每天只能创建一次任务(当天已有状态为待发送/发送中/暂停/已发送/已停止的任务则不可再创建) +4. IsSendNow=1 时,SendTime 自动设为当前时间 +5. 自动生成 IdNumber(`YmdHis` + 3位随机数) +6. IsDoctorCreate=1(医生端创建),CreateWorkerId 为空 +7. 生成模板消息内容(调用 `transformTemplateContent` 转化模板变量) +8. 保存任务后,自动调用 `generateUserRecord` 生成用户发送记录 +9. 更新任务的 ActualPatientNum 和 IsInsertUser 字段 + +--- + +## 四、获取任务列表 + +- **路由**:`?r=igg4/doctor/task/list` +- **请求方式**:GET +- **说明**:获取当前医生的任务列表,支持分页,按创建时间降序排列 + +### 请求参数 + +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| count | int | 否 | 每页条数,默认10 | +| page | int | 否 | 页码,从1开始 | + +### 请求示例 + +``` +?r=igg4/doctor/task/list&count=10&page=1 +``` + +### 响应示例 + +```json +{ + "code": 0, + "data": { + "list": [ + { + "Id": 1, + "IdNumber": "20260702143025123", + "DoctorId": 5, + "FilterCondition": { + "SelectAll": 0, + "BindStartDate": "2026-01-01", + "BindEndDate": "2026-06-30", + "ConfirmedIgg4": 1, + "MedicationType": "2" + }, + "TemplateType": 1, + "CreateTime": "2026-07-02 14:30:25", + "IsSendNow": 1, + "SendTime": "2026-07-02 14:30:25", + "Status": 4, + "PatientNum": 25, + "ActualPatientNum": 23 + } + ], + "pages": 3, + "count": 28, + "page": 1 + } +} +``` + +### 响应字段说明 +| 字段 | 类型 | 说明 | +|------|------|------| +| Id | int | 任务ID | +| IdNumber | string | 任务编号 | +| DoctorId | int | 医生ID | +| FilterCondition | object | 筛选条件JSON对象 | +| TemplateType | int | 模板类型 | +| CreateTime | string | 创建时间 | +| IsSendNow | int | 是否立即发送:0-否,1-是 | +| SendTime | string | 发送时间 | +| Status | int | 任务状态 | +| PatientNum | int | 患者人数 | +| ActualPatientNum | int | 实际发送患者人数 | + +#### FilterCondition 结构说明 + +| 字段 | 类型 | 说明 | +|------|------|------| +| SelectAll | int | 全选:0-否,1-是 | +| BindStartDate | string | 绑定日期开始 | +| BindEndDate | string | 绑定日期结束 | +| ConfirmedIgg4 | int | 确诊IGG4-RD:0-全部,1-是,2-否 | +| MedicationType | string | 正在使用的药物,逗号分隔 | + +#### TemplateType 枚举 + +| 值 | 说明 | +|----|------| +| 1 | 复诊提醒 | +| 2 | 激素风险提醒 | + +#### Status 枚举 + +| 值 | 说明 | +|----|------| +| 1 | 待发送 | +| 2 | 发送中 | +| 3 | 暂停 | +| 4 | 已发送 | +| 5 | 已停止 | +| 6 | 已取消 | + +### 业务逻辑说明 + +1. 仅查询 `DeleteTime` 为空的任务 +2. FilterCondition 字段从 JSON 字符串解码为数组返回 +3. 返回字段包含:Id, IdNumber, DoctorId, FilterCondition, TemplateType, CreateTime, IsSendNow, SendTime, Status, PatientNum, ActualPatientNum +4. 分页参数:pages 为总页数,count 为总记录数,page 为当前页码(从1开始) + +--- + +## 五、获取任务详情 + +- **路由**:`?r=igg4/doctor/task/detail` +- **请求方式**:GET +- **说明**:获取单个任务的详细信息,包含发送统计 + +### 请求参数 + +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| TaskId | int | 是 | 任务ID | + +### 请求示例 + +``` +?r=igg4/doctor/task/detail&TaskId=1 +``` + +### 响应示例 + +```json +{ + "code": 0, + "data": { + "Id": 1, + "IdNumber": "20260702143025123", + "DoctorId": 5, + "FilterCondition": { + "SelectAll": 0, + "BindStartDate": "2026-01-01", + "BindEndDate": "2026-06-30", + "ConfirmedIgg4": 1, + "MedicationType": "2" + }, + "TemplateType": 1, + "PushTemplateId": 2, + "TemplateMsgContent": "{...}", + "InteractMsgContent": "互动消息内容", + "IsSendNow": 1, + "SendTime": "2026-07-02 14:30:25", + "PatientNum": 25, + "ActualPatientNum": 23, + "IsInsertUser": 1, + "Status": 4, + "IsDoctorCreate": 1, + "WorkerId": "", + "DeleteTime": null, + "CreateTime": "2026-07-02 14:30:25", + "UpdateTime": "2026-07-02 14:30:30", + "SendDetail": { + "TaskId": 1, + "SumSendCount": 23, + "SendCount": 20, + "UnSendCount": 3, + "InteractSendSuccessCount": 18, + "InteractSendFailCount": 2, + "PushSendSuccessCount": 16, + "PushSendFailCount": 4, + "PushClickCount": 10, + "InteractReadCount": 15, + "InteractUnReadCount": 5, + "PushUnClickCount": 10 + } + } +} +``` + +#### SendDetail 字段说明 + +| 字段 | 说明 | +|------|------| +| sumSendCount | 总人数(去重) | +| sendCount | 已发送人数 | +| unSendCount | 未发送人数 | +| InteractSendSuccessCount | 互动消息发送成功人数 | +| InteractSendFailCount | 互动消息发送失败人数(派生值:SendCount - InteractSendSuccessCount) | +| PushSendSuccessCount | Push消息发送成功人数 | +| PushSendFailCount | Push消息发送失败人数 | +| PushClickCount | Push消息点击人数 | +| InteractReadCount | 互动消息已读人数 | +| InteractUnReadCount | 互动消息未读人数(派生值:sendCount - InteractReadCount) | +| PushUnClickCount | Push消息未点击人数(派生值:sendCount - PushClickCount) | + +### 业务逻辑说明 + +1. 校验任务存在且 `DeleteTime` 为空,否则抛出"任务不存在" +2. FilterCondition 从 JSON 字符串解码为数组 +3. 根据 PushTemplateId 查询模板,补充 TemplateType 和 InteractMsgContent 字段 +4. 通过 `TZdDoctorMsgTaskUserMessage::taskDetail` 获取发送统计数据,包含派生的失败/未读/未点击人数 + +--- + +## 六、删除任务 + +- **路由**:`?r=igg4/doctor/task/delete` +- **请求方式**:POST +- **说明**:逻辑删除已取消的任务,使用数据库事务 + +### 请求参数 + +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| TaskId | int | 是 | 任务ID | + +### 请求示例 + +```json +{ + "TaskId": 1 +} +``` + +### 响应示例(成功) + +```json +{ + "code": 0, + "data": "删除成功" +} +``` + +### 响应示例(失败) + +```json +{ + "code": 1, + "msg": "当前任务状态不能删除", +} +``` + +### 业务逻辑说明 + +1. 校验任务存在、属于当前医生且 `DeleteTime` 为空,否则抛出"任务不存在" +2. 只有状态为"已取消"(Status=6)的任务才能删除 +3. 设置 `DeleteTime` 为当前时间(软删除) + +--- + +## 七、停止任务 + +- **路由**:`?r=igg4/doctor/task/stop` +- **请求方式**:POST +- **说明**:停止正在发送中或暂停的任务,使用数据库事务 + +### 请求参数 + +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| TaskId | int | 是 | 任务ID | + +### 请求示例 + +```json +{ + "TaskId": 1 +} +``` + +### 响应示例(成功) + +```json +{ + "code": 0, + "data": "停止成功" +} +``` + +### 响应示例(失败) + +```json +{ + "code": 1, + "msg": "当前任务状态不能停止", +} +``` + +### 业务逻辑说明 + +1. 校验任务存在、属于当前医生且 `DeleteTime` 为空,否则抛出"任务不存在" +2. 只有状态为"发送中"(Status=2)或"暂停"(Status=3)的任务才能停止 +3. 将状态更新为"已停止"(Status=5) + +--- + +## 八、取消任务 + +- **路由**:`?r=igg4/doctor/task/cancel` +- **请求方式**:POST +- **说明**:取消待发送的任务,使用数据库事务 + +### 请求参数 + +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| TaskId | int | 是 | 任务ID | + +### 请求示例 + +```json +{ + "TaskId": 1 +} +``` + +### 响应示例(成功) + +```json +{ + "code": 0, + "data": "取消成功" +} +``` + +### 响应示例(失败) + +```json +{ + "code": 1, + "msg": "当前任务状态不能取消", +} +``` + +### 业务逻辑说明 + +1. 校验任务存在、属于当前医生且 `DeleteTime` 为空,否则抛出"任务不存在" +2. 只有状态为"待发送"(Status=1)的任务才能取消 +3. 将状态更新为"已取消"(Status=6) + +--- + +## 附录 + +### 附录A:任务状态流转 + +``` +待发送(1) ──发送调度──> 发送中(2) ──发送完成──> 已发送(4) + │ │ ↑ + │取消 │ │暂停 + ↓ ↓ │ +已取消(6) <────────── 暂停(3)─┘ + │ │ + │删除(软删) │停止 + ↓ ↓ +(DeleteTime非空) 已停止(5) +``` diff --git a/doc/track.md b/doc/track.md new file mode 100644 index 0000000..ecb44aa --- /dev/null +++ b/doc/track.md @@ -0,0 +1,216 @@ +# 埋点文档 + +## 命名规范 + +| 类别 | 前缀 | 格式 | 示例 | +|------|------|------|------| +| 页面浏览(患者端) | `PG_` | `PG_Patient{功能名}` | `PG_PatientHome` | +| 页面浏览(医生端) | `PG_` | `PG_Doctor{功能名}` | `PG_DoctorHome` | +| 点击事件(患者端) | `BTN_` | `BTN_Patient{功能名}{操作}` | `BTN_PatientHomeNextVisit` | +| 点击事件(医生端) | `BTN_` | `BTN_Doctor{功能名}{操作}` | `BTN_DoctorHomeInvite` | + +## 埋点示例 + +### 患者端页面访问埋点 + +```ts +// 页面级 PV +app.waitLogin().then(() => { + app.mpBehavior({ PageName: 'PG_PatientHome' }) +}) + +// 详情页带 detailId +app.waitLogin().then(() => { + app.mpBehavior({ PageName: 'PG_PatientDoctorDetail', detailId: options.id }) +}) +``` + +### 医生端页面访问埋点 + +```ts +app.waitLogin().then(() => { + app.mpBehavior({ doctor: true, PageName: 'PG_DoctorHome' }) +}) +``` + +### 患者端点击埋点 + +```ts +handleNextVisit() { + app.mpBehavior({ PageName: 'BTN_PatientHomeNextVisit' }) + // ... 业务逻辑 +} +``` + +### 医生端点击埋点 + +```ts +handleInvite() { + app.mpBehavior({ doctor: true, PageName: 'BTN_DoctorHomeInvite' }) + // ... 业务逻辑 +} +``` + +### 全局访问埋点 + +```ts +// app.ts onShow 中,记录小程序整体打开事件 +app.mpBehavior({ PageName: 'MINI_PROGRAM_VISIT' }) +``` + +## 页面级埋点(PG_) + +### 患者端 + +| 页面路径 | 页面名称 | PageName | detailId | +|---------|---------|----------|----------| +| pages/index/index | 首页 | `PG_PatientHome` | - | +| gift/pages/recordList/index | 就诊记录列表页 | `PG_PatientRecordList` | - | +| gift/pages/record/index | 就诊记录新增页 | `PG_PatientRecordAdd` | - | +| gift/pages/recordDetail/index | 就诊记录详情页 | `PG_PatientRecordDetail` | `options.id` | +| pages/interactivePatient/index | 医患互动页 | `PG_PatientInteractive` | - | +| pages/doctorDetail/index | 医生详情页 | `PG_PatientDoctorDetail` | `options.id` | +| pages/repository/index | 知识库 | `PG_PatientRepository` | - | +| pages/repositoryDetail/index | 知识库详情页 | `PG_PatientRepositoryDetail` | `id` | +| pages/my/index | 我的 | `PG_PatientMy` | - | +| pages/qaFormDetail/index | 健康档案页 | `PG_PatientQaFormDetail` | - | +| pages/qaForm/index | 健康档案编辑页 | `PG_PatientQaForm` | - | +| pages/caseReport/index | 病例报告页 | `PG_PatientCaseReport` | - | +| pages/personalInformation/index | 个人信息页 | `PG_PatientPersonalInfo` | - | +| pages/cancellation/index | 注销账号页 | `PG_PatientCancellation` | - | +| pages/mySave/index | 我的收藏页 | `PG_PatientMySave` | - | +| pages/feedback/index | 问题反馈页 | `PG_PatientFeedback` | - | + +### 医生端 + +| 页面路径 | 页面名称 | PageName | detailId | +|---------|---------|----------|----------| +| doctor/pages/d_home/index | 首页 | `PG_DoctorHome` | - | +| doctor/pages/d_invite/index | 邀约患者页 | `PG_DoctorInvite` | - | +| doctor/pages/d_patient/index | 患者列表页 | `PG_DoctorPatient` | - | +| doctor/pages/d_patientDetail/index | 患者详情页 | `PG_DoctorPatientDetail` | `this.data.id` | +| doctor/pages/d_taskList/index | 群发列表页 | `PG_DoctorTaskList` | - | +| doctor/pages/d_taskDetail/index | 群发详情页 | `PG_DoctorTaskDetail` | `this.data.id` | +| doctor/pages/d_createTask/index | 群发新增页 | `PG_DoctorCreateTask` | - | +| doctor/pages/d_interactive/index | 互动列表页 | `PG_DoctorInteractive` | - | +| doctor/pages/d_interactiveDoctor/index | 互动页 | `PG_DoctorInteractiveDoctor` | `this.data.patientId` | +| doctor/pages/d_my/index | 我的 | `PG_DoctorMy` | - | +| doctor/pages/d_userInfo/index | 个人信息页 | `PG_DoctorUserInfo` | - | +| doctor/pages/d_changeDoctor/index | 切换医生页 | `PG_DoctorChangeDoctor` | - | + +## 点击级埋点(BTN_) + +### 患者端 + +#### 首页(pages/index/index) + +| 方法 | PageName | 说明 | +|------|----------|------| +| `routerTo(e)` | `BTN_PatientHomeFunctionCard` | 功能卡片跳转 | +| `handleNextVisit()` | `BTN_PatientHomeNextVisit` | 下次复诊入口 | +| `handleArticleView(e)` | `BTN_PatientHomeArticle` | 文章点击 | +| `handleArticleSave(e)` | `BTN_PatientHomeArticleSave` | 文章收藏 | +| `handleToastOk()` | `BTN_PatientHomeBindDoctor` | 绑定医生弹窗确认 | +| `handlePublic()` | `BTN_PatientHomeFollowPublic` | 关注公众号 | + +#### 我的(pages/my/index) + +| 方法 | PageName | 说明 | +|------|----------|------| +| `routerVipTo()` | `BTN_PatientMyVip` | VIP 认证入口 | +| `handleMyHealthRecord(e)` | `BTN_PatientMyHealthRecord` | 健康档案 | +| `handleQaForm()` | `BTN_PatientMyQaForm` | 健康问卷 | +| `routerTo(e)` → mySave | `BTN_PatientMySave` | 我的收藏 | +| `routerTo(e)` → personalInfo | `BTN_PatientMyPersonalInfo` | 个人信息 | +| `handleMiniDoctor()` | `BTN_PatientMyMiniDoctor` | 迷你医生 | +| `handleFeedback()` | `BTN_PatientMyFeedback` | 问题反馈 | + +#### 医患互动(pages/interactivePatient/index) + +| 方法 | PageName | 说明 | +|------|----------|------| +| `handleHot(e)` | `BTN_PatientInteractiveHotQuestion` | 热门问题点击 | +| `handleQuestion(e)` | `BTN_PatientInteractiveQuestion` | 快捷问题点击 | +| `handleConfirm()` | `BTN_PatientInteractiveSend` | 发送消息 | +| `handleAdl()` | `BTN_PatientInteractiveAdl` | ADL 评估入口 | +| `handleQol()` | `BTN_PatientInteractiveQol` | QoL 入口 | +| `handleDoctorDetail()` | `BTN_PatientInteractiveDoctorDetail` | 查看医生详情 | + +#### 知识库(pages/repository/index) + +| 方法 | PageName | 说明 | +|------|----------|------| +| `tabChange(e)` | `BTN_PatientRepositoryTab` | Tab 切换 | +| `handleSearch()` | `BTN_PatientRepositorySearch` | 搜索 | +| `handleCate(e)` | `BTN_PatientRepositoryCategory` | 分类筛选 | +| `handleDetail(e)` | `BTN_PatientRepositoryArticle` | 文章详情 | +| `handleStar(e)` | `BTN_PatientRepositoryStar` | 点赞 | +| `handleToggleSave(e)` | `BTN_PatientRepositorySave` | 收藏 | + +#### 就诊记录列表(gift/pages/recordList/index) + +| 方法 | PageName | 说明 | +|------|----------|------| +| `handleAdd()` | `BTN_PatientRecordListAdd` | 新增记录 | +| `handleDetail(e)` | `BTN_PatientRecordListItem` | 记录列表项 | + +#### 就诊记录新增(gift/pages/record/index) + +| 方法 | PageName | 说明 | +|------|----------|------| +| `handleSubmit()` | `BTN_PatientRecordAddSubmit` | 保存记录 | + +### 医生端 + +#### 医生首页(doctor/pages/d_home/index) + +| 方法 | PageName | 说明 | +|------|----------|------| +| `handlePatient(e)` | `BTN_DoctorHomePatient` | 患者列表入口 | +| `handleInvite()` | `BTN_DoctorHomeInvite` | 邀约按钮 | +| `handleSelectYear1()` | `BTN_DoctorHomeSelectYear` | 年份筛选 | + +#### 邀约患者(doctor/pages/d_invite/index) + +| 方法 | PageName | 说明 | +|------|----------|------| +| `handleDownload()` | `BTN_DoctorInviteSend` | 发送邀约(海报保存/分享) | + +#### 患者列表(doctor/pages/d_patient/index) + +| 方法 | PageName | 说明 | +|------|----------|------| +| `handleSearch()` | `BTN_DoctorPatientSearch` | 搜索患者 | +| `handleDetail(e)` | `BTN_DoctorPatientItem` | 患者列表项 | + +#### 互动列表(doctor/pages/d_interactive/index) + +| 方法 | PageName | 说明 | +|------|----------|------| +| `handleSearch()` | `BTN_DoctorInteractiveSearch` | 搜索互动 | +| `handleDetail(e)` | `BTN_DoctorInteractiveItem` | 互动列表项 | + +#### 互动页(doctor/pages/d_interactiveDoctor/index) + +| 方法 | PageName | 说明 | +|------|----------|------| +| `handleConfirm()` | `BTN_DoctorInteractiveSend` | 发送消息 | + +#### 群发列表(doctor/pages/d_taskList/index) + +| 方法 | PageName | 说明 | +|------|----------|------| +| `handleCreate()` | `BTN_DoctorTaskListAdd` | 新增群发 | +| `handleDetail(e)` | `BTN_DoctorTaskListItem` | 群发列表项 | + +#### 群发新增(doctor/pages/d_createTask/index) + +| 方法 | PageName | 说明 | +|------|----------|------| +| `handleSubmit()` | `BTN_DoctorCreateTaskSubmit` | 创建群发 | + +#### 切换医生(doctor/pages/d_changeDoctor/index) + +| 方法 | PageName | 说明 | +|------|----------|------| +| `handleSubmit()` | `BTN_DoctorChangeDoctorSelect` | 切换医生选择 | diff --git a/src/api/request.ts b/src/api/request.ts index aa310a1..fe5db74 100644 --- a/src/api/request.ts +++ b/src/api/request.ts @@ -20,7 +20,7 @@ export const request = function ( ...header, }, url: gUrl + url, - method: method, + method, data: { loginState: getApp().globalData.loginState, ...(data as object), diff --git a/src/app.ts b/src/app.ts index a91c519..8426bc9 100644 --- a/src/app.ts +++ b/src/app.ts @@ -411,7 +411,7 @@ App({ callback(res) }) }, - mpBehavior(data: { PageName: string; doctor?: boolean }) { + mpBehavior(data: { PageName: string; doctor?: boolean; detailId?: string }) { let url = '?r=igg4/mp-behavior/add' if (data.doctor) { url = '?r=igg4/doctor/mp-behavior/add' diff --git a/src/doctor/pages/d_changeDoctor/index.ts b/src/doctor/pages/d_changeDoctor/index.ts index b1e4ffc..6c210f6 100644 --- a/src/doctor/pages/d_changeDoctor/index.ts +++ b/src/doctor/pages/d_changeDoctor/index.ts @@ -14,6 +14,9 @@ Page({ timer = null this.setData({ codeText: '发送验证码' }) } + app.waitLogin().then(() => { + app.mpBehavior({ doctor: true, PageName: 'PG_DoctorChangeDoctor' }) + }) }, onUnload() { if (timer) { @@ -67,6 +70,7 @@ Page({ }) }, handleSubmit() { + app.mpBehavior({ doctor: true, PageName: 'BTN_DoctorChangeDoctorSelect' }) if (!this.data.mobile) { wx.showToast({ icon: 'none', diff --git a/src/doctor/pages/d_createTask/index.ts b/src/doctor/pages/d_createTask/index.ts index ca2ed55..3b351d9 100644 --- a/src/doctor/pages/d_createTask/index.ts +++ b/src/doctor/pages/d_createTask/index.ts @@ -62,6 +62,7 @@ Page({ }) app.waitLogin().then(() => { + app.mpBehavior({ doctor: true, PageName: 'PG_DoctorCreateTask' }) if (this.data.step === 2) { this.getTaskNum() } @@ -245,6 +246,7 @@ Page({ this.handleViewMp() }, handleSubmit() { + app.mpBehavior({ doctor: true, PageName: 'BTN_DoctorCreateTaskSubmit' }) const { SelectAll, ConfirmedIgg4, diff --git a/src/doctor/pages/d_customExport/index.ts b/src/doctor/pages/d_customExport/index.ts index c13ec5b..2464a63 100644 --- a/src/doctor/pages/d_customExport/index.ts +++ b/src/doctor/pages/d_customExport/index.ts @@ -1,4 +1,3 @@ -import dayjs from 'dayjs' const app = getApp() Page({ diff --git a/src/doctor/pages/d_home/index.ts b/src/doctor/pages/d_home/index.ts index 05e1c81..44fc583 100644 --- a/src/doctor/pages/d_home/index.ts +++ b/src/doctor/pages/d_home/index.ts @@ -35,6 +35,7 @@ Page({ } echarts = await require.async('../../../resource/components/echart/echarts.js') app.waitLogin().then((_res) => { + app.mpBehavior({ doctor: true, PageName: 'PG_DoctorHome' }) this.getDoctorInfo() this.getDetail() this.getList1_1() @@ -65,6 +66,7 @@ Page({ }) }, handleSelectYear1() { + app.mpBehavior({ doctor: true, PageName: 'BTN_DoctorHomeSelectYear' }) this.getList1_1() }, getList1_1() { @@ -203,6 +205,7 @@ Page({ } as any) }, handlePatient(e) { + app.mpBehavior({ doctor: true, PageName: 'BTN_DoctorHomePatient' }) const { type, name } = e.currentTarget.dataset wx.navigateTo({ @@ -210,6 +213,7 @@ Page({ }) }, handleInvite() { + app.mpBehavior({ doctor: true, PageName: 'BTN_DoctorHomeInvite' }) wx.navigateTo({ url: '/doctor/pages/d_invite/index', }) diff --git a/src/doctor/pages/d_interactive/index.ts b/src/doctor/pages/d_interactive/index.ts index 760b8e1..c550d91 100644 --- a/src/doctor/pages/d_interactive/index.ts +++ b/src/doctor/pages/d_interactive/index.ts @@ -14,6 +14,7 @@ Page({ }, onShow() { app.waitLogin().then((_res) => { + app.mpBehavior({ doctor: true, PageName: 'PG_DoctorInteractive' }) this.getList() app.setTabbarNoticeMessage() }) @@ -21,6 +22,7 @@ Page({ handleTapSearch() { }, handleSearch() { + app.mpBehavior({ doctor: true, PageName: 'BTN_DoctorInteractiveSearch' }) this.setData({ list: [], pagination: { @@ -67,6 +69,7 @@ Page({ } }, handleDetail(e) { + app.mpBehavior({ doctor: true, PageName: 'BTN_DoctorInteractiveItem' }) const { index } = e.currentTarget.dataset const { list } = this.data const listItem: any = list[index] diff --git a/src/doctor/pages/d_interactiveDoctor/index.ts b/src/doctor/pages/d_interactiveDoctor/index.ts index 239e911..bb1df87 100644 --- a/src/doctor/pages/d_interactiveDoctor/index.ts +++ b/src/doctor/pages/d_interactiveDoctor/index.ts @@ -66,6 +66,7 @@ Page({ }, onShow() { app.waitLogin().then((_res) => { + app.mpBehavior({ doctor: true, PageName: 'PG_DoctorInteractiveDoctor', detailId: this.data.patientId }) this.getDoctorDetail() this.getPatientDetail() this.getMessageList() @@ -332,6 +333,7 @@ Page({ } }, handleConfirm() { + app.mpBehavior({ doctor: true, PageName: 'BTN_DoctorInteractiveSend' }) const { customMessage } = this.data this.handleHideKeyboard() this.handleSendCustomMessage(customMessage) diff --git a/src/doctor/pages/d_invite/index.ts b/src/doctor/pages/d_invite/index.ts index 5efba41..a4b9dae 100644 --- a/src/doctor/pages/d_invite/index.ts +++ b/src/doctor/pages/d_invite/index.ts @@ -18,6 +18,7 @@ Page({ }) } app.waitLogin().then((_res) => { + app.mpBehavior({ doctor: true, PageName: 'PG_DoctorInvite' }) wx.showLoading({ title: '加载中', }) @@ -57,6 +58,7 @@ Page({ }) }, handleDownload() { + app.mpBehavior({ doctor: true, PageName: 'BTN_DoctorInviteSend' }) wx.showToast({ title: '请长按海报图片进行保存', icon: 'none', diff --git a/src/doctor/pages/d_my/index.ts b/src/doctor/pages/d_my/index.ts index 998767a..5e7a161 100644 --- a/src/doctor/pages/d_my/index.ts +++ b/src/doctor/pages/d_my/index.ts @@ -20,6 +20,7 @@ Page({ }, onShow() { app.waitLogin().then((_res) => { + app.mpBehavior({ doctor: true, PageName: 'PG_DoctorMy' }) this.getDetail() }) }, diff --git a/src/doctor/pages/d_patient/index.ts b/src/doctor/pages/d_patient/index.ts index bfb149f..423e6e2 100644 --- a/src/doctor/pages/d_patient/index.ts +++ b/src/doctor/pages/d_patient/index.ts @@ -57,6 +57,7 @@ Page({ IsThisWeekAdl: Number(options.IsThisWeekAdl || ''), }) app.waitLogin().then((_res) => { + app.mpBehavior({ doctor: true, PageName: 'PG_DoctorPatient' }) this.getList() }) }, @@ -105,6 +106,7 @@ Page({ this.handleSearch() }, handleSearch() { + app.mpBehavior({ doctor: true, PageName: 'BTN_DoctorPatientSearch' }) this.getList() }, getList(newPage = 1) { @@ -180,6 +182,7 @@ Page({ }) }, handleDetail(e: any) { + app.mpBehavior({ doctor: true, PageName: 'BTN_DoctorPatientItem' }) const { index } = e.currentTarget.dataset const item = this.data.list[index] diff --git a/src/doctor/pages/d_patientDetail/index.ts b/src/doctor/pages/d_patientDetail/index.ts index 29a28f6..c829be6 100644 --- a/src/doctor/pages/d_patientDetail/index.ts +++ b/src/doctor/pages/d_patientDetail/index.ts @@ -189,6 +189,7 @@ Page({ echarts = await require.async('../../../resource/components/echart/echarts.js') this.ecDataTrendComponent = this.selectComponent('#chart1') app.waitLogin().then(async (_res) => { + app.mpBehavior({ doctor: true, PageName: 'PG_DoctorPatientDetail', detailId: this.data.id }) this.getDoctorDetail() await this.getDetail() this.getIndicatorHistory() diff --git a/src/doctor/pages/d_taskDetail/index.ts b/src/doctor/pages/d_taskDetail/index.ts index 2ff85df..3195a05 100644 --- a/src/doctor/pages/d_taskDetail/index.ts +++ b/src/doctor/pages/d_taskDetail/index.ts @@ -39,6 +39,7 @@ Page({ id: options.id, }) app.waitLogin().then(() => { + app.mpBehavior({ doctor: true, PageName: 'PG_DoctorTaskDetail', detailId: this.data.id }) this.getDetail() }) }, diff --git a/src/doctor/pages/d_taskList/index.ts b/src/doctor/pages/d_taskList/index.ts index 1f914b9..5768b3b 100644 --- a/src/doctor/pages/d_taskList/index.ts +++ b/src/doctor/pages/d_taskList/index.ts @@ -47,6 +47,7 @@ Page({ }, onShow() { app.waitLogin().then(() => { + app.mpBehavior({ doctor: true, PageName: 'PG_DoctorTaskList' }) this.getList() }) }, @@ -96,11 +97,13 @@ Page({ }) }, handleCreate() { + app.mpBehavior({ doctor: true, PageName: 'BTN_DoctorTaskListAdd' }) wx.navigateTo({ url: '/doctor/pages/d_createTask/index', }) }, handleDetail(e) { + app.mpBehavior({ doctor: true, PageName: 'BTN_DoctorTaskListItem' }) const { id } = e.currentTarget.dataset wx.navigateTo({ url: `/doctor/pages/d_taskDetail/index?id=${id}`, diff --git a/src/doctor/pages/d_userInfo/index.ts b/src/doctor/pages/d_userInfo/index.ts index dcc2208..18710c4 100644 --- a/src/doctor/pages/d_userInfo/index.ts +++ b/src/doctor/pages/d_userInfo/index.ts @@ -57,6 +57,7 @@ Page({ onLoad() {}, onShow() { app.waitLogin().then((_res) => { + app.mpBehavior({ doctor: true, PageName: 'PG_DoctorUserInfo' }) this.getDetail() }) }, diff --git a/src/gift/pages/record/index.ts b/src/gift/pages/record/index.ts index 52bb5e7..242ad3f 100644 --- a/src/gift/pages/record/index.ts +++ b/src/gift/pages/record/index.ts @@ -76,6 +76,9 @@ Page({ _saveDraftDebounced: null as any, onLoad(options: any) { + _app.waitLogin().then(() => { + _app.mpBehavior({ PageName: 'PG_PatientRecordAdd' }) + }) if (options.id) { this.setData({ draftId: Number(options.id) }) _app.waitLogin().then(() => { @@ -418,6 +421,7 @@ Page({ }, handleSubmit() { + _app.mpBehavior({ PageName: 'BTN_PatientRecordAddSubmit' }) const hasData = this.data.igG4Value || this.data.medicationsUsed.length || diff --git a/src/gift/pages/recordDetail/index.ts b/src/gift/pages/recordDetail/index.ts index 0689e73..e993c98 100644 --- a/src/gift/pages/recordDetail/index.ts +++ b/src/gift/pages/recordDetail/index.ts @@ -27,6 +27,8 @@ const IMAGE_TYPE_LABELS: Record = { immuneFunction: '外周血免疫功能评估', } +const app = getApp() + Page({ data: { id: 0, @@ -41,6 +43,9 @@ Page({ }, onLoad(options: any) { + app.waitLogin().then(() => { + app.mpBehavior({ PageName: 'PG_PatientRecordDetail', detailId: String(options.id) }) + }) if (options.id) { this.setData({ id: Number(options.id) }) this.getDetail() diff --git a/src/gift/pages/recordList/index.ts b/src/gift/pages/recordList/index.ts index 6524e4b..3072446 100644 --- a/src/gift/pages/recordList/index.ts +++ b/src/gift/pages/recordList/index.ts @@ -59,6 +59,7 @@ Page({ echarts = mod }) _app.waitLogin().then(() => { + _app.mpBehavior({ PageName: 'PG_PatientRecordList' }) this.getLatestRecord() this.getList() this.getIndicatorHistory() @@ -324,6 +325,7 @@ Page({ // ========== 导航 ========== handleDetail(e: any) { + _app.mpBehavior({ PageName: 'BTN_PatientRecordListItem' }) const { id, status } = e.currentTarget.dataset if (status === 1) { wx.navigateTo({ url: `/gift/pages/record/index?id=${id}` }) @@ -333,6 +335,7 @@ Page({ }, handleAdd() { + _app.mpBehavior({ PageName: 'BTN_PatientRecordListAdd' }) wx.navigateTo({ url: '/gift/pages/record/index' }) }, diff --git a/src/images/avatar1.png b/src/images/avatar1.png new file mode 100644 index 0000000000000000000000000000000000000000..de4450dabec3ae84cc16d70a297ecbc0640a5b1f GIT binary patch literal 6769 zcmV-%8jj_OP)8K#UD*`)4g2+7DG$PHhyy>zDPceqSsZkJzxQ>7!+_0)@>o$nF6OHZ~cixf;}Z92}BHc{-YEVGtQ?g=Rg6c zV1zqkc4s82B4+_-eM>0XG9bkMM2a~xzJHCmvKtCGK_X0s5VLxoD^th`dM{uj-t&?#T)6B-q1!e^ z5m%;=rN;s`!i5+i-n39Tt|GrJqmQH_!vQD$P$=Y7dM998RfcfWic@h>>R*ImvMj`<;I;5u&pq^Bko)l$1VxO<-UPx^kqqR<4)wp!3)@k7u97{nOzlT zx^BNg&lqm(YCEA)jlB4}1Wd33&M8#UbxD#eHx9bM6{LV|$P8z76{?U2qcud=B}uY! z<6uMT-~?=|%>OEbAu}t?qzIo%RH@cOG9lhCjEH9?Ac7LG9Z_}O@hybRzYq?{AjNG6x@lneUQ1NXv`87O|HCHsXai5jJb_VofTD zm-#NK1Bmz6GWe7UZ$<2#fUS7pyt+-qVijqM%QDz6#>lNJzDFU3oI#T8Ds+G1+Of$i`}ikF0j%ZWFP$XwGqr3Kmwp($Px zD!4}V`1^QCr^abqz;;%VPX2L>;w7PgNi-MKvBUP-Zj?p^Z0GapDS;Rsc}WNf3k)ne zs*as8*Z7;#AdLywKJi{p#)lLCTnGsd4C!@Es`*EAt-mS_(TIQ(4;D+pSw$ptViD`{ z`Hi)gY8P-u#rcv@yd->Z4gX9XiwAntUYQ=3`aw?MsyK5penmWA7g>8Dvix22^^5h* zJ=ku#{o`ZNeqwv{_3jT&^W#q&kB#z;lN6J|1(mb^a*e<%Ri&pVs>tsk)jaVP8 z8o`?V(wcewy$r>q`Sd4D4EBogi+wvHag(9Jb&ZFtB?XJ3)>55|$JZucn*+FtRuu0L zEI$`nFruA*HoRb6zY{CFJ+iAl?KEQEZ^V3PH^n?8aA7RZlbqym-e}=gT_d$>3!=<_ z`rl=1=!``Fm%_Za6mZ&aSB%qsCyfF}p57($gIz+(0rCDywyrxpZv^~XsexJqoU(p1 zSCA~hx8~!&x4fChwgp`I$Q}y0Bv?HD19hyHrD`h|u$^M{Q*{_Eq)S3_Sv2A7HzwFx zt0+va3JSS2mu0Ykg=K0VNQG3|MoO&VoCJctC?pdUrvCI;-+^37uO ze}_>7$N7e@n!QXzkXz8}n zX(`Dt4t(D6AEEmy5I&L!yceuW4*>DH26vQl;Zg#2xG(+_Zwc7~9H&oJ=RELUJnV5T zAcK)zxU2(f_dP3g-vQ{pgPKw2!~}*taM)m*0ZAfrh|%f2&;~?z}xEe z;i6-ti#o6#>P7c;zz{K?1-h^c*QB6AE}Sc1J7-b<^2$~e=n{)`mt1(0OGQVtGeufT zMI2aLx$ADxd!9aL_*?`OvlvD@fu{6ag4~u;5drJg5p!P$OB{7on5P|BN~k7uWSbjC zXA0OBuXO8(?(2ZVCX2(HT`H(8Z5h~+SIo+DU>2_mvP@Sg3~L3cK)ff_v6-wN$P=(` zD6@FwAo(m_k`LZ1PBTnJx0Ft06|+(WY)4+{#p)P7J6NWpl%@+y>ed7_rpHImq@A4Q zz^^%eF>%1^b9p!}IukuUI#qj40b9$~;q%)e0(HA9kITCg4Nr^^b%Q(j+>Jc1|%I z5U?G*!Rj+1?J`h}b`9!qIq(U`FCv6AkDezyqfc-NSjXDugb>mO+B~xz*iIds&iN%o zF|l1pNhYd%w0w8bdGJBqPSS6qOT2tYcMjXfgp_1E1zZGZPaEh=^2N5SZwhFY&T7xsm7cT{DV{0v7I&cBtz`P)fgZGLzy~1b> zP9^i;qyryRCms{#zlGriSsaGXrGN&th+kHtx48~l^u%J4!PE{R1>t*D8ePbGxk^q_ zz`Fl?Tu5Q|m3}Z}f8l#onq%tqORXjayf^2ENCx|MFb^&Q-Xl72X|xt!)~YrHY?ETW zcpVE^CD~7B$z}h9kn-qy)XPFv?7*%97AeWW-9mEs!7d@gaX`J^aN%uP-z4Q=7@ZB; zZ494>#u-M(0_NJ!74bv5a4JXGlpF;u;0?{Dh0t{1AvrWj7k07XzN`_9f{v262v}F3 z4+L=J4{04HJiJR)%6BYT8c z5RuS*M+OyyE!u>3@wQUHHE?J*$43LW?;)lXRiWR>y%4Z2EwENt5y$sR@A>;zgjB~s zB^m_d=Ykf}2!_s;qOYc%bl{pfvA3Ut7mz-%?^`+g9o=wXJvx;+aK*g7 zuV2gV;BP(ocS5R1YjeU?#9|M)V(>1X+}DrR5-RY>dl@>{f-{6B4S0%q5)MlhWYYeN0$vB-;#JeD*LnHQ*y0~|Mv0V*t5wGZ!| z9&mIr%8mbQ^5WGO;x!1FU!UU28oodQdjg#7tjUY-E{i-|_OHOTG0%B2a^7)HmGlM* z*fU}`zV}pQ?wPa>h3hvIu!q2n5vF1?z_-SYAFnkZT2r`TKmmIUgpA1$CnR#?N2_LA zliC=!4;{megE?*(P{4tJC26odH@WeW5%J=8W^cCT=Q0uyEW~>Uwj{l83JE>5$%)2gGS)$_!`39xt)RyjCu8Xi4NQW_StZk zk1gpRY{L^04$JEGDg^vQ9h?_Jh>vIiuR*|TIVTZ9JOu(?RmUh`Li|KW$4^`WW(ZA) zpJ;8a#%-h|bl{3XODAsgU=LQmmrfDSNF$r zQO~+hOYK&KHrF+V&_e>Jom+{uv` zM9kGG9mH z7~BZ)zG6E#K_RDbN4?&NoMQnm$W{U4WKL+1C{)IrTsm$u#6re%l`tQfMX#64sn=Ts zyr{m(Ua(=&E(qrJd2$vtSq1Gz6 zaUw@vc^<9Y*>gAkTD=|!p_BBsm4w2|jla=#ed1elBVAaHo-Nhm+<4ygI-X8AmveG2 zK*)wio>090fzRanqe#p>MVsoTfK53Xqp^}<^s@BKh3`I%!ZjAE`~{!Q?I%%s(=!Gt z&{nfsCiLqt`nL20i1$8+uLJ`MTs;%97VygmIVs?KIX~1%DBdvXnTQJsSdWSRi*y`{ zH*9(&;v4Gq{rHP*u7eh+zO$D%#oG;fAYxZNYS4ilg)EVd7P2t1isJ1K@t}{6qQmF8 zxPS%ps+6a89csmEG)1xkO?&XoFbACy1#FG<9Kls1J&VZ71pJg+YbUbYBAIo&{Nv{#3o5O%9(-lJ$UZE!fW_AQrjU zI*}+B4zMDfTYZkn67Z}9T#aVge3FMj>So_&E zcq2)k1B2`8wbue(ebL!@p=1OQMh8%hzM@`V&HI5O0=}kRqeta!F^l3QX*~A3t*DDv z;C|i@@8V>B`(;Mi(B#jk+uZ_~h ztC&Ipw#6)+On)LCLIIOBJa%9m(az-+uVRWiFwnU$<_UY%QbLh}>s^sFaBX;4$a1;w zbty<;0h>F*tPDOs$*X}K%gldC4r~6+PSWnXlr{27Q^tXT{>2y{?Tri5eMugkrC2Wa z&21eeDJx)v(RyHqH!e&8lfck*q*Cq+N(tDulyrRVjSC09gbHZ@kFF88ub$yo%6&mu z2L@idFd>03Qtlg5TEHnTj3HoN_Js-YkdbrWm|+|kBE~fF z46LHp>KN(mV?szK+ef+Ls{wNfDsf*h^q*tz7<#lwt7D`mwhJMd>=~D~`Hgx#wEKcl z???L1f&WNr1+A%_LP#dN+ZFKVGFU76SVmwZ0oyUsv+6JkTCKE|#!U!4wL=JT0{0zn zFU^8*^?YBjVqZyuG@hXR+Sg-{wH(!qA`w8TSjO-!^?frbYD zQyoL$>i1FsRsKo(4&#dX8{zm~wv@;w=uRBjBW0s(9&~;TM4D%!YzJa z#50aew&uPFo%MLZtS z?KtWGRfqA1v@*={#9rpZeFmRBu7Q?th0Y(PJ)~?{Di17DLTTj3tqkyZeTq)pNAQ{B zvu_Dp>$)cNrP0QMR7@?If%%W(Kd?(?UG(! zU&mYcQ?n(zZ_{S`rP*5P)~-m)o4%ql@m4&M$wf(8~ zKdkRMt>wc2A1uPEv(vUO$jJ}EgU=MA#b=7owngy*SKfQIF7blegG%GX7tHRAI{cp5 z-VzUhD`PcFEOy3aY5fOj5W-~Kd@*^YWx*zacy;J}&8CyJ(Zt*gl+9<%mMkg2g^!u- zl(Y;kfQgA#huM+vLBDq(@0E&MMlNcQG zO8|D(k{;x7SGXV^36IMXUAsxH)z$A!qwyM^t;*@Ov~Y|fCZT|u&cN)ux+~5u+A6|- zB!iP4F#OEh2Zs}4akYzLT2xaRcQqKtO8ryLOAWpi&>>6Nl<0R!gH>W87stG^}Se?M(__CF+zrb-;}|T zTYv?wegoIVc;?R>-$Td@;a-=3>BQ55azbjlaX-m&T^#!;#E@CjsmFa~RH*@T<9?9k zx*(VqQ4u=#ygoY_;vGqMV~F^IkS>x|VFoBv{ZD9B<~%z2z|EWj7l4p4DdMP*E)YN3 zdY*{i29) zH=e!K<#5?W?*trUgp9s09GOD)7v!*?nC*9xF5Hdh@EYOXkRH-o0mqaOGPXB_G(lcf z8T2O4&7$`LjwvYQxQ~2F=*m?Chs6Mk&t-5;sw5l2HQV(rwuQ<<0V@g$8PJuh0d9-j z7H*sMoaiNcE`^(b0#3mS83RG`oEG25xu{+r6H){S5rWMsO2wc!b-l@lW`_g?oP!ba zVY53a#heymK5MpfLTA>*qD7cIU*P;%iE`XtRh7#^0T;yfks;{dE6+&!=q?RJjIq}cG(zpJ2^s>uBhj!%6rqZ?byn@Uvvk|? zP{1Q%bLAPkl>uVL&mOm5hn7FzNo)|{-4Z_w(ay`JaOt)~LIGEVodGptw^yaOGbe$N z56Whn3R|1PhO4efB+_}=6zqZ&3yG6Jw6`QGN>Q{GK>^o<4YN;3lsAvsGmgcKu={}B z$H&CJo=lvZMY4c2Cy_vx?eU~wSEN|6DevEk1j}H>>L3vGYG)-9 zE?u?(DBu>b;WmVfP#X>nffuQ4`vk-qJ1l1Y+^1lhhXVG5gs2fBPuZ`15OyrorNr0s z6ssRlzyV;y4H095$fxaoLN>*{({3X9f?rB}4d+C0Y0d7J?AJKHWJJ0o#B2T^RFX*d T*hQZe00000NkvXXu0mjfEZ4;w literal 0 HcmV?d00001 diff --git a/src/pages/cancellation/index.ts b/src/pages/cancellation/index.ts index 511767a..875126a 100644 --- a/src/pages/cancellation/index.ts +++ b/src/pages/cancellation/index.ts @@ -5,9 +5,12 @@ Page({ durgInfo: {}, }, onLoad() { + app.waitLogin().then(() => { + app.mpBehavior({ PageName: 'PG_PatientCancellation' }) + }) const _this = this; const eventChannel = this.getOpenerEventChannel(); - eventChannel.on("durgInfo", function (data) { + eventChannel.on("durgInfo", (data) => { console.log(data); _this.setData({ durgInfo: data, diff --git a/src/pages/caseReport/index.ts b/src/pages/caseReport/index.ts index defa011..dab8e64 100644 --- a/src/pages/caseReport/index.ts +++ b/src/pages/caseReport/index.ts @@ -1,3 +1,5 @@ +const app = getApp() + Page({ data: { imageField: '', @@ -6,6 +8,9 @@ Page({ }, onLoad(options: any) { + app.waitLogin().then(() => { + app.mpBehavior({ PageName: 'PG_PatientCaseReport' }) + }) if (options.name) { wx.setNavigationBarTitle({ title: options.name }) } diff --git a/src/pages/certReslove/index.ts b/src/pages/certReslove/index.ts index f8b86e9..51d2877 100644 --- a/src/pages/certReslove/index.ts +++ b/src/pages/certReslove/index.ts @@ -1,5 +1,5 @@ const app = getApp(); -let timer = null as null | number; +const timer = null as null | number; Page({ data: { diff --git a/src/pages/changeUser/index.ts b/src/pages/changeUser/index.ts index 9cc43a1..6c6d44a 100644 --- a/src/pages/changeUser/index.ts +++ b/src/pages/changeUser/index.ts @@ -32,7 +32,7 @@ Page({ return; } // 验证手机号 - if (!/^(13[0-9]|14[579]|15[0-3,5-9]|16[6]|17[0135678]|18[0-9]|19[89])\d{8}$/.test(mobile)) { + if (!/^(13\d|14[579]|15[0-3,5-9]|166|17[0135-8]|18\d|19[89])\d{8}$/.test(mobile)) { wx.showToast({ title: "手机号格式不正确", icon: "none", @@ -55,7 +55,7 @@ Page({ timer = setInterval(() => { time--; this.setData({ - codeText: time + "s后重新发送", + codeText: `${time }s后重新发送`, }); if (time <= 0) { clearInterval(timer as number); diff --git a/src/pages/doctorDetail/index.ts b/src/pages/doctorDetail/index.ts index 9b18c47..57457bc 100644 --- a/src/pages/doctorDetail/index.ts +++ b/src/pages/doctorDetail/index.ts @@ -23,6 +23,7 @@ Page({ }) } app.waitLogin().then((_res) => { + app.mpBehavior({ PageName: 'PG_PatientDoctorDetail', detailId: options.id }) this.setData({ id: options.id, }) diff --git a/src/pages/doctorDetailBak/index.ts b/src/pages/doctorDetailBak/index.ts index 649565e..faf89ad 100644 --- a/src/pages/doctorDetailBak/index.ts +++ b/src/pages/doctorDetailBak/index.ts @@ -40,7 +40,7 @@ Page({ title: "请求授权当前位置", content: "需要获取您的地理位置,请确认授权", confirmColor: "#cf5375", - success: function (res) { + success (res) { if (res.cancel) { //取消授权 wx.showToast({ @@ -51,7 +51,7 @@ Page({ } else if (res.confirm) { //确定授权,通过wx.openSetting发起授权请求 wx.openSetting({ - success: function (res) { + success (res) { if (res.authSetting["scope.userFuzzyLocation"] == true) { // wx.showToast({ // title: '授权成功', diff --git a/src/pages/familyScan/index.ts b/src/pages/familyScan/index.ts index 84092fe..8d3dc02 100644 --- a/src/pages/familyScan/index.ts +++ b/src/pages/familyScan/index.ts @@ -1,5 +1,4 @@ const app = getApp(); -import { parseScene } from "@/utils/util"; Page({ data: { @@ -40,7 +39,7 @@ Page({ }, loading: true, }).then((res) => { - let RelationType = res.HasSelf == 1 ? "2" : ""; + const RelationType = res.HasSelf == 1 ? "2" : ""; if (!res.PatientId) { if (!this.data.ignoreAgreement) { if (UserType >= 2) { diff --git a/src/pages/feedback/index.ts b/src/pages/feedback/index.ts index 7fed005..33ea295 100644 --- a/src/pages/feedback/index.ts +++ b/src/pages/feedback/index.ts @@ -6,7 +6,11 @@ Page({ toastType: '', toastParams: {}, }, - onLoad() {}, + onLoad() { + _app.waitLogin().then(() => { + _app.mpBehavior({ PageName: 'PG_PatientFeedback' }) + }) + }, handleTel() { // wx.navigateTo({ // url: '/pages/feedbackTel/index', diff --git a/src/pages/getUserInfo/index.ts b/src/pages/getUserInfo/index.ts index 1971e67..828aeb1 100644 --- a/src/pages/getUserInfo/index.ts +++ b/src/pages/getUserInfo/index.ts @@ -12,7 +12,7 @@ Page({ if (SystemInfo) { const { bottom } = SystemInfo.capsulePosition; this.setData({ - bottom: bottom, + bottom, }); } }, @@ -24,17 +24,17 @@ Page({ onChooseAvatar(e) { const { avatarUrl } = e.detail; const that = this; - let url = `${app.globalData.upFileUrl}?r=file-service/upload-img`; + const url = `${app.globalData.upFileUrl}?r=file-service/upload-img`; wx.showLoading({ title: "上传中", }); wx.uploadFile({ - url: url, + url, filePath: avatarUrl, name: "file", success(res) { - let data = JSON.parse(res.data); - let avatarUrl = data.data.Url; + const data = JSON.parse(res.data); + const avatarUrl = data.data.Url; wx.ajax({ method: "POST", url: "?r=igg4/account/update-user-img", @@ -49,7 +49,7 @@ Page({ icon: "none", }); that.setData({ - ["userInfo.UserImg"]: avatarUrl, + "userInfo.UserImg": avatarUrl, }); }) .catch(() => { diff --git a/src/pages/index/index.ts b/src/pages/index/index.ts index 1e7693b..8b57e94 100644 --- a/src/pages/index/index.ts +++ b/src/pages/index/index.ts @@ -62,6 +62,7 @@ Page({ }, onShow() { app.waitLogin({}).then(() => { + app.mpBehavior({ PageName: 'PG_PatientHome' }) this.setData({ anyWhere: app.globalData.anyWhere, }) @@ -328,6 +329,7 @@ Page({ }) }, routerTo(e) { + app.mpBehavior({ PageName: 'BTN_PatientHomeFunctionCard' }) let { url, active, code } = e.currentTarget.dataset if (!url) return @@ -352,6 +354,7 @@ Page({ }) }, handleNextVisit() { + app.mpBehavior({ PageName: 'BTN_PatientHomeNextVisit' }) const nextVisitDays = this.data.nextVisitDays app.permissionVerification(3, 0, '').then(() => { wx.navigateTo({ @@ -385,6 +388,7 @@ Page({ handleToastOk() { const { toastType } = this.data if (toastType === 'dedicatedDoctor' || toastType === 'recommendBindDoctor') { + app.mpBehavior({ PageName: 'BTN_PatientHomeBindDoctor' }) wx.ajax({ method: 'POST', url: '?r=igg4/popup/close-popup', @@ -426,12 +430,14 @@ Page({ }) }, handleArticleView(e: any) { + app.mpBehavior({ PageName: 'BTN_PatientHomeArticle' }) const { id } = e.currentTarget.dataset wx.navigateTo({ url: `/pages/repositoryDetail/index?id=${id}`, }) }, handleArticleSave(e: any) { + app.mpBehavior({ PageName: 'BTN_PatientHomeArticleSave' }) const { id, saved } = e.currentTarget.dataset const url = saved ? '?r=igg4/pic-text/cancel-collection' : '?r=igg4/pic-text/collection' app.permissionVerification(3, 3, `/pages/index/index`, id).then(() => { @@ -456,6 +462,7 @@ Page({ }) }, handlePublic() { + app.mpBehavior({ PageName: 'BTN_PatientHomeFollowPublic' }) this.setData({ toastShow: true, toastType: 'public-toast', diff --git a/src/pages/interactivePatient/index.ts b/src/pages/interactivePatient/index.ts index b6942ae..412656f 100644 --- a/src/pages/interactivePatient/index.ts +++ b/src/pages/interactivePatient/index.ts @@ -65,6 +65,7 @@ Page({ this.setData({ pageTop }) app.waitLogin({}).then(() => { + app.mpBehavior({ PageName: 'PG_PatientInteractive' }) this.getDoctorDetail() this.getQuestionList() this.getMessageList() @@ -165,6 +166,7 @@ Page({ } }, handleHot(e) { + app.mpBehavior({ PageName: 'BTN_PatientInteractiveHotQuestion' }) if (this.data.sending) return const { index, mindex } = e.currentTarget.dataset const { messageList } = this.data @@ -188,6 +190,7 @@ Page({ this.sendQuestion(hot?.questionId) }, handleQuestion(e) { + app.mpBehavior({ PageName: 'BTN_PatientInteractiveQuestion' }) if (this.data.sending) return const { index } = e.currentTarget.dataset const { questionActiveList, messageList } = this.data @@ -280,6 +283,7 @@ Page({ }) }, handleDoctorDetail() { + app.mpBehavior({ PageName: 'BTN_PatientInteractiveDoctorDetail' }) const { doctorId } = this.data.doctorDetail wx.navigateTo({ url: `/pages/doctorDetail/index?id=${doctorId}`, @@ -352,6 +356,7 @@ Page({ this.handleSendCustomMessage(message) }, handleConfirm() { + app.mpBehavior({ PageName: 'BTN_PatientInteractiveSend' }) const { customMessage } = this.data this.handleFooter() this.handleSendCustomMessage(customMessage) @@ -408,11 +413,13 @@ Page({ }) }, handleAdl() { + app.mpBehavior({ PageName: 'BTN_PatientInteractiveAdl' }) wx.navigateTo({ url: '/pages/adl/index', }) }, handleQol() { + app.mpBehavior({ PageName: 'BTN_PatientInteractiveQol' }) wx.navigateTo({ url: '/pages/qaForm/index', }) diff --git a/src/pages/liveResult/index.ts b/src/pages/liveResult/index.ts index 16c7019..bbd3eb2 100644 --- a/src/pages/liveResult/index.ts +++ b/src/pages/liveResult/index.ts @@ -1,5 +1,5 @@ -const app = getApp(); import dayjs from "dayjs"; +const app = getApp(); let live_time: null | number = null; Page({ diff --git a/src/pages/my/index.ts b/src/pages/my/index.ts index b91b42b..6c54290 100644 --- a/src/pages/my/index.ts +++ b/src/pages/my/index.ts @@ -29,6 +29,7 @@ Page({ }, onShow() { app.waitLogin().then(() => { + app.mpBehavior({ PageName: 'PG_PatientMy' }) app.getUserInfo(this, true, () => {}) this.getScore() }) @@ -45,6 +46,7 @@ Page({ }) }, handleMyHealthRecord(e) { + app.mpBehavior({ PageName: 'BTN_PatientMyHealthRecord' }) const { url } = e.currentTarget.dataset app.permissionVerification(3, 0, url).then(() => { wx.navigateTo({ @@ -73,6 +75,11 @@ Page({ }, routerTo(e) { const { url } = e.currentTarget.dataset + if (url?.includes('mySave')) { + app.mpBehavior({ PageName: 'BTN_PatientMySave' }) + } else if (url?.includes('personalInformation')) { + app.mpBehavior({ PageName: 'BTN_PatientMyPersonalInfo' }) + } if (!url) { wx.showToast({ icon: 'none', @@ -84,6 +91,7 @@ Page({ }) }, handleQaForm() { + app.mpBehavior({ PageName: 'BTN_PatientMyQaForm' }) wx.ajax({ method: 'GET', url: '?r=igg4/health-question/get-patient-questionnaire', @@ -103,6 +111,7 @@ Page({ }) }, routerVipTo() { + app.mpBehavior({ PageName: 'BTN_PatientMyVip' }) const { UseDrugsAuditStatus, UserType } = this.data.userInfo if (!UserType) { app.getUserInfo(this, true, () => { @@ -126,11 +135,13 @@ Page({ }, handleMiniDoctor() { + app.mpBehavior({ PageName: 'BTN_PatientMyMiniDoctor' }) wx.navigateTo({ url: '/pages/webview/index', }) }, handleFeedback() { + app.mpBehavior({ PageName: 'BTN_PatientMyFeedback' }) wx.navigateTo({ url: '/pages/feedback/index', }) diff --git a/src/pages/mySave/index.ts b/src/pages/mySave/index.ts index b7bcc0c..b3e71b7 100644 --- a/src/pages/mySave/index.ts +++ b/src/pages/mySave/index.ts @@ -13,6 +13,7 @@ Page({ }, onLoad() { app.waitLogin().then(() => { + app.mpBehavior({ PageName: 'PG_PatientMySave' }) wx.ajax({ method: 'GET', url: '?r=igg4/common/get-config', diff --git a/src/pages/personalInformation/index.ts b/src/pages/personalInformation/index.ts index fe1f1f4..d6adbbb 100644 --- a/src/pages/personalInformation/index.ts +++ b/src/pages/personalInformation/index.ts @@ -31,6 +31,7 @@ Page({ }) app.waitLogin().then(() => { + app.mpBehavior({ PageName: 'PG_PatientPersonalInfo' }) const that = this app.getUserInfo(that, true, that.formatUserInfo.bind(that)) }) diff --git a/src/pages/qaForm/index.ts b/src/pages/qaForm/index.ts index fca0f75..19872b3 100644 --- a/src/pages/qaForm/index.ts +++ b/src/pages/qaForm/index.ts @@ -41,6 +41,7 @@ Page({ backPage: options.backPage || '', }) app.waitLogin({}).then(() => { + app.mpBehavior({ PageName: 'PG_PatientQaForm' }) this.loadQuestionnaire() }) }, diff --git a/src/pages/qaFormDetail/index.ts b/src/pages/qaFormDetail/index.ts index 8e04c50..1044fdc 100644 --- a/src/pages/qaFormDetail/index.ts +++ b/src/pages/qaFormDetail/index.ts @@ -65,6 +65,7 @@ Page({ onLoad() { app.waitLogin({}).then(() => { + app.mpBehavior({ PageName: 'PG_PatientQaFormDetail' }) this.loadData() }) }, diff --git a/src/pages/repository/index.ts b/src/pages/repository/index.ts index 8048d28..76279f6 100644 --- a/src/pages/repository/index.ts +++ b/src/pages/repository/index.ts @@ -18,6 +18,7 @@ Page({ }, onLoad(options) { app.waitLogin().then(() => { + app.mpBehavior({ PageName: 'PG_PatientRepository' }) this.getConfig(options) this.getBanner() app.getUserInfo(this, true) @@ -58,6 +59,7 @@ Page({ }) }, tabChange(e) { + app.mpBehavior({ PageName: 'BTN_PatientRepositoryTab' }) const { storyCateId } = this.data this.setData({ active: e.detail.index, @@ -79,6 +81,7 @@ Page({ this.handleSearch() }, handleSearch() { + app.mpBehavior({ PageName: 'BTN_PatientRepositorySearch' }) this.getList() }, getList() { @@ -134,6 +137,7 @@ Page({ }) }, handleStar(e) { + app.mpBehavior({ PageName: 'BTN_PatientRepositoryStar' }) const { id, index } = e.currentTarget.dataset wx.ajax({ method: 'POST', @@ -150,6 +154,7 @@ Page({ }) }, handleCate(e: WechatMiniprogram.CustomEvent) { + app.mpBehavior({ PageName: 'BTN_PatientRepositoryCategory' }) const { id } = e.currentTarget.dataset this.setData({ CateId: id, @@ -157,12 +162,14 @@ Page({ this.getList() }, handleDetail(e: WechatMiniprogram.CustomEvent) { + app.mpBehavior({ PageName: 'BTN_PatientRepositoryArticle' }) const { id } = e.currentTarget.dataset wx.navigateTo({ url: `/pages/repositoryDetail/index?id=${id}`, }) }, handleToggleSave(e: WechatMiniprogram.CustomEvent) { + app.mpBehavior({ PageName: 'BTN_PatientRepositorySave' }) const { id, collect, index } = e.currentTarget.dataset const { list, active } = this.data const title = list[index].Title diff --git a/src/pages/repositoryDetail/index.ts b/src/pages/repositoryDetail/index.ts index 6220312..f7d5f27 100644 --- a/src/pages/repositoryDetail/index.ts +++ b/src/pages/repositoryDetail/index.ts @@ -33,6 +33,7 @@ Page({ id, }) app.waitLogin().then(() => { + app.mpBehavior({ PageName: 'PG_PatientRepositoryDetail', detailId: id }) this.getDetail(true) }) }, diff --git a/src/pages/smallPage/index.ts b/src/pages/smallPage/index.ts index 2910b11..b84501a 100644 --- a/src/pages/smallPage/index.ts +++ b/src/pages/smallPage/index.ts @@ -49,9 +49,9 @@ Page({ }, ], }, - onLoad: function (options) { + onLoad (options) { if (options.scene || app.globalData.newPageId) { - let scene = app.filterUrlParam(decodeURIComponent(options.scene)); + const scene = app.filterUrlParam(decodeURIComponent(options.scene)); console.log(scene.pageId || app.globalData.newPageId); this.setData({ pageId: scene.pageId || app.globalData.newPageId, @@ -83,7 +83,7 @@ Page({ success(res) { const dataInfo = res.data.data; that.setData({ - dataInfo: dataInfo, + dataInfo, }); wx.setNavigationBarTitle({ title: dataInfo.WeiTitle, @@ -100,7 +100,7 @@ Page({ handleSex(e) { const { value } = e.currentTarget.dataset; this.setData({ - ["form.sex"]: value, + "form.sex": value, }); }, handleCllaNo() { diff --git a/src/pages/storyDetail/index.ts b/src/pages/storyDetail/index.ts index 19704b4..b65d3e1 100644 --- a/src/pages/storyDetail/index.ts +++ b/src/pages/storyDetail/index.ts @@ -13,7 +13,7 @@ Page({ if (SystemInfo) { const { bottom } = SystemInfo.capsulePosition; this.setData({ - bottom: bottom, + bottom, }); } this.setData({ @@ -82,7 +82,7 @@ Page({ handleOk() { const id = this.data.detail.Id; const type = this.data.toastType; - let url = type === "withdraw" ? "?r=igg4/story/cancel-publish" : "?r=igg4/story/recovery-publish"; + const url = type === "withdraw" ? "?r=igg4/story/cancel-publish" : "?r=igg4/story/recovery-publish"; wx.ajax({ method: "POST", url, diff --git a/src/pages/storyEnterResult/index.ts b/src/pages/storyEnterResult/index.ts index 15e8583..61b4808 100644 --- a/src/pages/storyEnterResult/index.ts +++ b/src/pages/storyEnterResult/index.ts @@ -11,7 +11,7 @@ Page({ if (SystemInfo) { const { bottom } = SystemInfo.capsulePosition; this.setData({ - bottom: bottom, + bottom, }); } this.setData({ diff --git a/src/pages/thePublic/index.ts b/src/pages/thePublic/index.ts index 92d9587..7f94c6e 100644 --- a/src/pages/thePublic/index.ts +++ b/src/pages/thePublic/index.ts @@ -10,7 +10,7 @@ Page({ if (SystemInfo) { const { bottom } = SystemInfo.capsulePosition; this.setData({ - bottom: bottom, + bottom, }); } app.waitLogin().then((_res) => { diff --git a/src/pages/uploadCert/index.ts b/src/pages/uploadCert/index.ts index 110a2ca..90d7a84 100644 --- a/src/pages/uploadCert/index.ts +++ b/src/pages/uploadCert/index.ts @@ -75,7 +75,7 @@ Page({ } else { urlKey = 'reslove' } - let navUrl = { + const navUrl = { reslove: '/pages/certReslove/index', pending: '/pages/certPending/index', nopending: '/pages/startPending/index', @@ -123,7 +123,7 @@ Page({ } else { urlKey = 'reslove' } - let navUrl = { + const navUrl = { reslove: '/pages/certReslove/index', pending: '/pages/certPending/index', nopending: '/pages/startPending/index', diff --git a/src/pages/vipLogin/index.ts b/src/pages/vipLogin/index.ts index 8ae5c72..e83abe2 100644 --- a/src/pages/vipLogin/index.ts +++ b/src/pages/vipLogin/index.ts @@ -33,7 +33,7 @@ Page({ }, bindScanCode(res: WechatMiniprogram.CustomEvent) { const { result } = res.detail; - this.setData({ result: result }); + this.setData({ result }); this.getDurgInfo(result); }, onHide() { @@ -45,7 +45,7 @@ Page({ getDurgInfo(DrugsCode: string) { const that = this; const { registrationSource, registChannel, regBusinessId } = app.globalData; - let scaned = this.data.scaned; + const scaned = this.data.scaned; if (!scaned) { that.setData({ scaned: !0, @@ -69,7 +69,7 @@ Page({ } else { urlKey = "reslove"; } - let navUrl = { + const navUrl = { reslove: "/pages/certReslove/index?drug=1", pending: "/pages/certPending/index", nopending: "/pages/startPending/index", @@ -136,7 +136,7 @@ Page({ }, openSetting() { const _this = this; - let promise = new Promise((resolve) => { + const promise = new Promise((resolve) => { wx.showModal({ title: "授权", content: "请先授权获取摄像头权限", diff --git a/src/pages/vipLoginReject/index.ts b/src/pages/vipLoginReject/index.ts index 4833fb9..c24c937 100644 --- a/src/pages/vipLoginReject/index.ts +++ b/src/pages/vipLoginReject/index.ts @@ -12,7 +12,7 @@ Page({ onLoad() { const _this = this; const eventChannel = this.getOpenerEventChannel(); - eventChannel.on("durgInfo", function (data) { + eventChannel.on("durgInfo", (data) => { _this.setData({ durgInfo: data, }); diff --git a/typings/index.d.ts b/typings/index.d.ts index b7e0f5c..0925b46 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -71,7 +71,7 @@ interface IAppOption { waitLogin: (obj?: { isReg?: boolean; loginPage?: boolean; pub?: boolean }) => Promise startLogin: () => Promise getUserInfo: (self?, update?: boolean, callback?: (userinfo) => void) => void - mpBehavior: (data: { PageName: string; doctor?: boolean }) => void + mpBehavior: (data: { PageName: string; doctor?: boolean; detailId?: string }) => void globalSystemInfo?: globalSystemInfo [propName: string]: any }