diff --git a/clinical-web/AGENTS.md b/clinical-web/AGENTS.md index a7a6582..936f499 100644 --- a/clinical-web/AGENTS.md +++ b/clinical-web/AGENTS.md @@ -49,14 +49,13 @@ src/ - 不在 API 文件中创建新的 Axios 实例,不在 API 层操作组件、路由或 `ElMessage`。 - 所有请求通过 `request` 单例发送;接口函数必须提供明确的返回类型。 - 接口地址使用相对路径,不重复写基础地址。 -- 业务接口的列表、详情、创建、更新和删除函数按资源命名,例如: +- 业务接口的列表、详情、创建、更新和删除函数按资源命名;没有后端接口时不要在前端伪造一个不存在的地址。报表当前由现有任务、模板和组织接口在 API 边界聚合,例如: ```ts -import { request } from '@/utils/request' -import type { ReportOverviewResponse, ReportQuery } from './types' +import { getReportTaskData } from './reports' -export function getReportOverview(params: ReportQuery) { - return request.get('/management/reports/overview', { params }) +export async function loadReports() { + return getReportTaskData() } ``` diff --git a/clinical-web/README.md b/clinical-web/README.md index fe8662d..243d9a8 100644 --- a/clinical-web/README.md +++ b/clinical-web/README.md @@ -163,7 +163,7 @@ API 模块与页面按业务域对应。工作台页面使用 `api/workbench` 用户与权限页面的接口核验结果、当前缺口和后端接口建议见 [`docs/users-permissions-api.md`](./docs/users-permissions-api.md)。 -报表页在真实模式下使用 `GET /api/v1/sign-tasks` 聚合当前任务数据,并支持跳转任务和导出当前筛选结果;MEDISIGN 文档中暂无独立的报表统计接口。首页同样从模板、院区和签署任务接口聚合工作台概览。 +报表页在真实模式下使用 `GET /api/v1/sign-tasks` 读取全部可见分页,并结合模板、院区和科室接口在前端临时聚合,支持跳转任务和导出当前筛选结果;MEDISIGN 文档中暂无独立的报表统计接口。报表接口核验、前端统计口径和后端缺口见 [`docs/reports-api.md`](./docs/reports-api.md)。首页同样从模板、院区和签署任务接口聚合工作台概览。 首页前端修复记录及后端聚合接口需求见 [`docs/workbench-home-api.md`](./docs/workbench-home-api.md)。 diff --git a/clinical-web/docs/reports-api.md b/clinical-web/docs/reports-api.md new file mode 100644 index 0000000..dfd6ff2 --- /dev/null +++ b/clinical-web/docs/reports-api.md @@ -0,0 +1,223 @@ +# 报表分析模块接口核验与后端接口需求 + +> 核验基准:MEDISIGN 患者电子签 API 文档([https://ipad.shenynet.com/doc.html#/home](https://ipad.shenynet.com/doc.html#/home))。 +> +> 本次核验时间:2026-09-01。接口文档当前为 v1,未提供独立的“报表分析”接口分组。 + +## 1. 核验结论 + +当前报表页面可以使用现有签署任务、模板和组织接口完成基础展示,但后端暂时没有报表聚合能力。页面真实模式目前采用以下临时方案: + +1. 查询当前用户有权查看的全部签署任务; +2. 按接口允许的最大页大小 200 条循环请求所有分页; +3. 使用模板接口补充文档名称和类别; +4. 使用院区、科室接口补充筛选字典; +5. 在前端按业务时间范围聚合指标、趋势和科室分布。 + +这个方案适合联调和小数据量验证,不适合作为长期报表架构。任务量增大后,首次打开页面会产生多次请求并占用浏览器内存;而且当前任务列表只支持按 `createdAt` 查询,无法让后端直接按签署完成时间或过期时间聚合。 + +## 2. 当前已接入接口 + +| 页面功能 | 接口 | 状态 | 说明 | +| -------------- | ------------------------------------------ | ------ | -------------------------------------------------------------------------------------------------- | +| 签署任务明细 | `GET /api/v1/sign-tasks` | 已接入 | 读取所有可见分页,使用 `page`、`size`,最大页大小为 200 | +| 任务状态 | `GET /api/v1/sign-tasks` | 已接入 | 使用 `CREATED`、`WAITING_SIGN`、`GENERATING`、`SIGNED`、`EXPIRED`、`VOIDED`、`FAILED` 映射页面状态 | +| 任务时间 | `GET /api/v1/sign-tasks` | 已接入 | 使用 `createdAt`、`signedAt`、`expiredAt` | +| 文档名称和类别 | `GET /api/v1/templates/available-versions` | 已接入 | 用 `templateVersionId` 关联模板版本;历史模板不可见时只能降级显示 | +| 院区筛选 | `GET /api/v1/campuses` | 已接入 | 动态生成院区选项,并用 `campusId` 映射任务院区 | +| 科室筛选 | `GET /api/v1/departments` | 已接入 | 动态生成科室选项;任务中出现的科室也会补入选项 | +| 明细查看 | 工作台任务详情路由 | 已接入 | 点击明细跳转签署工作台,由工作台查询任务详情和签署文件 | +| 当前筛选导出 | 浏览器生成 CSV | 已接入 | 导出当前已加载且按创建时间筛选的任务;不是后端审计型导出 | + +`GET /api/v1/sign-tasks` 当前文档明确支持的筛选字段包括: + +- `page`、`size`; +- `keyword`、`patientId`、`visitId`、`templateVersionId`; +- `status`、`signMethod`、`campusId`、`departmentId`; +- `createdFrom`、`createdTo`。 + +响应中已经提供报表所需的基础字段:任务状态、签署方式、患者和就诊脱敏快照、院区/科室 ID、`signedAt`、`expiredAt`、`createdAt` 和 `updatedAt`。文档没有提供独立的聚合统计响应,也没有提供签署耗时字段。 + +## 3. 本轮前端修复 + +- 删除了原先指向不存在的 `/management/reports/overview` 的报表 API;统一通过 `src/api/management/reports.ts` 聚合真实接口。 +- 修复只读取第 1 页、最多 200 条导致的统计和导出不完整问题。 +- 每日趋势改为按 `signedAt` 统计,不再按任务创建时间冒充签署完成时间。 +- “签署完成”按本期 `signedAt` 统计;“累计发起任务”和明细仍按本期 `createdAt` 统计。 +- “按时签署率”只统计有签署/过期时间的终态任务,并以 `signedAt <= expiredAt` 判断签署是否按时;`VOIDED`、`FAILED` 和未完成任务不进入分母。 +- 平均用时不再默认填充 7 分钟;当前按 `signedAt - createdAt` 计算任务完成耗时,没有可用数据时显示 `—`。 +- `month` 趋势按当月实际天数生成;`custom` 增加起止日期并校验起始日期不能晚于结束日期。 +- `FAILED` 单独显示为“处理失败”,不再错误归类为“已作废”。 +- 导出增加签署完成时间和过期时间,文件名使用本地日期,且导出内容覆盖全部已加载分页。 +- 任务院区优先使用 `campusId` 对应的组织字典,避免字典顺序或默认值导致院区误归类。 + +## 4. 当前前端统计口径 + +当前临时聚合的时间范围使用医院浏览器本地时间。生产环境建议由后端统一按 `Asia/Shanghai` 计算。 + +### 4.1 指标卡 + +- `累计发起任务`:`createdAt` 在当前日期范围内,且符合院区、科室、文档类别筛选的任务数。 +- `签署完成`:`status=SIGNED` 且 `signedAt` 在当前日期范围内的任务数。 +- `按时签署率`:本期已签署任务与本期已超时任务作为终态样本;分子为 `signedAt <= expiredAt` 的已签署任务,分母为两类终态任务之和。 +- `平均签署用时`:当前使用 `signedAt - createdAt` 的平均分钟数。该值是“任务从创建到完成的总耗时”,不是患者实际落笔时长。 + +### 4.2 趋势和科室分布 + +- 每日趋势按 `SIGNED` 任务的 `signedAt` 按自然日统计。 +- 科室分布按本期完成签署的任务、使用任务科室名称统计。 +- 明细表按 `createdAt` 筛选,便于核对本期发起的任务;这意味着明细条数与“本期签署完成”可能不完全相等,后端聚合接口上线后建议在界面上明确两个时间维度。 + +## 5. 后端缺口与推荐接口 + +### 5.1 签署报表聚合接口(最高优先级) + +建议新增: + +```http +GET /api/v1/reports/signing/overview +X-Token: {登录令牌} +``` + +建议请求参数: + +| 参数 | 类型 | 必填 | 说明 | +| --------------------------- | ------------- | ---- | ------------------------------------------------ | +| `createdFrom` / `createdTo` | ISO-8601 | 否 | 发起任务统计和明细的时间范围 | +| `signedFrom` / `signedTo` | ISO-8601 | 否 | 签署完成、趋势和完成分布的时间范围 | +| `expiredFrom` / `expiredTo` | ISO-8601 | 否 | 超时任务统计的时间范围 | +| `campusId` | UUID | 否 | 院区筛选;不传表示当前权限范围内全部院区 | +| `departmentId` | UUID | 否 | 科室筛选 | +| `category` | string | 否 | 文档类别,建议使用模板的稳定分类编码 | +| `signMethod` | `PAD` / `SMS` | 否 | 签署方式筛选 | +| `timezone` | string | 否 | 默认 `Asia/Shanghai`;建议服务端固定或校验白名单 | +| `detailPage` / `detailSize` | integer | 否 | 明细分页,`detailSize` 最大 200 | + +建议响应: + +```json +{ + "code": 0, + "message": "OK", + "data": { + "timezone": "Asia/Shanghai", + "metrics": { + "initiatedCount": 128, + "signedCount": 112, + "onTimeSignedCount": 108, + "onTimeDenominator": 120, + "onTimeRate": 90.0, + "averageCompletionDurationSeconds": 382, + "durationSampleCount": 112 + }, + "trend": [ + { + "date": "2026-09-01", + "signedCount": 32 + } + ], + "departments": [ + { + "departmentId": "科室 UUID", + "departmentName": "消化内科", + "initiatedCount": 40, + "signedCount": 36, + "onTimeSignedCount": 35, + "onTimeRate": 87.5 + } + ], + "details": { + "records": [], + "page": 1, + "size": 200, + "total": 128, + "pages": 1 + } + }, + "traceId": "链路追踪 ID", + "timestamp": "2026-09-01T08:00:00Z" +} +``` + +后端应在 SQL 聚合前执行当前用户的数据范围、模板 ACL 和院区/科室权限过滤,不能让前端拉取无权数据后再过滤。`onTimeRate` 的分母、是否排除作废任务、过期任务的口径需要在接口契约中固定,不能由不同页面各自猜测。 + +### 5.2 稳定的模板快照信息 + +当前任务响应只有 `templateVersionId` 和模板版本信息;如果模板不再处于当前用户可见的可用版本列表,报表无法可靠获取名称和类别,只能显示版本号或根据文档名称猜测分类。 + +建议在签署任务响应中增加不可变的模板快照摘要,或由报表接口直接返回: + +```json +{ + "templateId": "模板 UUID", + "templateVersionId": "模板版本 UUID", + "templateName": "胃镜检查知情同意书", + "templateCategory": "EXAM_CONSENT" +} +``` + +分类应使用稳定编码和展示字典,不建议前端继续通过“入院”“告知”等中文名称关键词推断。 + +### 5.3 可审计的签署耗时字段 + +`createdAt` 到 `signedAt` 只能表示任务生命周期耗时,短信等待和患者未操作时间会被计入。若产品要展示真正的签署用时,建议返回: + +```json +{ + "signStartedAt": "2026-09-01T07:53:00Z", + "signedAt": "2026-09-01T08:00:02Z", + "signDurationSeconds": 422 +} +``` + +其中 `signStartedAt` 应来自签署投递/签署事件,而不是前端打开页面时自行记录。聚合接口应同时返回有效样本数;没有有效耗时样本时返回 `null`,前端显示 `—`。 + +### 5.4 后端导出接口 + +当前 CSV 是浏览器导出,只适合已加载的少量明细,不能替代正式导出。建议提供异步导出: + +```http +POST /api/v1/reports/signing/export-jobs +GET /api/v1/reports/signing/export-jobs/{jobId} +GET /api/v1/reports/signing/export-jobs/{jobId}/download +``` + +导出任务请求复用报表筛选条件,响应返回任务状态、文件有效期和下载地址。导出的每一行都应在服务端按权限过滤,并记录操作人、筛选条件摘要、生成时间、文件过期时间和 `traceId`。文件中只返回当前角色允许查看的脱敏患者字段,不应包含明文身份证号、手机号或完整病历。 + +### 5.5 时间范围查询能力(没有聚合接口时的最低要求) + +如果近期无法提供聚合接口,至少请扩展 `GET /api/v1/sign-tasks`: + +- 增加 `signedFrom`、`signedTo`; +- 增加 `expiredFrom`、`expiredTo`; +- 明确多个状态、时间条件的组合语义; +- 保证 `total`、`page`、`size`、`pages` 在权限过滤后保持一致; +- 保证分页排序稳定,例如按 `createdAt DESC, id DESC`; +- 如需前端核对总量,提供按条件返回的汇总字段,避免客户端循环读取全部历史任务。 + +## 6. 权限、错误和审计要求 + +推荐复用现有统一响应包和错误约定: + +| HTTP 状态 | 场景 | +| --------- | ------------------------------------- | +| `200` | 查询或导出任务创建成功 | +| `400` | 日期格式、范围、分页或筛选参数错误 | +| `401` | 未登录或令牌失效 | +| `403` | 无报表查询权限或超出院区/科室数据范围 | +| `404` | 导出任务不存在或已过期 | +| `409` | 导出条件版本或数据快照冲突 | +| `429` | 导出任务频率超限 | +| `500` | 服务端聚合或文件生成异常 | + +报表查询、导出和下载都应记录审计信息;审计内容记录筛选条件摘要即可,不要记录明文患者证件号、手机号、签名原图或完整病历内容。 + +## 7. 前端联调验收标准 + +- 院区、科室、文档类别和签署方式筛选只返回当前用户有权查看的数据。 +- 趋势按 `signedAt` 统计;任务延迟签署时不会落入创建日。 +- 超时按 `expiredAt` 统计;跨自然日时按 `Asia/Shanghai` 计算。 +- 签署耗时没有有效样本时返回空值并显示 `—`,不使用固定默认值。 +- 明细支持服务端分页;导出结果不受浏览器已加载条数限制。 +- 同一筛选条件的指标、趋势、科室汇总和明细使用明确且一致的时间口径。 +- 返回 `traceId`,前端错误提示可以关联后端日志排查。