safety-eval-service/docs/机构端首页驾驶舱接口设计.md

106 lines
8.0 KiB
Markdown
Raw Normal View History

# 机构端首页(驾驶舱)接口设计
> 对应前端路由:`/container/driver?pageMode=3` → 机构端首页 `Institution/Dashboard`
> 基址:`/safetyEval/institution/dashboard`
> 全部为**新增**聚合接口,落在 `InstitutionDashboardController`,未改动任何既有功能/接口。
> 实现位置:`safety-eval-client/.../co/institution/dashboard/*CO`、`.../api/institution/InstitutionDashboardApi`、`safety-eval-adapter/.../web/institution/InstitutionDashboardController`、`safety-eval-app/.../executor/institution/InstitutionDashboardExecutor`
## 1. 页面动态数据项 → 接口映射
| 大屏板块 | 动态项 | 对应接口 |
|---|---|---|
| 当前项目节点统计 | 项目总数 / 法定项目 + 8 节点待办 + 已归档 + 项目延期 | `GET /project-node-stats` |
| 通知提醒 | 资质现场审查通知 / 监督检查通知 / 未读监管通知 | `GET /notices` |
| 服务行业项目统计 | 各行业「项目数 / 法定项目数」 | `GET /industry-stat` |
| 评价类别占比 | 各评价类别项目数 + 总数 | `GET /eval-type-ratio` |
| 项目执行情况 | 项目列表(编号/名称/被评价企业/类别/负责人/结束日期) | `GET /project-execution` |
## 2. 公共约定
- 鉴权:`orgId` 取自 `ThreadLocalUserInfoAdapter`(机构端请求上下文,由网关/拦截器注入)。若取不到 `orgId`,所有接口返回空数据(不报错),便于未登录/非机构场景降级。
- 聚合策略:复用既有 `EvalProjectGateway.page()`、`EvalProjectNodeOverviewAssembler.buildForInstitution()`、`SafetyMessageGateway.page()`、`EvalCustomerGateway.get()`,在内存做聚合,**不新写脆弱 SQL**,避免 N+1 与跨库耦合。
- 性能:建议前端对 5 个接口加 30~60s 短 TTL 缓存;面板级相互独立,单接口异常不影响其余面板。
- 响应:`SingleResponse<CO>`,成功 `code="0"`
## 3. 接口清单
### 3.1 GET /project-node-stats — 当前项目节点统计
- **入参**:无
- **出参** `InstitutionDashboardProjectNodeStatsCO`
- `totalProjects` 项目总数
- `statutoryProjects` 法定项目数
- `nodeStats[]``nodeCode`(NODE_01..NODE_08)、`nodeName`(待X)、`pendingCount`(待办数)
- `archivedProjectCount` 已归档项目数
- `delayedProjectCount` 项目延期数
- **边界**仅统计当前机构orgId名下项目节点待办口径 = 节点状态为「未开始」(与监管端 `processOverview` 一致)。
- **数据源**`eval_project`orgId 过滤)、`EvalProjectNodeOverviewAssembler.buildForInstitution(projectId)`(节点状态)、`EvalProjectGateway.countByOrgIdAndProgressStatus(orgId,"DELAY")`(延期)。
- **业务逻辑**
1. `listOrgProjects(orgId)` 取本机构全部项目;
2. 总数 / 法定项目(`is_statutory=1`)计数;
3. 逐项目 `buildForInstitution` 取 8 节点,状态为「未开始」则该节点 `pendingCount+1`(单项目装配异常 try-catch 跳过,保证整体可用);
4. `archiveFlag=1` 计已归档;`progressStatus=DELAY` 计延期。
### 3.2 GET /notices — 通知提醒
- **入参**:无
- **出参** `InstitutionDashboardNoticeCO`
- `qualOnSiteReviewCount` 资质现场审查通知数(`sendType=ON_SITE_REVIEW_NOTICE`
- `inspectionCount` 监督检查通知数(`sendType=INSP_NOTICE_ORG`
- `unreadRegulatoryCount` 未读监管通知数(本机构消息中 `sendState!=1`
- **边界**:仅统计本机构消息;未读 = `sendState` 非 1已读标记 `MessageSendStateEnum.SENT=1`)。
- **数据源**`safety_message``SafetyMessageGateway.page`,按 orgId + sendType 统计总数;按 orgId 取列表过滤未读)。
- **业务逻辑**
1.`orgId + sendType=ON_SITE_REVIEW_NOTICE``total`
2.`orgId + sendType=INSP_NOTICE_ORG``total`
3.`orgId` 取消息列表,统计 `sendState!=1` 的数量(消息量较大时受 `PAGE_SIZE=1000` 限制,机构维度一般远小于此值)。
### 3.3 GET /industry-stat — 服务行业项目统计
- **入参**:无
- **出参** `InstitutionDashboardIndustryStatCO`
- `list[]``industryCode`、`industryName`、`projectCount`、`statutoryProjectCount`
- **边界**:仅返回「有项目」的行业(前端按固定类目轴渲染,缺失类目补 0行业名称取自 `IndustryEnum`
- **数据源**`eval_project`orgId 过滤),按 `industry_code` 分组,法定项目按 `is_statutory=1` 再计。
- **业务逻辑**`listOrgProjects` → `groupBy(industryCode)` → 每组计项目数 / 法定项目数,名称用 `IndustryEnum.ofCode(code).value`
### 3.4 GET /eval-type-ratio — 评价类别占比
- **入参**:无
- **出参** `InstitutionDashboardEvalTypeRatioCO`
- `totalProjectCount` 项目总数
- `items[]``evalTypeCode`、`evalTypeName`、`count`
- **边界**:仅本机构;评价类型名称取自 `EvalTypeEnum`PRE 安全预评价 / ACCEPT 安全设施竣工验收评价 / STATUS 安全现状评价)。
- **数据源**`eval_project`orgId 过滤),按 `eval_type_code` 分组。
- **业务逻辑**`listOrgProjects` → `groupBy(evalTypeCode)` → 计各组数量与总和,名称用 `EvalTypeEnum.ofCode(code).value`
### 3.5 GET /project-execution — 项目执行情况
- **入参**`limit`(可选,默认 10范围 1~50
- **出参** `InstitutionDashboardProjectExecutionCO`
- `list[]``projectId`、`projectNo`(项目编号)、`projectName`、`customerName`(被评价企业)、`evalTypeCode`、`evalTypeName`、`projectLeaderName`(项目负责人)、`planEndDate`(yyyy-MM-dd)
- **边界**:仅本机构;按 `planEndDate` 升序取前 `limit` 条(最近到期在前,空日期置尾);被评价企业名称经 `EvalCustomerGateway.get(customerId)` 解析(解析失败置空,不影响其余行)。
- **数据源**`eval_project`orgId 过滤)、`eval_customer``EvalCustomerGateway.get`)。
- **业务逻辑**`listOrgProjects` → 按 `planEndDate` 升序 → `take(limit)` → 逐行映射,评价类别名称用 `EvalTypeEnum`,被评价企业名称查客户表。
## 4. 已知缺口 / 口径说明
1. **行业类目不一致**:前端 `mockData.js` 硬编码 7 个行业(危险化学品/非煤矿山/金属冶炼/工贸/烟花爆竹/石油天然气/其他行业),与数据库 `IndustryEnum`COAL_MINING 煤炭开采业… 等 8 类)**不一致**。本接口返回 `IndustryEnum` 真实编码/名称,前端需以其固定类目轴对齐合并(缺失补 0
2. **评价类别名称**:前端写「安全验收评价」,实际 `EvalTypeEnum.ACCEPT` 为「安全设施竣工验收评价」,按枚举真实值返回。
3. **消息未读口径**`safety_message.send_state` 仅 0/1未读/已读);`unreadRegulatoryCount` 统计 `sendState!=1`,即本机构全部未读监管消息(含资质现场审查、监督检查、报告抽查等)。
4. **节点待办口径**:与监管端一致,待办 = 节点状态「未开始」。处于「进行中/退回」的节点不计入待办(计入已到达)。
5. **项目延期**:直接复用 `EvalProjectGateway.countByOrgIdAndProgressStatus(orgId,"DELAY")`,与系统既有延期判定一致。
6. **未做写操作**:本批接口均为只读聚合,不改写任何表。
## 5. 文件清单(均为新增)
- `safety-eval-client/.../co/institution/dashboard/InstitutionDashboardProjectNodeStatsCO.java`
- `safety-eval-client/.../co/institution/dashboard/InstitutionDashboardNoticeCO.java`
- `safety-eval-client/.../co/institution/dashboard/InstitutionDashboardIndustryStatCO.java`
- `safety-eval-client/.../co/institution/dashboard/InstitutionDashboardEvalTypeRatioCO.java`
- `safety-eval-client/.../co/institution/dashboard/InstitutionDashboardProjectExecutionCO.java`
- `safety-eval-client/.../api/institution/InstitutionDashboardApi.java`
- `safety-eval-adapter/.../web/institution/InstitutionDashboardController.java`
- `safety-eval-app/.../executor/institution/InstitutionDashboardExecutor.kt`
- `docs/openapi/机构端-首页驾驶舱.openapi.yaml`