diff --git a/api.md b/api.md new file mode 100644 index 0000000..21e7245 --- /dev/null +++ b/api.md @@ -0,0 +1,1398 @@ +# 就诊记录接口文档 + +## 通用说明 + +### 响应格式 + +所有接口返回 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 | 否 | 按就诊年份筛选 | +| count | int | 否 | 取最近 N 次就诊记录 | + +#### 响应示例 + +```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 + +--- + +### 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 | 否 | 按就诊年份筛选 | +| count | int | 否 | 取最近 N 次就诊记录 | + +#### imageField 枚举 + +| 值 | 说明 | +|------|------| +| outpatientRecord | 门诊病历及处方 | +| labReport | 检验报告 | +| imagingExam | 影像学检查 | +| pathology | 病理诊断及活检 | +| immuneFunction | 外周血免疫功能评估 | + +#### 响应示例 + +```json +{ + "code": 0, + "message": "success", + "data": { + "list": [ + { + "visitDate": "2026-06-29", + "imageUrl": "https://...", + "ocrStatus": 2 + }, + { + "visitDate": "2026-03-15", + "imageUrl": "https://...", + "ocrStatus": 0 + } + ] + } +} +``` + +--- + +### 1.7 指标字段历史列表 + +- **路由**:`?r=igg4/medical-visit/indicator-history` +- **请求方式**:GET +- **说明**:查询指定指标字段的历史数据列表,返回每次就诊中该指标的值,按就诊日期降序排列。仅返回已提交的记录。 + +#### 请求参数 + +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| indicatorField | string | 是 | 指标字段标识 | +| year | int | 否 | 按就诊年份筛选 | +| count | int | 否 | 取最近 N 次就诊记录 | + +#### 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 | 否 | 按就诊年份筛选 | +| count | int | 否 | 取最近 N 次就诊记录 | + +#### 响应示例 + +同 [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 | 否 | 按就诊年份筛选 | +| count | int | 否 | 取最近 N 次就诊记录 | + +#### 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 | 否 | 按就诊年份筛选 | +| count | int | 否 | 取最近 N 次就诊记录 | + +#### 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 new file mode 100644 index 0000000..607cff9 --- /dev/null +++ b/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/project.private.config.json b/project.private.config.json index d4b4349..40cb7a4 100644 --- a/project.private.config.json +++ b/project.private.config.json @@ -22,11 +22,18 @@ "miniprogram": { "list": [ { + "name": "就诊记录", + "pathName": "gift/pages/record/index", + "query": "id=15", + "scene": null, + "launchMode": "default" + }, + { "name": "医生-患者详情", "pathName": "doctor/pages/d_patientDetail/index", "query": "id=67", - "scene": null, - "launchMode": "default" + "launchMode": "default", + "scene": null }, { "name": "病例报告", @@ -50,13 +57,6 @@ "scene": null }, { - "name": "就诊记录", - "pathName": "gift/pages/record/index", - "query": "", - "launchMode": "default", - "scene": null - }, - { "name": "医生-新建消息", "pathName": "doctor/pages/d_createTask/index", "query": "", diff --git a/src/components/toast/index.scss b/src/components/toast/index.scss index fccfb40..9205f32 100644 --- a/src/components/toast/index.scss +++ b/src/components/toast/index.scss @@ -2477,21 +2477,29 @@ } .popup-public-toast { .popup-container { - position: relative; - padding: 360rpx 146rpx 0; - width: 590rpx; - height: 880rpx; + padding: 226rpx 0; + width: 630rpx; + height: 864rpx; box-sizing: border-box; + .title { + font-size: 40rpx; + color: rgba(34, 34, 34, 1); + text-align: center; + } .code { - width: 286rpx; - height: 286rpx; + display: block; + width: 310rpx; + height: 310rpx; + margin: 20rpx auto 0; + border: 1px solid rgba(0, 0, 0, 0.03); + border-radius: 22rpx; } } - .close { - margin: 68rpx auto 0; + .clsoe{ display: block; - width: 64rpx; - height: 64rpx; + margin: 52rpx auto 0; + width: 84rpx; + height: 84rpx; } } diff --git a/src/components/toast/index.ts b/src/components/toast/index.ts index 48ed459..0b6d815 100644 --- a/src/components/toast/index.ts +++ b/src/components/toast/index.ts @@ -42,7 +42,7 @@ Component({ if (['storyLead', 'storyStar', 'storyShare'].includes(this.data.type)) { this.getSettingInfo() } - if (this.data.type === 'feedback' || this.data.type === 'doctor-feedback') { + if (this.data.type === 'feedback' || this.data.type === 'doctor-feedback' || this.data.type === 'public-toast') { this.getFeedbackCode() } if (this.data.type === 'follow') { diff --git a/src/components/toast/index.wxml b/src/components/toast/index.wxml index dde66f6..aad9ad2 100644 --- a/src/components/toast/index.wxml +++ b/src/components/toast/index.wxml @@ -718,16 +718,20 @@ bind:tap="handleCancel" > - + - + + 关注「IgG4愈见昕生」公众号 + + 重要提醒不丢失 + + diff --git a/src/doctor/pages/d_createTask/index.scss b/src/doctor/pages/d_createTask/index.scss index 7194283..4f7d626 100644 --- a/src/doctor/pages/d_createTask/index.scss +++ b/src/doctor/pages/d_createTask/index.scss @@ -99,22 +99,29 @@ page { } .select { margin-top: 24rpx; - display: grid; - grid-template-columns: repeat(3, 1fr); + display: flex; + flex-wrap: wrap; gap: 16rpx; .s-item { - padding: 22rpx; + flex: 0 0 auto; + min-width: calc((100% - 44rpx) / 3); + padding: 22rpx 12rpx; text-align: center; border-radius: 12rpx; font-size: 32rpx; color: rgba(34, 34, 34, 0.6); background: rgba(248, 248, 248, 1); border: 1px solid rgba(248, 248, 248, 1); + box-sizing: border-box; &.active { color: rgba(22, 121, 203, 1); background-color: rgba(22, 121, 203, 0.1); border-color: rgba(22, 121, 203, 1); } + &:nth-of-type(4), + &:nth-of-type(5) { + width: 100%; + } } } .custom { @@ -162,7 +169,7 @@ page { .content { font-size: 32rpx; - color: rgba(34, 34, 34, 0.2); + color: rgba(34, 34, 34, 1); &:empty::after { content: attr(data-place); @@ -250,7 +257,7 @@ page { flex: 1; padding: 18rpx; font-size: 32rpx; - color: rgba(34, 34, 34, 0.60); + color: rgba(34, 34, 34, 0.6); text-align: center; background: rgba(248, 248, 248, 1); border-radius: 12rpx 12rpx 12rpx 12rpx; @@ -259,7 +266,7 @@ page { &.active { color: rgba(22, 121, 203, 1); border-color: rgba(22, 121, 203, 1); - background: rgba(22, 121, 203, 0.10); + background: rgba(22, 121, 203, 0.1); } } } diff --git a/src/doctor/pages/d_createTask/index.ts b/src/doctor/pages/d_createTask/index.ts index 56689ad..ade58ee 100644 --- a/src/doctor/pages/d_createTask/index.ts +++ b/src/doctor/pages/d_createTask/index.ts @@ -1,5 +1,4 @@ import dayjs from 'dayjs' -import { filterColumns } from '@/utils/doctorPatientTask' const licia = require('miniprogram-licia') const app = getApp() @@ -7,7 +6,7 @@ Page({ data: { background: 'transparent', - step: 2, + step: 1, TemplateType: 1, templates: [] as any, @@ -25,28 +24,24 @@ Page({ PatientNum: 0, //患者人数 // form - Search: '', - HasAdl: 0, - DoubleStandard: 0, - AdlTime: 0, - AdlScore: [] as any, - AdlScoreChange: [], - AdlScoreChangeType: 0, - AdlScoreChangeMax: '', - AdlScoreChangeMin: '', - SteroidDailyDose: [] as any, - SteroidDailyDoseChange: [] as any, - IsThisWeekAdl: 0, - PharyngealSymptoms: 0, - AntibodyType: 0, - ThyroidAbnormal: 0, - PreviousConvulsion: 0, - TraditionalImmunosuppressant: 0, - MedicalInsuranceType: 0, + SelectAll: 0, + ConfirmedIgg4: 0, + MedicationType: [] as number[], BindStartDate: '', BindEndDate: '', - ...filterColumns, + ConfirmedIgg4Column: [ + { id: 0, value: '全部' }, + { id: 1, value: '是' }, + { id: 2, value: '否' }, + ], + MedicationTypeColumn: [ + { id: 0, value: '全部' }, + { id: 2, value: '激素' }, + { id: 3, value: '免疫抑制剂' }, + { id: 4, value: '靶向CD19生物制剂(伊奈利珠单抗)' }, + { id: 5, value: '靶向CD20生物制剂(利妥昔单抗等)' }, + ], }, onLoad() { const SystemInfo = app.globalSystemInfo @@ -114,26 +109,11 @@ Page({ method: 'GET', url: '?r=igg4/doctor/task/filter-patient-num', data: { - Search: this.data.Search, - HasAdl: this.data.HasAdl, - DoubleStandard: this.data.DoubleStandard, - AdlTime: this.data.AdlTime, - AdlScore: this.data.AdlScore.join('-'), - AdlScoreChange: this.data.AdlScoreChange.join('-'), - AdlScoreChangeType: this.data.AdlScoreChangeType, - AdlScoreChangeMax: this.data.AdlScoreChangeMax, - AdlScoreChangeMin: this.data.AdlScoreChangeMin, - SteroidDailyDose: this.data.SteroidDailyDose.join('-'), - SteroidDailyDoseChange: this.data.SteroidDailyDoseChange.join('-'), - IsThisWeekAdl: this.data.IsThisWeekAdl, - PharyngealSymptoms: this.data.PharyngealSymptoms, - AntibodyType: this.data.AntibodyType, - ThyroidAbnormal: this.data.ThyroidAbnormal, - PreviousConvulsion: this.data.PreviousConvulsion, - TraditionalImmunosuppressant: this.data.TraditionalImmunosuppressant, - MedicalInsuranceType: this.data.MedicalInsuranceType, + SelectAll: this.data.SelectAll, BindStartDate: this.data.BindStartDate, BindEndDate: this.data.BindEndDate, + ConfirmedIgg4: this.data.ConfirmedIgg4, + MedicationType: this.data.MedicationType.join(','), }, loading: true, }) @@ -150,24 +130,9 @@ Page({ success: (res) => { if (res.confirm) { this.setData({ - Search: '', - HasAdl: 0, - DoubleStandard: 0, - AdlTime: 0, - AdlScore: [] as any, - AdlScoreChange: [], - AdlScoreChangeType: 0, - AdlScoreChangeMax: '', - AdlScoreChangeMin: '', - SteroidDailyDose: [] as any, - SteroidDailyDoseChange: [] as any, - IsThisWeekAdl: 0, - PharyngealSymptoms: 0, - AntibodyType: 0, - ThyroidAbnormal: 0, - PreviousConvulsion: 0, - TraditionalImmunosuppressant: 0, - MedicalInsuranceType: 0, + SelectAll: 0, + ConfirmedIgg4: 0, + MedicationType: [], BindStartDate: '', BindEndDate: '', }) @@ -186,14 +151,24 @@ Page({ handleCheckbox(e: any) { const { index, key } = e.currentTarget.dataset const data = this.data[`${key}Column`] + const clickedId = data[index].id const oldValue = this.data[`${key}`] - const value = oldValue.includes(data[index].id) - ? oldValue.filter((item: any) => item !== data[index].id) - : [...oldValue, data[index].id] - this.setData({ - [`${key}`]: data[index].id ? value : [], - }) + if (!clickedId) { + // 点击"全部":清空其他选择 + this.setData({ [`${key}`]: [] }) + return + } + + const value = oldValue.includes(clickedId) + ? oldValue.filter((item: any) => item !== clickedId) + : [...oldValue.filter((item: any) => item !== 0), clickedId] // 选具体选项时移除"全部" + + this.setData({ [`${key}`]: value }) + }, + handleSelectAll() { + this.setData({ SelectAll: this.data.SelectAll === 1 ? 0 : 1 }) + this.getTaskNum() }, handleDay(e) { const { value } = e.currentTarget.dataset @@ -236,33 +211,12 @@ Page({ wx.navigateBack() }, async handleNext() { - const anyValueKeys = [ - 'Search', - 'HasAdl', - 'DoubleStandard', - 'AdlTime', - 'AdlScore', - 'AdlScoreChange', - 'AdlScoreChangeType', - 'AdlScoreChangeMax', - 'AdlScoreChangeMin', - 'SteroidDailyDose', - 'SteroidDailyDoseChange', - 'IsThisWeekAdl', - 'PharyngealSymptoms', - 'AntibodyType', - 'ThyroidAbnormal', - 'PreviousConvulsion', - 'TraditionalImmunosuppressant', - 'MedicalInsuranceType', - 'BindStartDate', - 'BindEndDate', - ] + const anyValueKeys = ['SelectAll', 'ConfirmedIgg4', 'MedicationType', 'BindStartDate', 'BindEndDate'] const empty = anyValueKeys.every((item) => Array.isArray(this.data[item]) ? licia.isEmpty(this.data[item]) : !this.data[item], ) - - if (empty) { + const hasSelectAll = this.data.SelectAll === 1 + if (empty && !hasSelectAll) { wx.showToast({ icon: 'none', title: '请至少选择一个筛选条件', @@ -294,24 +248,9 @@ Page({ }, handleSubmit() { const { - Search, - HasAdl, - DoubleStandard, - AdlTime, - AdlScore, - AdlScoreChange, - AdlScoreChangeType, - AdlScoreChangeMax, - AdlScoreChangeMin, - SteroidDailyDose, - SteroidDailyDoseChange, - IsThisWeekAdl, - PharyngealSymptoms, - AntibodyType, - ThyroidAbnormal, - PreviousConvulsion, - TraditionalImmunosuppressant, - MedicalInsuranceType, + SelectAll, + ConfirmedIgg4, + MedicationType, BindStartDate, BindEndDate, @@ -356,26 +295,11 @@ Page({ if (res.confirm) { const params = { FilterCondition: { - Search, - HasAdl, - DoubleStandard, - AdlTime, - AdlScore: AdlScore.join('-'), - AdlScoreChange: AdlScoreChange.join('-'), - AdlScoreChangeType, - AdlScoreChangeMax, - AdlScoreChangeMin, - SteroidDailyDose: SteroidDailyDose.join('-'), - SteroidDailyDoseChange: SteroidDailyDoseChange.join('-'), - IsThisWeekAdl, - PharyngealSymptoms, - AntibodyType, - ThyroidAbnormal, - PreviousConvulsion, - TraditionalImmunosuppressant, - MedicalInsuranceType, + SelectAll, BindStartDate, BindEndDate, + ConfirmedIgg4, + MedicationType: MedicationType.join(','), }, PushTemplateId, IsSendNow, diff --git a/src/doctor/pages/d_createTask/index.wxml b/src/doctor/pages/d_createTask/index.wxml index 0492f4e..6920904 100644 --- a/src/doctor/pages/d_createTask/index.wxml +++ b/src/doctor/pages/d_createTask/index.wxml @@ -29,7 +29,7 @@ 选择全员 - + @@ -53,13 +53,13 @@ - 确诊IgG4-R + 确诊IgG4-RD @@ -73,9 +73,9 @@ 正在使用的药物 一键生成病历 - + diff --git a/src/doctor/pages/d_taskDetail/index.ts b/src/doctor/pages/d_taskDetail/index.ts index 3a8009b..2ff85df 100644 --- a/src/doctor/pages/d_taskDetail/index.ts +++ b/src/doctor/pages/d_taskDetail/index.ts @@ -1,5 +1,4 @@ import dayjs from 'dayjs' -import { filterObjs } from '@/utils/doctorPatientTask' const app = getApp() @@ -12,39 +11,37 @@ Page({ Status: { 1: '待发送', 2: '发送中', + 3: '暂停', 4: '已发送', 5: '已停止', 6: '已取消', }, - templateObj: {}, - - ...filterObjs, + ConfirmedIgg4Obj: { + 0: '全部', + 1: '是', + 2: '否', + }, + MedicationTypeObj: { + 0: '全部', + 2: '激素', + 3: '免疫抑制剂', + 4: '靶向CD19生物制剂(伊奈利珠单抗)', + 5: '靶向CD20生物制剂(利妥昔单抗等)', + }, + TemplateTypeObj: { + 1: '复诊提醒', + 2: '激素风险提醒', + }, }, onLoad(options) { this.setData({ id: options.id, }) app.waitLogin().then(() => { - this.getTemplate() this.getDetail() }) }, - getTemplate() { - wx.ajax({ - method: 'GET', - url: '?r=igg4/doctor/task/get-template', - data: {}, - }).then((res) => { - const templateObj = {} - res.forEach((item) => { - templateObj[item.TemplateType] = item.TemplateTypeText - }) - this.setData({ - templateObj, - }) - }) - }, getDetail() { wx.ajax({ method: 'GET', @@ -53,33 +50,10 @@ Page({ TaskId: this.data.id, }, }).then((res) => { - if (typeof res.FilterCondition.AdlScore === 'string') { - res.FilterCondition.AdlScore = res.FilterCondition.AdlScore?.split('-') - .map((item) => Number(item)) - .filter((item) => Boolean(item)) - } else { - res.FilterCondition.AdlScore = [] - } - if (typeof res.FilterCondition.AdlScoreChange === 'string') { - res.FilterCondition.AdlScoreChange = res.FilterCondition.AdlScoreChange?.split('-') - .map((item) => Number(item)) - .filter((item) => Boolean(item)) - } else { - res.FilterCondition.AdlScoreChange = [] - } - if (typeof res.FilterCondition.SteroidDailyDose === 'string') { - res.FilterCondition.SteroidDailyDose = res.FilterCondition.SteroidDailyDose?.split('-') - .map((item) => Number(item)) - .filter((item) => Boolean(item)) - } else { - res.FilterCondition.SteroidDailyDose = [] - } - if (typeof res.FilterCondition.SteroidDailyDoseChange === 'string') { - res.FilterCondition.SteroidDailyDoseChange = res.FilterCondition.SteroidDailyDoseChange?.split('-') - .map((item) => Number(item)) - .filter((item) => Boolean(item)) + if (typeof res.FilterCondition.MedicationType === 'string' && res.FilterCondition.MedicationType) { + res.FilterCondition.MedicationTypeArr = res.FilterCondition.MedicationType.split(',').map(Number) } else { - res.FilterCondition.SteroidDailyDoseChange = [] + res.FilterCondition.MedicationTypeArr = [] } if (res.CreateTime) { res.CreateTime = dayjs(res.CreateTime).format('YYYY-MM-DD HH:mm') @@ -98,26 +72,11 @@ Page({ url: '/doctor/pages/d_createTask/index', success: (res) => { res.eventChannel.emit('FilterCondition', { - Search: FilterCondition.Search, - HasAdl: FilterCondition.HasAdl, - DoubleStandard: FilterCondition.DoubleStandard, - AdlTime: FilterCondition.AdlTime, - AdlScore: FilterCondition.AdlScore.filter((item) => Boolean(item)), - AdlScoreChange: FilterCondition.AdlScoreChange.filter((item) => Boolean(item)), - AdlScoreChangeType: FilterCondition.AdlScoreChangeType, - AdlScoreChangeMax: FilterCondition.AdlScoreChangeMax, - AdlScoreChangeMin: FilterCondition.AdlScoreChangeMin, - SteroidDailyDose: FilterCondition.SteroidDailyDose.filter((item) => Boolean(item)), - SteroidDailyDoseChange: FilterCondition.SteroidDailyDoseChange.filter((item) => Boolean(item)), - IsThisWeekAdl: FilterCondition.IsThisWeekAdl, - PharyngealSymptoms: FilterCondition.PharyngealSymptoms, - AntibodyType: FilterCondition.AntibodyType, - ThyroidAbnormal: FilterCondition.ThyroidAbnormal, - PreviousConvulsion: FilterCondition.PreviousConvulsion, - TraditionalImmunosuppressant: FilterCondition.TraditionalImmunosuppressant, - MedicalInsuranceType: FilterCondition.MedicalInsuranceType, + SelectAll: FilterCondition.SelectAll, BindStartDate: FilterCondition.BindStartDate, BindEndDate: FilterCondition.BindEndDate, + ConfirmedIgg4: FilterCondition.ConfirmedIgg4, + MedicationType: FilterCondition.MedicationType, }) }, }) diff --git a/src/doctor/pages/d_taskDetail/index.wxml b/src/doctor/pages/d_taskDetail/index.wxml index 7619770..d1bad5a 100644 --- a/src/doctor/pages/d_taskDetail/index.wxml +++ b/src/doctor/pages/d_taskDetail/index.wxml @@ -21,97 +21,26 @@ 筛选患者 - - 搜索 - {{detail.FilterCondition.Search}} + + 选择范围 + 全部患者 - + 绑定时间 - {{detail.FilterCondition.BindStartDate}}~{{detail.FilterCondition.BindEndDate}} + {{detail.FilterCondition.BindStartDate || '---'}}~{{detail.FilterCondition.BindEndDate || '---'}} - - 本周ADL测评 - {{IsThisWeekAdlObj[detail.FilterCondition.IsThisWeekAdl]}} + + 确诊IgG4-RD + {{ConfirmedIgg4Obj[detail.FilterCondition.ConfirmedIgg4]}} - - 是否有ADL测评 - {{HasAdlObj[detail.FilterCondition.HasAdl]}} - - - ADL测评间隔时长 - {{AdlTimeObj[detail.FilterCondition.AdlTime]}} - - - 是否双达标 - {{DoubleStandardObj[detail.FilterCondition.DoubleStandard]}} - - - ADL评分(多选) - - - {{AdlScorceObj[subItem]}}{{index < detail.FilterCondition.AdlScore.length - 1 ? ',' : ''}} - - - - - ADL分数变化(多选) - - - {{AdlScoreChangeObj[subItem]}}{{index < detail.FilterCondition.AdlScoreChange.length - 1 ? ',' : ''}} - - - - {{AdlScoreChangeTypeObj[detail.FilterCondition.AdlScoreChangeType]}} - - - ({{detail.FilterCondition.AdlScoreChangeMin}}-{{detail.FilterCondition.AdlScoreChangeMax}}) - - - - - - 激素用量(多选) + + 正在使用的药物 - - {{SteroidDailyDoseObj[subItem]}}{{index < detail.FilterCondition.SteroidDailyDose.length - 1 ? ',' : ''}} + + {{MedicationTypeObj[subItem]}}{{index < detail.FilterCondition.MedicationTypeArr.length - 1 ? '、' : ''}} - - 激素变化(多选) - - - {{SteroidDailyDoseChangeObj[subItem]}}{{index < detail.FilterCondition.SteroidDailyDoseChange.length - 1 ? - ',' : ''}} - - - - - 延髓症状 - {{PharyngealSymptomsObj[detail.FilterCondition.PharyngealSymptoms]}} - - - 抗体类型 - {{AntibodyTypeObj[detail.FilterCondition.AntibodyType]}} - - - 胸腺异常 - {{ThyroidAbnormalObj[detail.FilterCondition.ThyroidAbnormal]}} - - - 既往发生危象 - {{PreviousConvulsionObj[detail.FilterCondition.PreviousConvulsion]}} - - - 传统免疫抑制剂 - - {{TraditionalImmunosuppressantObj[detail.FilterCondition.TraditionalImmunosuppressant]}} - - - - 医保类型 - {{MedicalInsuranceTypeObj[detail.FilterCondition.MedicalInsuranceType]}} - @@ -120,7 +49,7 @@ 消息标题 - {{templateObj[detail.TemplateType]}} + {{TemplateTypeObj[detail.TemplateType]}} 消息内容 diff --git a/src/doctor/pages/d_taskList/index.json b/src/doctor/pages/d_taskList/index.json index e89c713..5541595 100644 --- a/src/doctor/pages/d_taskList/index.json +++ b/src/doctor/pages/d_taskList/index.json @@ -1,6 +1,9 @@ { "navigationBarTitleText": "任务列表", "usingComponents": { + "pagination": "/components/pagination/index", + "van-divider": "@vant/weapp/divider/index", + "van-loading": "@vant/weapp/loading/index", "navBar": "/components/navBar/navBar" } } diff --git a/src/doctor/pages/d_taskList/index.scss b/src/doctor/pages/d_taskList/index.scss index 32ebe30..ce7a4b0 100644 --- a/src/doctor/pages/d_taskList/index.scss +++ b/src/doctor/pages/d_taskList/index.scss @@ -38,6 +38,10 @@ page { color: rgba(229, 154, 41, 1); } + &.status3 { + color: rgba(229, 154, 41, 1); + } + &.status4 { color: rgba(103, 186, 202, 1); } diff --git a/src/doctor/pages/d_taskList/index.ts b/src/doctor/pages/d_taskList/index.ts index 2810516..5efec94 100644 --- a/src/doctor/pages/d_taskList/index.ts +++ b/src/doctor/pages/d_taskList/index.ts @@ -1,5 +1,4 @@ import dayjs from 'dayjs' -import { filterObjs } from '@/utils/doctorPatientTask' const app = getApp() @@ -14,11 +13,27 @@ Page({ Status: { 1: '待发送', 2: '发送中', + 3: '暂停', 4: '已发送', 5: '已停止', 6: '已取消', }, - ...filterObjs, + ConfirmedIgg4Obj: { + 0: '全部', + 1: '是', + 2: '否', + }, + MedicationTypeObj: { + 0: '全部', + 2: '激素', + 3: '免疫抑制剂', + 4: '靶向CD19生物制剂(伊奈利珠单抗)', + 5: '靶向CD20生物制剂(利妥昔单抗等)', + }, + TemplateTypeObj: { + 1: '复诊提醒', + 2: '激素风险提醒', + }, }, onLoad() { const SystemInfo = app.globalSystemInfo @@ -32,7 +47,7 @@ Page({ }, onShow() { app.waitLogin().then(() => { - // this.getList() + this.getList() }) }, getList(newPage = 1) { @@ -44,33 +59,10 @@ Page({ }, }).then((res) => { res.list.forEach((item) => { - if (typeof item.FilterCondition.AdlScore === 'string') { - item.FilterCondition.AdlScore = item.FilterCondition.AdlScore?.split('-') - .map((item) => Number(item)) - .filter((item) => Boolean(item)) - } else { - item.FilterCondition.AdlScore = [] - } - if (typeof item.FilterCondition.AdlScoreChange === 'string') { - item.FilterCondition.AdlScoreChange = item.FilterCondition.AdlScoreChange?.split('-') - .map((item) => Number(item)) - .filter((item) => Boolean(item)) - } else { - item.FilterCondition.AdlScoreChange = [] - } - if (typeof item.FilterCondition.SteroidDailyDose === 'string') { - item.FilterCondition.SteroidDailyDose = item.FilterCondition.SteroidDailyDose?.split('-') - .map((item) => Number(item)) - .filter((item) => Boolean(item)) - } else { - item.FilterCondition.SteroidDailyDose = [] - } - if (typeof item.FilterCondition.SteroidDailyDoseChange === 'string') { - item.FilterCondition.SteroidDailyDoseChange = item.FilterCondition.SteroidDailyDoseChange?.split('-') - .map((item) => Number(item)) - .filter((item) => Boolean(item)) + if (typeof item.FilterCondition.MedicationType === 'string' && item.FilterCondition.MedicationType) { + item.FilterCondition.MedicationTypeArr = item.FilterCondition.MedicationType.split(',').map(Number) } else { - item.FilterCondition.SteroidDailyDoseChange = [] + item.FilterCondition.MedicationTypeArr = [] } if (item.CreateTime) { @@ -123,26 +115,11 @@ Page({ url: '/doctor/pages/d_createTask/index', success: (res) => { res.eventChannel.emit('FilterCondition', { - Search: FilterCondition.Search, - HasAdl: FilterCondition.HasAdl, - DoubleStandard: FilterCondition.DoubleStandard, - AdlTime: FilterCondition.AdlTime, - AdlScore: FilterCondition.AdlScore.filter((item) => Boolean(item)), - AdlScoreChange: FilterCondition.AdlScoreChange.filter((item) => Boolean(item)), - AdlScoreChangeType: FilterCondition.AdlScoreChangeType, - AdlScoreChangeMax: FilterCondition.AdlScoreChangeMax, - AdlScoreChangeMin: FilterCondition.AdlScoreChangeMin, - SteroidDailyDose: FilterCondition.SteroidDailyDose.filter((item) => Boolean(item)), - SteroidDailyDoseChange: FilterCondition.SteroidDailyDoseChange.filter((item) => Boolean(item)), - IsThisWeekAdl: FilterCondition.IsThisWeekAdl, - PharyngealSymptoms: FilterCondition.PharyngealSymptoms, - AntibodyType: FilterCondition.AntibodyType, - ThyroidAbnormal: FilterCondition.ThyroidAbnormal, - PreviousConvulsion: FilterCondition.PreviousConvulsion, - TraditionalImmunosuppressant: FilterCondition.TraditionalImmunosuppressant, - MedicalInsuranceType: FilterCondition.MedicalInsuranceType, + SelectAll: FilterCondition.SelectAll, BindStartDate: FilterCondition.BindStartDate, BindEndDate: FilterCondition.BindEndDate, + ConfirmedIgg4: FilterCondition.ConfirmedIgg4, + MedicationType: FilterCondition.MedicationType, }) }, }) diff --git a/src/doctor/pages/d_taskList/index.wxml b/src/doctor/pages/d_taskList/index.wxml index 4ae44c1..63dd481 100644 --- a/src/doctor/pages/d_taskList/index.wxml +++ b/src/doctor/pages/d_taskList/index.wxml @@ -24,9 +24,9 @@ 筛选条件 - - 搜索: - {{item.FilterCondition.Search}} + + 选择范围: + 全部患者 绑定时间: @@ -34,90 +34,24 @@ {{item.FilterCondition.BindStartDate || '---'}}~{{item.FilterCondition.BindEndDate || '---'}} - - 本周ADL测评: - {{IsThisWeekAdlObj[item.FilterCondition.IsThisWeekAdl]}} + + 确诊IgG4-RD: + {{ConfirmedIgg4Obj[item.FilterCondition.ConfirmedIgg4]}} - - 是否有ADL测评: - {{HasAdlObj[item.FilterCondition.HasAdl]}} - - - ADL测评间隔时长: - {{AdlTimeObj[item.FilterCondition.AdlTime]}} - - - 是否双达标: - {{DoubleStandardObj[item.FilterCondition.DoubleStandard]}} - - - ADL评分(多选): - - - {{AdlScorceObj[subItem]}}{{index < item.FilterCondition.AdlScore.length - 1 ? ',' : ''}} - - - - - ADL分数变化(多选): + + 正在使用的药物: - - {{AdlScoreChangeObj[subItem]}}{{index < item.FilterCondition.AdlScoreChange.length - 1 ? ',' : ''}} - - - {{AdlScoreChangeTypeObj[item.FilterCondition.AdlScoreChangeType]}} - - - ({{item.FilterCondition.AdlScoreChangeMin}}-{{item.FilterCondition.AdlScoreChangeMax}}) + + {{MedicationTypeObj[subItem]}}{{index < item.FilterCondition.MedicationTypeArr.length - 1 ? '、' : ''}} - - 激素用量(多选): - - - {{SteroidDailyDoseObj[subItem]}}{{index < item.FilterCondition.SteroidDailyDose.length - 1 ? ',' : - ''}} - - - - - 激素变化(多选): - - - {{SteroidDailyDoseChangeObj[subItem]}}{{index < item.FilterCondition.SteroidDailyDoseChange.length - 1 - ? ',' : ''}} - - - - - 延髓症状: - {{PharyngealSymptomsObj[item.FilterCondition.PharyngealSymptoms]}} - - - 抗体类型: - {{AntibodyTypeObj[item.FilterCondition.AntibodyType]}} - - - 胸腺异常: - {{ThyroidAbnormalObj[item.FilterCondition.ThyroidAbnormal]}} - - - 既往发生危象: - {{PreviousConvulsionObj[item.FilterCondition.PreviousConvulsion]}} - - - 传统免疫抑制剂: - - {{TraditionalImmunosuppressantObj[item.FilterCondition.TraditionalImmunosuppressant]}} - - - - 医保类型: - {{MedicalInsuranceTypeObj[item.FilterCondition.MedicalInsuranceType]}} - + + 模板类型 + {{TemplateTypeObj[item.TemplateType]}} + diff --git a/src/gift/pages/record/index.scss b/src/gift/pages/record/index.scss index 40ea24b..4133be9 100644 --- a/src/gift/pages/record/index.scss +++ b/src/gift/pages/record/index.scss @@ -87,6 +87,9 @@ page { margin-top: 32rpx; padding-bottom: 32rpx; border-bottom: 1px dashed rgba(34, 34, 34, 0.1); + &:last-of-type { + border: none; + } .label { font-size: 36rpx; color: rgba(34, 34, 34, 1); @@ -125,11 +128,10 @@ page { .content { flex: 1; font-size: 36rpx; - color: rgba(34, 34, 34, 1); + color: rgba(34, 34, 34, 0.4); - &:empty::after { - content: attr(data-place); - color: rgba(34, 34, 34, 0.7); + &.active { + color: rgba(34, 34, 34, 1); } } } @@ -213,19 +215,25 @@ page { font-size: 32rpx; color: rgba(34, 34, 34, 0.5); } - .upload-container { + .upload-wrap { margin-top: 32rpx; + display: flex; + flex-wrap: wrap; + gap: 20rpx; + } + .upload-container { + flex-shrink: 0; padding: 0; width: 300rpx; height: 168rpx; box-sizing: border-box; background: #f3fffa; - border-radius: 16rpx 16rpx 16rpx 16rpx; + border-radius: 16rpx; border: 2rpx dashed #0eb66d; overflow: hidden; .icon { display: block; - margin: 28rpx auto 0; + margin: 34rpx auto 0; width: 48rpx; height: 48rpx; } @@ -238,25 +246,26 @@ page { } .upload-preview { position: relative; - margin-top: 32rpx; + flex-shrink: 0; width: 300rpx; height: 168rpx; - border-radius: 24rpx; + border-radius: 16rpx; + overflow: hidden; .upload-img { display: block; width: 100%; height: 100%; - border-radius: 24rpx; + border-radius: 16rpx; } .del { position: absolute; top: 0; right: 0; color: #fff; - font-size: 28rpx; + font-size: 24rpx; padding: 4rpx 12rpx; background-color: rgba(0, 0, 0, 0.8); - border-radius: 0 24rpx 0 24rpx; + border-radius: 0 16rpx 0 16rpx; } } } @@ -377,23 +386,22 @@ page { display: grid; gap: 24rpx; &.col1 { - grid-template-columns: repeat(1, 1fr); + grid-template-columns: repeat(auto-fill, minmax(300rpx, 1fr)); } &.col2 { grid-template-columns: repeat(2, 1fr); } .check-item { display: flex; - align-items: center; gap: 24rpx; - padding: 0 32rpx; - height: 96rpx; + padding: 32rpx 32rpx; border-radius: 16rpx; background-color: rgba(248, 248, 248, 1); border: 1px solid rgba(248, 248, 248, 1); box-sizing: border-box; .check { flex-shrink: 0; + margin-top: 6rpx; width: 40rpx; height: 40rpx; border-radius: 8rpx; @@ -577,6 +585,12 @@ page { } } } + .num-select { + .n-item.active { + border-color: rgba(89, 86, 233, 1); + background-color: rgba(89, 86, 233, 0.08); + } + } } .step3-footer { .prev { diff --git a/src/gift/pages/record/index.ts b/src/gift/pages/record/index.ts index ebe1998..3a5e836 100644 --- a/src/gift/pages/record/index.ts +++ b/src/gift/pages/record/index.ts @@ -1,37 +1,466 @@ +import { debounce } from 'miniprogram-licia' const _app = getApp() +const MEDICATIONS_OPTIONS = [ + { id: 1, label: '没有使用激素', active: false }, + { id: 2, label: '激素', active: false }, + { id: 3, label: '免疫抑制剂', active: false }, + { id: 4, label: '靶向CD19生物制剂(伊奈利珠单抗)', active: false }, + { id: 5, label: '靶向CD20生物制剂(利妥昔单抗等)', active: false }, + { id: 99, label: '其他', active: false }, +] + +const IMMUNOSUPPRESSANT_OPTIONS = [ + { id: 1, label: '吗替麦考酚酯(骁悉、麦考芬)', active: false }, + { id: 2, label: '替唑嘌呤', active: false }, + { id: 3, label: '环磷酰胺', active: false }, + { id: 4, label: '来氟米特', active: false }, + { id: 5, label: '甲氨蝶呤', active: false }, + { id: 6, label: '环孢素 A', active: false }, + { id: 7, label: '他克莫司', active: false }, + { id: 8, label: '艾拉莫德', active: false }, + { id: 99, label: '其他', active: false }, +] + +const HORMONE_DOSAGE_OPTIONS = [1, 2, 4, 6, 8] + +const IMAGE_TYPE_MAP: Record = { + outpatientRecord: 'outpatientRecord', + labReport: 'labReport', + imagingExam: 'imagingExam', + pathology: 'pathology', + immuneFunction: 'immuneFunction', +} + Page({ data: { - step: 3, + step: 1, + draftId: 0, + recordStatus: 0, + + // step1 + visitDate: '', + nextVisitDate: '', + + // step2 - 每种图片类型的文件列表 + outpatientRecordFiles: [] as any[], + labReportFiles: [] as any[], + imagingExamFiles: [] as any[], + pathologyFiles: [] as any[], + immuneFunctionFiles: [] as any[], + + // step3 + igG4Value: '', + medicationsUsed: [] as number[], + immunosuppressantName: [] as number[], + oralHormoneDosage: 0, + customDosage: '', + medicationsOptions: MEDICATIONS_OPTIONS, + immunosuppressantOptions: IMMUNOSUPPRESSANT_OPTIONS, + hormoneDosageOptions: HORMONE_DOSAGE_OPTIONS, + // 其他输入 + medicationsUsedOtherText: '', + immunosuppressantNameOtherText: '', + medicationsOtherShow: false, + immunosuppressantOtherShow: false, + + // UI toastShow: false, toastType: '', - // toastType: 'oneWrite', - // toastType: 'noWrite', // 用户信息未填全的提醒弹窗 toastParams: {} as any, + saving: false, + submitted: false, + }, + + _saveDraftDebounced: null as any, + + onLoad(options: any) { + if (options.id) { + this.setData({ draftId: Number(options.id) }) + _app.waitLogin().then(() => { + this.getDetail() + }) + } + + this._saveDraftDebounced = debounce(() => { + this.saveDraft() + }, 800) + }, + + onUnload() { + wx.disableAlertBeforeUnload() + }, + + _updateAlertBeforeUnload() { + if (this.data.submitted || !this._hasFilledData()) { + wx.disableAlertBeforeUnload() + } else { + wx.enableAlertBeforeUnload({ message: '您有填写信息还未提交' }) + } }, - onLoad() {}, + + _hasFilledData() { + if (this.data.visitDate || this.data.nextVisitDate) return true + const hasImage = Object.keys(IMAGE_TYPE_MAP).some( + (key) => (this.data[`${key}Files` as any] as any[]).length > 0, + ) + if (hasImage) return true + if (this.data.igG4Value || this.data.oralHormoneDosage || this.data.customDosage) return true + if (this.data.medicationsUsed.length || this.data.immunosuppressantName.length) return true + return false + }, + + // ========== API ========== + + getDetail() { + wx.ajax({ + method: 'GET', + url: '?r=igg4/medical-visit/detail', + data: { id: this.data.draftId }, + }).then((res: any) => { + if (!res) return + const images = res.images || {} + const setData: Record = { + visitDate: res.visitDate || '', + nextVisitDate: res.nextVisitDate || '', + igG4Value: res.manualIgG4Value != null ? String(res.manualIgG4Value) : '', + medicationsUsed: res.medicationsUsed || [], + immunosuppressantName: res.immunosuppressantName || [], + medicationsOptions: MEDICATIONS_OPTIONS.map((item) => ({ + ...item, + active: (res.medicationsUsed || []).includes(item.id), + })), + immunosuppressantOptions: IMMUNOSUPPRESSANT_OPTIONS.map((item) => ({ + ...item, + active: (res.immunosuppressantName || []).includes(item.id), + })), + oralHormoneDosage: res.oralHormoneDosage || 0, + recordStatus: res.recordStatus, + customDosage: + res.oralHormoneDosage && !HORMONE_DOSAGE_OPTIONS.includes(res.oralHormoneDosage) + ? String(res.oralHormoneDosage) + : '', + medicationsUsedOtherText: res.medicationsUsedOtherText || '', + immunosuppressantNameOtherText: res.immunosuppressantNameOtherText || '', + medicationsOtherShow: (res.medicationsUsed || []).includes(99), + immunosuppressantOtherShow: (res.immunosuppressantName || []).includes(99), + } + + // 将按类型分组的图片转为 fileList + for (const typeKey of Object.keys(IMAGE_TYPE_MAP)) { + const typeImages = images[typeKey] || [] + setData[`${typeKey}Files`] = typeImages.map((img: any) => ({ + imgUrl: img.maskedImageUrl || img.imageUrl, + fileUrl: img.imageUrl, + type: 'image', + imageId: img.id, + imageType: typeKey, + })) + } + + this.setData(setData) + }) + }, + + saveDraft(): Promise { + if (this.data.saving) return Promise.resolve() + if (!this.data.visitDate) return Promise.resolve() + + this.setData({ saving: true }) + + // 汇总所有图片 + const images: any[] = [] + const typeKeys = Object.keys(IMAGE_TYPE_MAP) + for (const typeKey of typeKeys) { + const files = this.data[`${typeKey}Files` as any] as any[] + if (files && files.length) { + for (const file of files) { + images.push({ + imageUrl: file.fileUrl || file.imgUrl, + imageType: typeKey, + }) + } + } + } + + const data: Record = { + visitDate: this.data.visitDate, + nextVisitDate: this.data.nextVisitDate || undefined, + manualIgG4Value: this.data.igG4Value ? Number(this.data.igG4Value) : undefined, + medicationsUsed: this.data.medicationsUsed.length ? this.data.medicationsUsed : undefined, + medicationsUsedOtherText: this.data.medicationsUsedOtherText || undefined, + immunosuppressantName: this.data.immunosuppressantName.length + ? this.data.immunosuppressantName + : undefined, + immunosuppressantNameOtherText: this.data.immunosuppressantNameOtherText || undefined, + oralHormoneDosage: + this.data.oralHormoneDosage || this.data.customDosage + ? Number(this.data.oralHormoneDosage || this.data.customDosage) + : undefined, + images, + } + + if (this.data.draftId) { + data.id = this.data.draftId + } + + return wx + .ajax({ + method: 'POST', + url: '?r=igg4/medical-visit/save-draft', + data, + }) + .then((res: any) => { + if (res && res.id && !this.data.draftId) { + this.setData({ draftId: res.id }) + } + if (res && res.recordStatus) { + this.setData({ recordStatus: res.recordStatus }) + } + }) + .catch(() => {}) + .finally(() => { + this.setData({ saving: false }) + }) + }, + + autoSave() { + this._updateAlertBeforeUnload() + if (this._saveDraftDebounced) { + this._saveDraftDebounced() + } + }, + + submit() { + if (!this.data.draftId) { + wx.showToast({ title: '请先保存草稿', icon: 'none' }) + return + } + + wx.ajax({ + method: 'POST', + url: '?r=igg4/medical-visit/submit', + data: { id: this.data.draftId }, + loading: true, + }).then(() => { + this.setData({ submitted: true }) + wx.disableAlertBeforeUnload() + wx.showToast({ title: '提交成功', icon: 'success' }) + setTimeout(() => { + wx.navigateBack() + }, 1500) + }) + }, + + // ========== Step1 事件 ========== + + handleVisitDateChange(e: WechatMiniprogram.PickerChange) { + this.setData({ visitDate: e.detail.value as string }) + this.autoSave() + }, + + handleNextVisitDateChange(e: WechatMiniprogram.PickerChange) { + this.setData({ nextVisitDate: e.detail.value as string }) + this.autoSave() + }, + + handleStep1Next() { + if (!this.data.visitDate && !this.data.nextVisitDate) { + this.setData({ toastShow: true, toastType: 'oneWrite', toastParams: {} }) + return + } + this.saveDraft().then(() => { + this.setData({ step: 2 }) + }) + }, + + // ========== Step2 事件 ========== + handleSetData(e: WechatMiniprogram.CustomEvent) { - const imgUrl = e.detail[0].imgUrl + const imageType = e.currentTarget.dataset.type as string + const file = e.detail[0] + const filesKey = `${imageType}Files` + const currentFiles = this.data[filesKey as any] as any[] || [] + const newFile = { + imgUrl: file.imgUrl, + fileUrl: file.imgUrl, + type: 'image', + imageType, + } + this.setData({ + [filesKey]: [...currentFiles, newFile], + }) + this.autoSave() + }, + + handleDeleteFile(e: WechatMiniprogram.CustomEvent) { + const imageType = e.currentTarget.dataset.type as string + const index = e.detail.index + this._removeFile(imageType, index) + }, + + handleDeleteImage(e: WechatMiniprogram.CustomEvent) { + const imageType = e.currentTarget.dataset.type as string + const index = e.currentTarget.dataset.index as number + this._removeFile(imageType, index) + }, + + _removeFile(imageType: string, index: number) { + const filesKey = `${imageType}Files` + const currentFiles = this.data[filesKey as any] as any[] + currentFiles.splice(index, 1) this.setData({ - uploadImg: imgUrl, - audit: true, + [filesKey]: [...currentFiles], }) + this.autoSave() }, - handleExample(e) { + + handlePreviewImage(e: WechatMiniprogram.CustomEvent) { + const imageType = e.currentTarget.dataset.type as string + const filesKey = `${imageType}Files` + const files = this.data[filesKey as any] as any[] + const urls = files.map((f) => f.fileUrl || f.imgUrl) + wx.previewImage({ urls }) + }, + + handleExample(e: WechatMiniprogram.CustomEvent) { wx.previewImage({ urls: [e.currentTarget.dataset.url], }) }, + + handleStep2Prev() { + this.saveDraft().then(() => { + this.setData({ step: 1 }) + }) + }, + + handleStep2Next() { + const hasImage = Object.keys(IMAGE_TYPE_MAP).some( + (key) => (this.data[`${key}Files` as any] as any[]).length > 0, + ) + if (!hasImage) { + this.setData({ toastShow: true, toastType: 'oneWrite', toastParams: {} }) + return + } + this.saveDraft().then(() => { + this.setData({ step: 3 }) + }) + }, + + // ========== Step3 事件 ========== + + handleIgG4Input(e: WechatMiniprogram.Input) { + this.setData({ igG4Value: e.detail.value }) + this.autoSave() + }, + + handleMedicationToggle(e: WechatMiniprogram.CustomEvent) { + const id = e.currentTarget.dataset.id as number + const options = this.data.medicationsOptions.map((item) => { + if (item.id === id) return { ...item, active: !item.active } + return item + }) + const usedIds = options.filter((item) => item.active).map((item) => item.id) + const isOtherActive = usedIds.includes(99) + this.setData({ + medicationsOptions: options, + medicationsUsed: usedIds, + medicationsOtherShow: isOtherActive, + medicationsUsedOtherText: isOtherActive ? this.data.medicationsUsedOtherText : '', + }) + this.autoSave() + }, + + handleMedicationsUsedOtherInput(e: WechatMiniprogram.Input) { + this.setData({ medicationsUsedOtherText: e.detail.value }) + this.autoSave() + }, + + handleImmunosuppressantToggle(e: WechatMiniprogram.CustomEvent) { + const id = e.currentTarget.dataset.id as number + const options = this.data.immunosuppressantOptions.map((item) => { + if (item.id === id) return { ...item, active: !item.active } + return item + }) + const usedIds = options.filter((item) => item.active).map((item) => item.id) + const isOtherActive = usedIds.includes(99) + this.setData({ + immunosuppressantOptions: options, + immunosuppressantName: usedIds, + immunosuppressantOtherShow: isOtherActive, + immunosuppressantNameOtherText: isOtherActive ? this.data.immunosuppressantNameOtherText : '', + }) + this.autoSave() + }, + + handleImmunosuppressantNameOtherInput(e: WechatMiniprogram.Input) { + this.setData({ immunosuppressantNameOtherText: e.detail.value }) + this.autoSave() + }, + + handleDosageSelect(e: WechatMiniprogram.CustomEvent) { + const val = e.currentTarget.dataset.val as number + this.setData({ + oralHormoneDosage: this.data.oralHormoneDosage === val ? 0 : val, + customDosage: '', + }) + this.autoSave() + }, + + handleCustomDosageInput(e: WechatMiniprogram.Input) { + this.setData({ + customDosage: e.detail.value, + oralHormoneDosage: 0, + }) + this.autoSave() + }, + + handleStep3Prev() { + this.saveDraft().then(() => { + this.setData({ step: 2 }) + }) + }, + + handleSubmit() { + const hasData = + this.data.igG4Value || + this.data.medicationsUsed.length || + this.data.immunosuppressantName.length || + this.data.oralHormoneDosage || + this.data.customDosage + if (!hasData) { + this.setData({ toastShow: true, toastType: 'oneWrite', toastParams: {} }) + return + } + this.saveDraft().then(() => { + // 编辑已提交的记录,无需再调用提交接口 + if (this.data.recordStatus === 2) { + this.setData({ submitted: true }) + wx.disableAlertBeforeUnload() + wx.navigateBack() + return + } + this.submit() + }) + }, + + // ========== Toast 事件 ========== + handleToastOk() { - const { toastType } = this.data + this.setData({ + toastShow: false, + toastType: '', + toastParams: {}, + }) }, - handleToastCancel(_e = null) { - const { toastType } = this.data + + handleToastCancel() { this.setData({ toastShow: false, toastType: '', - toastParams: '', + toastParams: {}, }) }, }) diff --git a/src/gift/pages/record/index.wxml b/src/gift/pages/record/index.wxml index 2e9dd87..7d4ed79 100644 --- a/src/gift/pages/record/index.wxml +++ b/src/gift/pages/record/index.wxml @@ -1,4 +1,4 @@ - + @@ -21,6 +21,8 @@ 核对指标 + + @@ -30,117 +32,204 @@ 我的本次就诊时间 - + - - + + {{visitDate || '选择就诊时间'}} 我的下次就诊时间 - + - - + + {{nextVisitDate || '选择复诊时间'}} - 下一步 + 下一步 + + 门诊材料会分类存储到 "我的-健康档案",方便您查看对比。 + + 门诊病历及处方 - 示意 + + 示意 + 医生手写或电脑打印的病历、处方 - - - - 添加文件照片 - - - - + + + + - + + + + 添加文件照片 + + + + + 检验报告(IgG4化验单等) - 示意 + + 示意 + 抽血检测的IgG4、总免疫球蛋白、ESR等 - - - - 添加文件照片 - - - + + + + + + - + + + + 添加文件照片 + + + + + 影像学检查(CT/超声/核磁) 超声、CT、核磁共振的描述结论、电子胶片 - - - - 添加文件照片 - - - + + + + + + - + + + + 添加文件照片 + + + + + 病理诊断及活检 受累组织穿刺或切除免疫组化报告 - - - - 添加文件照片 - - - + + + + + + - + + + + 添加文件照片 + + + + + 外周血免疫功能评估 免疫细胞亚群、淋巴细胞比例测定 - - - - 添加文件照片 - - - + + + + + + - + + + + 添加文件照片 + + + + - 上一页 - 下一页 + 上一页 + 下一页 + + 请填写本次就诊的以下信息,方便医生关注您的健康情况 + + @@ -153,67 +242,119 @@ - - + + mg/dL + + 本次就诊已使用的药物 - - - - - - - 没有使用激素 - - + + - 没有使用激素 + {{item.label}} + + + + + 最近一周,口服激素的每日用量 - 8片 + + {{item}}片 + - + + + 正在使用的免疫抑制剂名称 - - - + + - 没有使用激素 - - - - - - 没有使用激素 + {{item.label}} + + + + - 上一页 - 提交 + 上一页 + 提交 diff --git a/src/gift/pages/recordDetail/index.json b/src/gift/pages/recordDetail/index.json index 1690f71..018eb95 100644 --- a/src/gift/pages/recordDetail/index.json +++ b/src/gift/pages/recordDetail/index.json @@ -2,7 +2,6 @@ "navigationBarTitleText": "就诊记录详情页", "navigationBarBackgroundColor": "#F6F6F6", "usingComponents": { - "uploadFile": "/components/uploadFile/index", "van-icon": "@vant/weapp/icon/index" } } diff --git a/src/gift/pages/recordDetail/index.ts b/src/gift/pages/recordDetail/index.ts index 067b6bb..0513376 100644 --- a/src/gift/pages/recordDetail/index.ts +++ b/src/gift/pages/recordDetail/index.ts @@ -1,8 +1,153 @@ -const _app = getApp(); +const MEDICATIONS_MAP: Record = { + 1: '没有使用激素', + 2: '激素', + 3: '免疫抑制剂', + 4: '靶向CD19生物制剂', + 5: '靶向CD20生物制剂', + 99: '其他', +} + +const IMMUNOSUPPRESSANT_MAP: Record = { + 1: '吗替麦考酚酯', + 2: '替唑嘌呤', + 3: '环磷酰胺', + 4: '来氟米特', + 5: '甲氨蝶呤', + 6: '环孢素A', + 7: '他克莫司', + 8: '艾拉莫德', + 99: '其他', +} + +const IMAGE_TYPE_LABELS: Record = { + outpatientRecord: '门诊病历及处方', + labReport: '检验报告', + imagingExam: '影像学检查', + pathology: '病理诊断及活检', + immuneFunction: '外周血免疫功能评估', +} Page({ - data: {}, - onLoad() {}, -}); + data: { + id: 0, + visitDate: '', + nextVisitDate: '', + displayIgG4Value: '' as string | number | null, + medicationsLabel: '', + oralHormoneDosage: '' as string | number | null, + immunosuppressantLabel: '', + reminderEnabled: 2, + imageGroups: [] as { type: string; label: string; list: string[] }[], + }, + + onLoad(options: any) { + if (options.id) { + this.setData({ id: Number(options.id) }) + this.getDetail() + this.getReminderConfig() + } + }, + + // ========== API ========== + + getDetail() { + wx.ajax({ + method: 'GET', + url: '?r=igg4/medical-visit/detail', + data: { id: this.data.id }, + }).then((res: any) => { + if (!res) return + const medicationsLabel = (res.medicationsUsed || []) + .map((id: number) => { + if (id === 99 && res.medicationsUsedOtherText) return `其他:${res.medicationsUsedOtherText}` + return MEDICATIONS_MAP[id] + }) + .filter(Boolean) + .join('、') + const immunosuppressantLabel = (res.immunosuppressantName || []) + .map((id: number) => { + if (id === 99 && res.immunosuppressantNameOtherText) return `其他:${res.immunosuppressantNameOtherText}` + return IMMUNOSUPPRESSANT_MAP[id] + }) + .filter(Boolean) + .join('、') + + const imageGroups: { type: string; label: string; list: string[] }[] = [] + const images = res.images || {} + for (const type of Object.keys(IMAGE_TYPE_LABELS)) { + const list = (images[type] || []).map((img: any) => img.maskedImageUrl || img.imageUrl) + if (list.length) { + imageGroups.push({ type, label: IMAGE_TYPE_LABELS[type], list }) + } + } + + this.setData({ + visitDate: res.visitDate || '', + nextVisitDate: res.nextVisitDate || '', + displayIgG4Value: res.displayIgG4Value, + medicationsLabel, + oralHormoneDosage: res.oralHormoneDosage, + immunosuppressantLabel, + imageGroups, + }) + }) + }, + + getReminderConfig() { + wx.ajax({ + method: 'GET', + url: '?r=igg4/medical-visit/get-reminder-config', + }).then((res: any) => { + if (!res) return + this.setData({ reminderEnabled: res.reminderEnabled || 2 }) + }) + }, + + saveReminderConfig(e: any) { + const val = e.detail.value ? 1 : 2 + this.setData({ reminderEnabled: val }) + wx.ajax({ + method: 'POST', + url: '?r=igg4/medical-visit/save-reminder-config', + data: { reminderEnabled: val }, + }) + }, + + // ========== 操作 ========== + + handleDelete() { + wx.showModal({ + title: '确认删除记录?', + content: `删除${this.data.visitDate || ''}记录,此操作不可逆,相关照片将永久删除`, + confirmText: '确认删除', + confirmColor: '#ee0a24', + success: (res) => { + if (!res.confirm) return + wx.ajax({ + method: 'POST', + url: '?r=igg4/medical-visit/delete', + data: { id: this.data.id }, + }).then((res: any) => { + if (!res) return + wx.navigateBack() + }) + }, + }) + }, + + handleEdit() { + wx.navigateTo({ url: `/gift/pages/record/index?id=${this.data.id}` }) + }, + + handlePreviewImage(e: any) { + const { url, type } = e.currentTarget.dataset + const group = this.data.imageGroups.find((g) => g.type === type) + if (!group) return + wx.previewImage({ + current: url, + urls: group.list, + }) + }, +}) export {} diff --git a/src/gift/pages/recordDetail/index.wxml b/src/gift/pages/recordDetail/index.wxml index 59e3495..4f70508 100644 --- a/src/gift/pages/recordDetail/index.wxml +++ b/src/gift/pages/recordDetail/index.wxml @@ -4,52 +4,62 @@ 我的本次就诊时间 - 2026-06-23 + {{visitDate || '--'}} 我的下次就诊时间 - 2026-07-23 + {{nextVisitDate || '--'}} 复诊提醒 - + - - 门诊病历及处方 + + {{item.label}} - + - + IgG4值 - 115 mg/dL + {{displayIgG4Value}} mg/dL - + 本次就诊已使用的药物 - 激素免疫抑制剂 + {{medicationsLabel}} - + 最近一周,每日激素使用剂量 - 5mg/天 + {{oralHormoneDosage}}mg/天 - + 正在使用的免疫抑制剂名称 - 吗替麦考酚酯(骁悉、麦考芬) + {{immunosuppressantLabel}} - + 删除 - + 编辑 diff --git a/src/gift/pages/recordList/index.json b/src/gift/pages/recordList/index.json index 6df6a90..958c3c7 100644 --- a/src/gift/pages/recordList/index.json +++ b/src/gift/pages/recordList/index.json @@ -4,6 +4,7 @@ "usingComponents": { "uploadFile": "/components/uploadFile/index", "van-icon": "@vant/weapp/icon/index", - "ec-canvas": "/components/ec-canvas/ec-canvas" + "ec-canvas": "/components/ec-canvas/ec-canvas", + "pagination": "/components/pagination/index" } } diff --git a/src/gift/pages/recordList/index.scss b/src/gift/pages/recordList/index.scss index 76b5fd4..1c237ac 100644 --- a/src/gift/pages/recordList/index.scss +++ b/src/gift/pages/recordList/index.scss @@ -55,6 +55,13 @@ page { display: flex; align-items: center; gap: 14rpx; + .start, + .end { + color: rgba(105, 104, 110, 1); + &.active { + color: rgba(34, 34, 34, 1); + } + } .line { margin: 0 10rpx; } diff --git a/src/gift/pages/recordList/index.ts b/src/gift/pages/recordList/index.ts index 9b73225..a69ade7 100644 --- a/src/gift/pages/recordList/index.ts +++ b/src/gift/pages/recordList/index.ts @@ -2,162 +2,329 @@ import dayjs from 'dayjs' const _app = getApp() let echarts: any = null +const MEDICATIONS_MAP: Record = { + 1: '没有使用激素', + 2: '激素', + 3: '免疫抑制剂', + 4: '靶向CD19生物制剂', + 5: '靶向CD20生物制剂', + 99: '其他', +} + +const IMMUNOSUPPRESSANT_MAP: Record = { + 1: '吗替麦考酚酯', + 2: '替唑嘌呤', + 3: '环磷酰胺', + 4: '来氟米特', + 5: '甲氨蝶呤', + 6: '环孢素A', + 7: '他克莫司', + 8: '艾拉莫德', + 99: '其他', +} + Page({ - data: {}, + data: { + list: [] as any[], + pagination: { count: 0, page: 1, pages: 1 }, + year: 0 as number, + yearOptions: [] as { label: string; value: number }[], + beginDate: '', + endDate: '', + + // 用户头部 + latestIgG4: '' as string | number, + + // 图表 + chartUnit: '', + chartList: [] as any[], + }, + ecDataTrendComponent: null as any, - async onLoad() { - echarts = await require.async('../../../resource/components/echart/echarts.js') - this.ecDataTrendComponent = this.selectComponent('#chart1') - this.initChart() + + onLoad() { + echarts = require.async('../../../resource/components/echart/echarts.js').then((mod: any) => { + echarts = mod + }) + // 默认按年,筛选前一年 + const lastYear = dayjs().subtract(1, 'year').year() + this.setData({ selectedYear: lastYear, selectedYearLabel: `${lastYear}年` }) + _app.waitLogin().then(() => { + this.getLatestRecord() + this.getList() + this.getIndicatorHistory() + }) + }, + + onShow() { + if (this.data.list.length) { + this.getLatestRecord() + this.getList(true) + } + }, + + // ========== API ========== + + getList(reset = false) { + const page = reset ? 1 : this.data.pagination.page + const data: Record = { page, pageSize: 10 } + + wx.ajax({ + method: 'GET', + url: '?r=igg4/medical-visit/list', + data, + }).then((res: any) => { + if (!res) return + const list = (res.list || []).map((item: any) => ({ + ...item, + medicationLabels: (item.medicationsUsed || []).map((id: number) => MEDICATIONS_MAP[id]).filter(Boolean), + immunosuppressantLabels: (item.immunosuppressantName || []) + .map((id: number) => IMMUNOSUPPRESSANT_MAP[id]) + .filter(Boolean), + statusText: item.recordStatus === 1 ? '草稿' : '已提交', + })) + + // 提取年份选项 + const yearSet = new Set() + for (const item of res.list || []) { + if (item.visitDate) yearSet.add(Number(item.visitDate.substring(0, 4))) + } + const yearOptions = [...yearSet].sort((a, b) => b - a).map((y) => ({ label: `${y}年`, value: y })) + + this.setData({ + list: reset ? list : [...this.data.list, ...list], + pagination: { + count: res.totalCount || 0, + page: res.page || 1, + pages: res.pages || 1, + }, + yearOptions: this.data.yearOptions.length ? this.data.yearOptions : yearOptions, + }) + }) + }, + + getLatestRecord() { + wx.ajax({ + method: 'GET', + url: '?r=igg4/medical-visit/get-latest-record', + }).then((res: any) => { + if (!res) { + this.setData({ latestIgG4: '' }) + return + } + this.setData({ latestIgG4: res.displayIgG4Value ?? '' }) + }) + }, + + getIndicatorHistory() { + const data: Record = { indicatorField: 'igG4' } + if (this.data.filterMode === 'year') { + data.year = this.data.selectedYear + } else { + data.count = this.data.filterCount || 10 + } + + wx.ajax({ + method: 'GET', + url: '?r=igg4/medical-visit/indicator-history', + data, + }).then((res: any) => { + if (!res) return + this.setData({ + chartUnit: res.unit || 'mg/dL', + chartList: res.list || [], + }) + this.initChart(res.list || []) + }) }, - initChart(defaultList = []) { - const list: any = [ - ...defaultList, - { Date: '2026-7-7', TotalScore: 100, InjectionBottles: false }, - { Date: '2026-7-8', TotalScore: 1000, InjectionBottles: false }, - ] - return new Promise((reslove) => { - const { theme } = this.data - this.ecDataTrendComponent.init((canvas, width, height, dpr) => { - const chart = echarts.init(canvas, null, { - width, - height, - devicePixelRatio: dpr, // new + handleDelete(e: any) { + const { id, date } = e.currentTarget.dataset + wx.showModal({ + title: '确认删除记录?', + content: `删除${date}记录,此操作不可逆,相关照片将永久删除`, + confirmText: '确认删除', + confirmColor: '#cf5375', + success: (res) => { + if (!res.confirm) return + wx.ajax({ + method: 'POST', + url: '?r=igg4/medical-visit/delete', + data: { id }, + }).then((res: any) => { + if (!res) return + const list = this.data.list.filter((item: any) => item.id !== id) + this.setData({ list }) }) - canvas.setChart(chart) - - const option: any = { - tooltip: { - show: false, - trigger: 'axis', - axisPointer: { - type: 'shadow', - }, - confine: true, - backgroundColor: 'rgba(0, 0, 0, 0.5)', - textStyle: { - color: '#fff', - fontSize: 10, + }, + }) + }, + + // ========== 图表 ========== + + initChart(defaultList: any[] = []) { + if (!defaultList.length) return + if (!echarts || !this.ecDataTrendComponent) { + this.ecDataTrendComponent = this.selectComponent('#chart1') + if (!echarts || !this.ecDataTrendComponent) return + } + + const list = defaultList + + const { theme } = this.data + this.ecDataTrendComponent.init((canvas: any, width: number, height: number, dpr: number) => { + const chart = echarts.init(canvas, null, { + width, + height, + devicePixelRatio: dpr, + }) + canvas.setChart(chart) + + const option: any = { + tooltip: { + show: false, + trigger: 'axis', + axisPointer: { type: 'shadow' }, + confine: true, + backgroundColor: 'rgba(0, 0, 0, 0.5)', + textStyle: { color: '#fff', fontSize: 10 }, + order: 'seriesDesc', + }, + grid: { + top: '30', + left: '0', + right: '0', + bottom: '10', + containLabel: true, + }, + xAxis: [ + { + type: 'category', + axisTick: { alignWithLabel: true }, + axisLine: { + lineStyle: { color: 'rgba(34, 34, 34, 0.20)', type: 'dashed' }, }, - order: 'seriesDesc', + data: list.map((item: any) => dayjs(item.visitDate).format('MM-DD')), }, - grid: { - top: '30', - left: '0', - right: '0', - bottom: '10', - containLabel: true, + ], + yAxis: [ + { + type: 'value', + min: 200, + minInterval: 1, + axisLabel: { color: 'rgba(34, 34, 34, 0.40)' }, + splitLine: { + lineStyle: { color: 'rgba(34, 34, 34, 0.20)', type: 'dashed' }, + }, }, - xAxis: [ - { - type: 'category', - axisTick: { - alignWithLabel: true, - }, - axisLine: { - lineStyle: { - color: 'rgba(34, 34, 34, 0.20)', - type: 'dashed', - }, - }, - data: list.map((item) => dayjs(item.Date).format('MM-DD')), + ], + series: [ + { + name: 'IgG4', + data: list.length ? list.map((item: any) => item.value) : [0], + barWidth: '16', + label: { + show: true, + position: 'top', + color: theme === 'DRUG' ? 'rgba(89, 86, 233, 1)' : 'rgba(14, 182, 109, 1)', }, - ], - yAxis: [ - { - type: 'value', - minInterval: 1, - axisLabel: { - color: 'rgba(34, 34, 34, 0.40)', - }, - splitLine: { - lineStyle: { - color: 'rgba(34, 34, 34, 0.20)', - type: 'dashed', - }, - }, + type: 'line', + symbol: 'circle', + symbolSize: 8, + showSymbol: list.length >= 1, + connectNulls: true, + z: 10, + itemStyle: { + color: theme === 'DRUG' ? 'rgba(89, 86, 233, 1)' : 'rgba(14, 182, 109, 1)', }, - ], - series: [ - { - name: '总分', - data: list.length ? list.map((item) => item.TotalScore) : [25], - barWidth: '16', - label: { - show: true, - position: 'top', - color: theme === 'DRUG' ? 'rgba(89, 86, 233, 1)' : 'rgba(14, 182, 109, 1)', - }, - type: 'line', - symbol: 'circle', - symbolSize: 8, - showSymbol: list.length >= 1, - connectNulls: true, - z: 10, - itemStyle: { - color: theme === 'DRUG' ? 'rgba(89, 86, 233, 1)' : 'rgba(14, 182, 109, 1)', - }, - markLine: { - symbol: ['none', 'none'], - data: [ - { - name: '135 安全区', - yAxis: 135, - label: { - formatter: '{b}', - position: 'insideMiddle', - color: theme === 'DRUG' ? 'rgba(89, 86, 233, 1)' : 'rgba(14, 182, 109, 1)', - fontSize: '10', - }, - lineStyle: { - cap: '', - color: theme === 'DRUG' ? 'rgba(89, 86, 233, 1)' : 'rgba(14, 182, 109, 1)', - type: 'dashed', - }, + markLine: { + symbol: ['none', 'none'], + data: [ + { + name: '135 安全区', + yAxis: 135, + label: { + formatter: '{b}', + position: 'insideMiddle', + color: theme === 'DRUG' ? 'rgba(89, 86, 233, 1)' : 'rgba(14, 182, 109, 1)', + fontSize: '10', + }, + lineStyle: { + cap: '', + color: theme === 'DRUG' ? 'rgba(89, 86, 233, 1)' : 'rgba(14, 182, 109, 1)', + type: 'dashed', }, - ], - }, - markArea: { - itemStyle: { - color: theme === 'DRUG' ? 'rgba(89, 86, 233, 0.06)' : 'rgba(14, 182, 109, 0.06)', }, - data: [ - [ - { - yAxis: 0, - }, - { - yAxis: 135, - }, - ], - ], + ], + }, + markArea: { + itemStyle: { + color: theme === 'DRUG' ? 'rgba(89, 86, 233, 0.06)' : 'rgba(14, 182, 109, 0.06)', }, + data: [[{ yAxis: 0 }, { yAxis: 135 }]], }, - ], - dataZoom: { - type: 'inside', // 有type这个属性,滚动条在最下面,也可以不行,写y:36,这表示距离顶端36px,一般就是在图上面。 - startValue: 0, - endValue: 4, - filterMode: 'none', }, - } + ], + dataZoom: { + type: 'inside', + startValue: 0, + endValue: 4, + filterMode: 'none', + }, + } - chart.setOption(option) - reslove(chart) - return chart - }) + chart.setOption(option) + return chart }) }, - handleDetail() { - wx.navigateTo({ - url: '/gift/pages/recordDetail/index', + + // ========== 筛选 ========== + + handleFilterModeChange(e: any) { + const mode = e.currentTarget.dataset.mode + this.setData({ filterMode: mode }) + this.getIndicatorHistory() + }, + + handleYearChange(e: any) { + const idx = Number(e.detail.value) + const selected = this.data.yearOptions[idx] + if (!selected) return + this.setData({ + selectedYear: selected.value, + selectedYearLabel: selected.label, }) + this.getIndicatorHistory() + }, + + handleCountChange(e: any) { + const idx = Number(e.detail.value) + const count = this.data.countOptions[idx] + this.setData({ filterCount: count }) + this.getIndicatorHistory() + }, + + // ========== 导航 ========== + + handleDetail(e: any) { + const { id, status } = e.currentTarget.dataset + if (status === 1) { + wx.navigateTo({ url: `/gift/pages/record/index?id=${id}` }) + } else { + wx.navigateTo({ url: `/gift/pages/recordDetail/index?id=${id}` }) + } }, + handleAdd() { - wx.navigateTo({ - url: '/gift/pages/record/index', - }) + wx.navigateTo({ url: '/gift/pages/record/index' }) + }, + + onReachBottom() { + const { page, pages } = this.data.pagination + if (page < pages) { + this.setData({ 'pagination.page': page + 1 }) + this.getList() + } }, }) diff --git a/src/gift/pages/recordList/index.wxml b/src/gift/pages/recordList/index.wxml index fe8f954..97e900d 100644 --- a/src/gift/pages/recordList/index.wxml +++ b/src/gift/pages/recordList/index.wxml @@ -4,40 +4,26 @@ 张先生,您好 - + 您的最近一次IgG4数值为: - 115 mg/dL + {{latestIgG4}} mg/dL - + - + - 按年 + {{year || '按年'}} - - 2025.08 + + {{beginDate ? beginDate : '开始时间'}} - - - 2025.09 + + {{endDate ? endDate : '结束时间'}} @@ -45,7 +31,7 @@ 血清IgG4趋势监测 - 单位mg/dL + 单位{{chartUnit}} @@ -56,40 +42,55 @@ 我的就诊历史总轴(按日期) - + - 2025-06-11 + {{item.visitDate}} - - lgG4值 + + + + IgG4值 - 385 + {{item.displayIgG4Value || '--'}} mg/dL - - - + + - 草稿 + {{item.statusText}} - + 激素用量 - 10mg/天 + {{item.oralHormoneDosage}}mg/天 - + 下次复诊时间 - 2025.06.11 + {{item.nextVisitDate}} + + 暂无就诊记录 + 新增就诊记录 diff --git a/src/images/bg43.png b/src/images/bg43.png new file mode 100644 index 0000000..9732d63 Binary files /dev/null and b/src/images/bg43.png differ diff --git a/src/images/bg44.png b/src/images/bg44.png new file mode 100644 index 0000000..962afed Binary files /dev/null and b/src/images/bg44.png differ diff --git a/src/images/icon145.png b/src/images/icon145.png new file mode 100644 index 0000000..69e039e Binary files /dev/null and b/src/images/icon145.png differ diff --git a/src/images/icon146.png b/src/images/icon146.png new file mode 100644 index 0000000..a7ad3f1 Binary files /dev/null and b/src/images/icon146.png differ diff --git a/src/images/logo.png b/src/images/logo.png new file mode 100644 index 0000000..21046f7 Binary files /dev/null and b/src/images/logo.png differ diff --git a/src/pages/caseReport/index.json b/src/pages/caseReport/index.json index 324a51a..cd76e72 100644 --- a/src/pages/caseReport/index.json +++ b/src/pages/caseReport/index.json @@ -1,4 +1,8 @@ { "navigationBarTitleText": "病例报告", - "usingComponents": {} + "usingComponents": { + "pagination": "/components/pagination/index", + "van-divider": "@vant/weapp/divider/index", + "van-loading": "@vant/weapp/loading/index" + } } diff --git a/src/pages/caseReport/index.scss b/src/pages/caseReport/index.scss index b1d39ec..b883dfe 100644 --- a/src/pages/caseReport/index.scss +++ b/src/pages/caseReport/index.scss @@ -60,24 +60,12 @@ page { } } } - .page-footer { - position: fixed; - bottom: 0; - left: 0; - width: 100%; - box-sizing: border-box; - padding: 32rpx 32rpx calc(env(safe-area-inset-bottom) + 32rpx); - background-color: #fff; - box-shadow: 0rpx -10rpx 30rpx 0rpx rgba(0, 0, 0, 0.01); - .btn { - font-size: 36rpx; - color: rgba(255, 255, 255, 1); - height: 96rpx; - display: flex; - align-items: center; - justify-content: center; - background: linear-gradient(86deg, #0eb66d 0%, #00d277 100%); - border-radius: 16rpx 16rpx 16rpx 16rpx; + .empty { + padding: 200rpx 0; + text-align: center; + .text { + font-size: 28rpx; + color: rgba(34, 34, 34, 0.4); } } } diff --git a/src/pages/caseReport/index.ts b/src/pages/caseReport/index.ts index 7a22cd8..fec95ba 100644 --- a/src/pages/caseReport/index.ts +++ b/src/pages/caseReport/index.ts @@ -1,13 +1,69 @@ -const _app = getApp() - Page({ - data: {}, - onLoad(options) { + data: { + imageField: '', + list: [] as { visitDate: string; images: string[] }[], + pagination: { count: 0, page: 1, pages: 1 }, + }, + + onLoad(options: any) { if (options.name) { - wx.setNavigationBarTitle({ - title: options.name, - }) + wx.setNavigationBarTitle({ title: options.name }) } + if (options.imageField) { + this.setData({ imageField: options.imageField }) + this.getImageHistory(true) + } + }, + + onReachBottom() { + const { page, pages } = this.data.pagination + if (page < pages) { + this.setData({ 'pagination.page': page + 1 }) + this.getImageHistory() + } + }, + + getImageHistory(reset = false) { + const page = reset ? 1 : this.data.pagination.page + wx.ajax({ + method: 'GET', + url: '?r=igg4/medical-visit/image-history', + data: { imageField: this.data.imageField, page, pageSize: 10 }, + }).then((res: any) => { + if (!res || !res.list) return + // 按就诊日期分组 + const groupMap: Record = {} + for (const item of res.list) { + if (!groupMap[item.visitDate]) { + groupMap[item.visitDate] = [] + } + groupMap[item.visitDate].push(item.imageUrl) + } + const newList = Object.keys(groupMap) + .sort((a, b) => b.localeCompare(a)) + .map((visitDate) => ({ + visitDate, + images: groupMap[visitDate], + })) + this.setData({ + list: reset ? newList : [...this.data.list, ...newList], + pagination: { + count: res.totalCount || 0, + page: res.page || 1, + pages: res.pages || 1, + }, + }) + }) + }, + + handlePreviewImage(e: WechatMiniprogram.CustomEvent) { + const { url, date } = e.currentTarget.dataset + const group = this.data.list.find((item) => item.visitDate === date) + if (!group) return + wx.previewImage({ + current: url, + urls: group.images, + }) }, }) diff --git a/src/pages/caseReport/index.wxml b/src/pages/caseReport/index.wxml index 6320ab7..089a6fa 100644 --- a/src/pages/caseReport/index.wxml +++ b/src/pages/caseReport/index.wxml @@ -1,17 +1,30 @@ - + - 2025-06-11 + {{item.visitDate}} - + + + 暂无记录 + diff --git a/src/pages/index/index.scss b/src/pages/index/index.scss index 1682327..f637c6e 100644 --- a/src/pages/index/index.scss +++ b/src/pages/index/index.scss @@ -481,7 +481,7 @@ page { .reg { position: fixed; left: 64rpx; - bottom: calc(env(safe-area-inset-bottom) + 120rpx); + bottom: calc(env(safe-area-inset-bottom) + 180rpx); width: 622rpx; background-color: rgba(39, 58, 101, 0.8); box-shadow: 0 8rpx 24rpx rgba(92, 144, 220, 0.25); @@ -505,7 +505,7 @@ page { .reg-audit { position: fixed; left: 34rpx; - bottom: calc(env(safe-area-inset-bottom) + 120rpx); + bottom: calc(env(safe-area-inset-bottom) + 180rpx); width: 682rpx; background-color: rgba(39, 58, 101, 0.8); box-shadow: 0 8rpx 24rpx rgba(92, 144, 220, 0.25); @@ -522,12 +522,12 @@ page { .public { position: fixed; left: 30rpx; - bottom: calc(env(safe-area-inset-bottom) + 120rpx); + bottom: calc(env(safe-area-inset-bottom) + 180rpx); width: 690rpx; height: 152rpx; - box-shadow: 0rpx 2rpx 16rpx 0rpx #390f1b2d; + box-shadow: 0rpx 4rpx 32rpx 0rpx rgba(0,0,0,0.08); border-radius: 24rpx; - background: linear-gradient(346deg, #ffffff 0%, #ffe2eb 100%); + background: linear-gradient(358deg, #ffffff 0%, #e1f4ec 100%); border: 2rpx solid #ffffff; display: flex; align-items: center; @@ -561,15 +561,15 @@ page { display: flex; align-items: center; justify-content: center; - background: #cf5375; + background: linear-gradient(188deg, #50e8a6 0%, #00d277 100%); border-radius: 12rpx 12rpx 12rpx 12rpx; } .close { position: absolute; top: 0; right: 0; - width: 48rpx; - height: 48rpx; + width: 40rpx; + height: 40rpx; } } } @@ -601,6 +601,12 @@ page { .action-btn.active { color: #5956e9; } + .public { + background: linear-gradient(358deg, #ffffff 0%, #ece9ff 100%); + .btn { + background: linear-gradient(274deg, #5956e9 0%, #b384f4 100%); + } + } } .slidearea { diff --git a/src/pages/index/index.ts b/src/pages/index/index.ts index 484dd42..0f2714f 100644 --- a/src/pages/index/index.ts +++ b/src/pages/index/index.ts @@ -26,6 +26,8 @@ Page({ detail: {}, + publicCard: false, + toastShow: false, toastType: '', // toastType: 'dedicatedDoctor', // 绑定医生弹窗 @@ -64,6 +66,7 @@ Page({ app.getUserInfo(this, true, (userInfo) => { this.setData({ userInfo, + publicCard: userInfo.isShowFollowGuide == 1, }) this.updateGreeting() this.updateNextVisitDays(userInfo) @@ -337,7 +340,7 @@ Page({ handleNextVisit() { app.permissionVerification(3, 0, '').then(() => { wx.navigateTo({ - url: '/pages/signIn/index', + url: '/gift/pages/record/index', }) }) }, @@ -437,4 +440,22 @@ Page({ }) }) }, + handlePublic() { + this.setData({ + toastShow: true, + toastType: 'public-toast', + toastParams: {}, + }) + this.handlePublicClose() + }, + handlePublicClose() { + this.setData({ + publicCard: false, + }) + wx.ajax({ + method: 'POST', + url: '?r=igg4/account/add-user-subscribe-guide-record', + data: {}, + }) + }, }) diff --git a/src/pages/index/index.wxml b/src/pages/index/index.wxml index 6c7b559..d483459 100644 --- a/src/pages/index/index.wxml +++ b/src/pages/index/index.wxml @@ -224,6 +224,15 @@ + + + + 关注公众号 + 重要提醒不丢失~ + + 去关注 + + - +