diff --git a/docs/openapi/监管端-风险预警中心.openapi.yaml b/docs/openapi/监管端-风险预警中心.openapi.yaml new file mode 100644 index 0000000..342df29 --- /dev/null +++ b/docs/openapi/监管端-风险预警中心.openapi.yaml @@ -0,0 +1,536 @@ +openapi: 3.0.3 +info: + title: 监管端-风险预警中心 API + description: | + 重庆市安全评价服务平台 - 监管端「风险预警中心」页面接口。 + + - 统一前缀:`/safetyEval/regulator/risk-center` + - 当前为 Mock 实现,数据存于 Controller 内存 + - 成功响应 `code = "0"` + + **Apifox 导入方式**:项目设置 → 导入数据 → 选择本文件(OpenAPI/Swagger 格式) + version: 1.0.0 + contact: + name: safety-eval-service + +servers: + - url: http://localhost:8095 + description: 本地开发 + - url: http://192.168.20.100:30140 + description: 测试网关(100) + +tags: + - name: 监管端-风险预警中心 + description: 风险预警中心页面相关接口 + +paths: + /safetyEval/regulator/risk-center/overview: + get: + tags: + - 监管端-风险预警中心 + summary: 页面概览 + description: 加载统计卡片与消息处理动作说明 + operationId: regulatorRiskOverview + responses: + '200': + description: 成功 + content: + application/json: + schema: + $ref: '#/components/schemas/SingleResponseRegulatorRiskOverviewCO' + example: + success: true + code: "0" + data: + stats: + - label: 未处理预警 + value: "5" + hint: 需监管人员处置 + - label: 紧急消息 + value: "4" + hint: 证书过期、社保异常 + - label: 重要提醒 + value: "2" + hint: 证书临期、变更停滞 + - label: 今日已处置 + value: "2" + hint: 含发函、确认、转办 + processGuide: 查看来源 → 核查材料/字段 → 发函或转办 → 设置处理结论 → 标记闭环。所有按钮均写入处置记录,用于监管留痕。 + + /safetyEval/regulator/risk-center/high-priority-alerts: + get: + tags: + - 监管端-风险预警中心 + summary: 高优先级消息列表 + description: 加载页面中部「高优先级消息」区块,默认返回紧急且未处理的前 2 条 + operationId: regulatorRiskHighPriorityAlerts + parameters: + - $ref: '#/components/parameters/levelParam' + - name: warningType + in: query + description: 预警类型 + schema: + type: string + enum: + - 证书过期 + - 社保异常 + - 信息变更 + - 项目超期 + - 账号限制 + - name: sourceModule + in: query + description: 来源模块 + schema: + type: string + example: 评价师信息管理 + - name: keyword + in: query + description: 标题/预警编号/预警内容关键字 + schema: + type: string + - name: onlyUntreated + in: query + description: 仅未处理(未处理/待确认/处理中) + schema: + type: boolean + default: true + - name: limit + in: query + description: 返回条数上限 + schema: + type: integer + default: 2 + minimum: 1 + responses: + '200': + description: 成功 + content: + application/json: + schema: + $ref: '#/components/schemas/SingleResponseRegulatorRiskPriorityAlertList' + example: + success: true + code: "0" + data: + - title: 评价师证书已过期 + description: 来源:评价师信息管理.证书有效期;触发:有效期至 2026-06-01。 + messageId: W-2026-008 + level: danger + warningType: 证书过期 + sourceModule: 评价师信息管理 + status: 未处理 + - title: 社保多处缴纳 + description: 来源:资质保持监控.社保缴纳单位;触发:同一人员两家机构。 + messageId: W-2026-007 + level: danger + warningType: 社保异常 + sourceModule: 资质保持监控 + status: 未处理 + + /safetyEval/regulator/risk-center/page: + get: + tags: + - 监管端-风险预警中心 + summary: 分页查询预警消息 + description: | + 消息列表分页查询,支持搜索栏与 Tab 筛选。 + + Tab 对应关系: + - 全部消息:`filterKind=all` 或不传 + - 紧急:`filterKind=urgent` + - 未读/未处理:`filterKind=unread` + operationId: regulatorRiskPage + parameters: + - name: keyword + in: query + description: 机构/人员/项目/预警编号 + schema: + type: string + - name: warningType + in: query + description: 预警类型 + schema: + type: string + enum: + - 证书过期 + - 社保异常 + - 信息变更 + - 项目超期 + - 账号限制 + - $ref: '#/components/parameters/levelParam' + - name: filterKind + in: query + description: Tab 筛选 + schema: + type: string + enum: + - all + - urgent + - unread + default: all + - $ref: '#/components/parameters/currentParam' + - $ref: '#/components/parameters/sizeParam' + responses: + '200': + description: 成功 + content: + application/json: + schema: + $ref: '#/components/schemas/PageResponseRegulatorRiskMessageCO' + example: + success: true + code: "0" + total: 4 + data: + - id: W-2026-008 + warningType: 证书过期 + level: urgent + levelName: 紧急 + sourceModule: 评价师信息管理 + sourceFields: + - 人员姓名 + - 证书类型 + - 有效期至 + content: 张建国一级安全评价师证书已过期,机构未上传延续材料。 + status: 未处理 + sourceModuleKey: evaluator + + /safetyEval/regulator/risk-center/handle: + post: + tags: + - 监管端-风险预警中心 + summary: 处置预警 + description: | + 处理弹窗提交、列表行内「闭环」「发函」「提醒」等操作。 + + status 自动推断规则(未传 status 时): + - handleType 含「闭环」→ 已闭环 + - handleType 含「发函」→ 已发函 + - handleType 含「提醒」→ 已提醒 + - handleType 含「转办」「转备案」→ 处理中 + - 其他 → 已处置 + operationId: regulatorRiskHandle + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/RegulatorRiskHandleCmd' + example: + id: W-2026-008 + handleType: 标记闭环 + deadline: "2026-07-18" + opinion: 请核查证书延续材料 + status: 已闭环 + responses: + '200': + description: 成功 + content: + application/json: + schema: + $ref: '#/components/schemas/SingleResponseRegulatorRiskMessageCO' + example: + success: true + code: "0" + data: + id: W-2026-008 + warningType: 证书过期 + level: urgent + levelName: 紧急 + sourceModule: 评价师信息管理 + sourceFields: + - 人员姓名 + - 证书类型 + - 有效期至 + content: 张建国一级安全评价师证书已过期,机构未上传延续材料。 + status: 已闭环 + sourceModuleKey: evaluator + '404': + description: 预警不存在 + content: + application/json: + schema: + $ref: '#/components/schemas/SingleResponseError' + example: + success: false + code: "404" + message: 预警不存在 + errMessage: 预警不存在 + +components: + parameters: + levelParam: + name: level + in: query + description: 等级编码 + schema: + type: string + enum: + - urgent + - important + - normal + default: urgent + currentParam: + name: current + in: query + description: 当前页 + schema: + type: integer + format: int64 + default: 1 + minimum: 1 + sizeParam: + name: size + in: query + description: 每页条数 + schema: + type: integer + format: int64 + default: 10 + minimum: 1 + + schemas: + # ---------- 通用响应 ---------- + SingleResponseError: + type: object + properties: + success: + type: boolean + example: false + code: + type: string + example: "404" + message: + type: string + errMessage: + type: string + + SingleResponseRegulatorRiskOverviewCO: + type: object + properties: + success: + type: boolean + example: true + code: + type: string + example: "0" + message: + type: string + errMessage: + type: string + data: + $ref: '#/components/schemas/RegulatorRiskOverviewCO' + + SingleResponseRegulatorRiskPriorityAlertList: + type: object + properties: + success: + type: boolean + example: true + code: + type: string + example: "0" + message: + type: string + errMessage: + type: string + data: + type: array + items: + $ref: '#/components/schemas/RegulatorRiskPriorityAlertCO' + + SingleResponseRegulatorRiskMessageCO: + type: object + properties: + success: + type: boolean + example: true + code: + type: string + example: "0" + message: + type: string + errMessage: + type: string + data: + $ref: '#/components/schemas/RegulatorRiskMessageCO' + + PageResponseRegulatorRiskMessageCO: + type: object + properties: + success: + type: boolean + example: true + code: + type: string + example: "0" + message: + type: string + errMessage: + type: string + total: + type: integer + format: int64 + description: 总条数 + example: 8 + data: + type: array + items: + $ref: '#/components/schemas/RegulatorRiskMessageCO' + + # ---------- 业务模型 ---------- + RegulatorRiskOverviewCO: + type: object + description: 页面概览 + properties: + stats: + type: array + description: 统计卡片 + items: + $ref: '#/components/schemas/StatCardCO' + processGuide: + type: string + description: 消息处理动作说明 + + StatCardCO: + type: object + properties: + label: + type: string + description: 标签 + example: 未处理预警 + value: + type: string + description: 数值 + example: "5" + hint: + type: string + description: 提示 + example: 需监管人员处置 + + RegulatorRiskPriorityAlertCO: + type: object + description: 高优先级预警消息 + properties: + title: + type: string + description: 标题 + example: 评价师证书已过期 + description: + type: string + description: 描述(含来源与触发规则) + messageId: + type: string + description: 关联预警编号 + example: W-2026-008 + level: + type: string + description: 展示级别 + enum: + - danger + - warning + - info + example: danger + warningType: + type: string + description: 预警类型 + example: 证书过期 + sourceModule: + type: string + description: 来源模块 + example: 评价师信息管理 + status: + type: string + description: 当前状态 + example: 未处理 + + RegulatorRiskMessageCO: + type: object + description: 预警消息 + properties: + id: + type: string + description: 预警编号 + example: W-2026-008 + warningType: + type: string + description: 预警类型 + enum: + - 证书过期 + - 社保异常 + - 信息变更 + - 项目超期 + - 账号限制 + level: + type: string + description: 等级编码 + enum: + - urgent + - important + - normal + levelName: + type: string + description: 等级名称 + enum: + - 紧急 + - 重要 + - 一般 + sourceModule: + type: string + description: 来源模块 + sourceFields: + type: array + description: 来源字段 + items: + type: string + content: + type: string + description: 预警内容 + status: + type: string + description: 状态 + enum: + - 未处理 + - 处理中 + - 待确认 + - 已闭环 + - 已发函 + - 已提醒 + - 已处置 + sourceModuleKey: + type: string + description: 来源模块跳转标识 + enum: + - evaluator + - qual-monitor + - qual-change + - institution-account + + RegulatorRiskHandleCmd: + type: object + description: 预警处置请求 + required: + - id + - handleType + properties: + id: + type: string + description: 预警编号 + example: W-2026-008 + handleType: + type: string + description: 处置方式 + example: 标记闭环 + deadline: + type: string + format: date + description: 办理期限 yyyy-MM-dd + example: "2026-07-18" + opinion: + type: string + description: 处置意见 + example: 请核查证书延续材料 + status: + type: string + description: 处置后状态(不传则根据 handleType 自动推断) + example: 已闭环 diff --git a/docs/监管端-风险预警中心接口文档.md b/docs/监管端-风险预警中心接口文档.md new file mode 100644 index 0000000..ad09463 --- /dev/null +++ b/docs/监管端-风险预警中心接口文档.md @@ -0,0 +1,303 @@ +# 监管端 - 风险预警中心接口文档 + +> 仅覆盖原型页 **风险预警中心**,Mock 数据内置于 `RegulatorRiskCenterController`,无数据库依赖。 +> 统一前缀:`/safetyEval/regulator/risk-center` +> 接口数量:**4 个** +> **OpenAPI 导入文件**:[监管端-风险预警中心.openapi.yaml](./openapi/监管端-风险预警中心.openapi.yaml)(可直接导入 Apifox) + +--- + +## 1. 页面与接口映射 + +| 页面区域 | 接口 | 说明 | +|----------|------|------| +| 顶部 4 个统计卡片 + 处理动作说明 | `GET /overview` | 页面首屏统计区 | +| 高优先级消息区块 | `GET /high-priority-alerts` | 支持等级/类型/来源等筛选 | +| 搜索栏 + Tab(全部/紧急/未读)+ 消息列表 | `GET /page` | 分页 + 筛选 | +| 处理 / 发函 / 闭环 / 提醒 / 审核 | `POST /handle` | 更新预警状态 | + +--- + +## 2. 通用约定 + +### 响应格式 + +成功时 `code = "0"`: + +```json +// SingleResponse +{ "success": true, "code": "0", "data": {} } + +// PageResponse +{ "success": true, "code": "0", "data": [], "total": 8 } +``` + +### 分页参数 + +| 参数 | 类型 | 默认 | 说明 | +|------|------|------|------| +| current | Long | 1 | 当前页 | +| size | Long | 10 | 每页条数 | + +--- + +## 3. 领域模型 + +### RegulatorRiskOverviewCO — 页面概览 + +| 字段 | 类型 | 说明 | +|------|------|------| +| stats | List\ | 统计卡片 | +| processGuide | String | 消息处理动作说明文案 | + +**StatCardCO**:`label` / `value` / `hint` + +### RegulatorRiskPriorityAlertCO — 高优先级消息 + +| 字段 | 类型 | 说明 | +|------|------|------| +| title | String | 标题 | +| description | String | 描述(含来源与触发规则) | +| messageId | String | 关联预警编号 | +| level | String | danger / warning / info | +| warningType | String | 预警类型 | +| sourceModule | String | 来源模块 | +| status | String | 当前状态 | + +### RegulatorRiskMessageCO — 预警消息 + +| 字段 | 类型 | 说明 | +|------|------|------| +| id | String | 预警编号,如 W-2026-008 | +| warningType | String | 证书过期 / 社保异常 / 信息变更 / 项目超期 / 账号限制 | +| level | String | urgent / important / normal | +| levelName | String | 紧急 / 重要 / 一般 | +| sourceModule | String | 来源模块名称 | +| sourceFields | List\ | 来源字段标签 | +| content | String | 预警内容 | +| status | String | 未处理 / 处理中 / 待确认 / 已闭环 / 已发函 / 已提醒 / 已处置 | +| sourceModuleKey | String | 来源跳转模块标识(evaluator、qual-monitor、qual-change 等) | + +--- + +## 4. 接口详情 + +### 4.1 GET `/overview` — 页面概览 + +**用途**:加载统计卡片、处理流程说明。 + +**响应示例**: + +```json +{ + "success": true, + "code": "0", + "data": { + "stats": [ + { "label": "未处理预警", "value": "5", "hint": "需监管人员处置" }, + { "label": "紧急消息", "value": "4", "hint": "证书过期、社保异常" }, + { "label": "重要提醒", "value": "2", "hint": "证书临期、变更停滞" }, + { "label": "今日已处置", "value": "2", "hint": "含发函、确认、转办" } + ], + "processGuide": "查看来源 → 核查材料/字段 → 发函或转办 → 设置处理结论 → 标记闭环。所有按钮均写入处置记录,用于监管留痕。" + } +} +``` + +> 统计数值由 Mock 消息列表动态计算,处置后再次请求会变化。 + +--- + +### 4.2 GET `/high-priority-alerts` — 高优先级消息 + +**用途**:加载页面中部「高优先级消息」区块,默认展示紧急且未处理的前 2 条。 + +**查询参数**: + +| 参数 | 必填 | 默认 | 说明 | +|------|------|------|------| +| level | 否 | urgent | 等级:urgent / important / normal | +| warningType | 否 | — | 证书过期、社保异常、信息变更、项目超期、账号限制 | +| sourceModule | 否 | — | 来源模块,如 评价师信息管理 | +| keyword | 否 | — | 标题/预警编号/预警内容关键字 | +| onlyUntreated | 否 | true | 仅未处理(未处理/待确认/处理中) | +| limit | 否 | 2 | 返回条数上限 | + +**请求示例**: + +``` +GET /safetyEval/regulator/risk-center/high-priority-alerts +GET /safetyEval/regulator/risk-center/high-priority-alerts?level=urgent&onlyUntreated=true&limit=2 +GET /safetyEval/regulator/risk-center/high-priority-alerts?level=important&limit=5 +``` + +**响应示例**: + +```json +{ + "success": true, + "code": "0", + "data": [ + { + "title": "评价师证书已过期", + "description": "来源:评价师信息管理.证书有效期;触发:有效期至 2026-06-01。", + "messageId": "W-2026-008", + "level": "danger", + "warningType": "证书过期", + "sourceModule": "评价师信息管理", + "status": "未处理" + }, + { + "title": "社保多处缴纳", + "description": "来源:资质保持监控.社保缴纳单位;触发:同一人员两家机构。", + "messageId": "W-2026-007", + "level": "danger", + "warningType": "社保异常", + "sourceModule": "资质保持监控", + "status": "未处理" + } + ] +} +``` + +--- + +### 4.3 GET `/page` — 分页查询消息列表 + +**查询参数**: + +| 参数 | 必填 | 说明 | +|------|------|------| +| keyword | 否 | 机构/人员/项目/预警编号 | +| warningType | 否 | 证书过期、社保异常、信息变更、项目超期、账号限制 | +| level | 否 | urgent / important / normal | +| filterKind | 否 | Tab 筛选:`all`(默认)/ `urgent` / `unread` | +| current | 否 | 当前页 | +| size | 否 | 每页条数 | + +**Tab 对应关系**(原型页右上角): + +| Tab | filterKind | +|-----|------------| +| 全部消息 | all 或不传 | +| 紧急 | urgent | +| 未读/未处理 | unread | + +**请求示例**: + +``` +GET /safetyEval/regulator/risk-center/page?filterKind=urgent¤t=1&size=10 +GET /safetyEval/regulator/risk-center/page?keyword=张建国&warningType=证书过期 +``` + +**响应示例**: + +```json +{ + "success": true, + "code": "0", + "total": 4, + "data": [ + { + "id": "W-2026-008", + "warningType": "证书过期", + "level": "urgent", + "levelName": "紧急", + "sourceModule": "评价师信息管理", + "sourceFields": ["人员姓名", "证书类型", "有效期至"], + "content": "张建国一级安全评价师证书已过期,机构未上传延续材料。", + "status": "未处理", + "sourceModuleKey": "evaluator" + } + ] +} +``` + +--- + +### 4.4 POST `/handle` — 处置预警 + +**用途**:处理弹窗提交、列表行内「闭环」「发函」「提醒」等操作。 + +**请求体**: + +```json +{ + "id": "W-2026-008", + "handleType": "标记闭环", + "deadline": "2026-07-18", + "opinion": "请核查证书延续材料", + "status": "已闭环" +} +``` + +| 字段 | 必填 | 说明 | +|------|------|------| +| id | 是 | 预警编号 | +| handleType | 是 | 发函核查 / 转备案审核 / 要求整改 / 标记闭环 / 已发函 / 已提醒 等 | +| deadline | 否 | 办理期限 | +| opinion | 否 | 处置意见 | +| status | 否 | 不传时根据 handleType 自动推断 | + +**status 自动推断规则**: + +| handleType 含 | 默认 status | +|---------------|-------------| +| 闭环 | 已闭环 | +| 发函 | 已发函 | +| 提醒 | 已提醒 | +| 转办 / 转备案 | 处理中 | +| 其他 | 已处置 | + +**响应**:返回更新后的 `RegulatorRiskMessageCO`。 + +--- + +## 5. 前端对接建议 + +```javascript +const BASE = '/safetyEval/regulator/risk-center'; + +// 1. 页面初始化 - 统计区 +const overview = await fetch(`${BASE}/overview`).then(r => r.json()); + +// 2. 高优先级消息(默认紧急未处理前2条) +const alerts = await fetch(`${BASE}/high-priority-alerts`).then(r => r.json()); + +// 3. Tab 切换 / 搜索 +const list = await fetch(`${BASE}/page?filterKind=unread¤t=1&size=10`).then(r => r.json()); + +// 4. 处置 +await fetch(`${BASE}/handle`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ id: 'W-2026-008', handleType: '标记闭环', status: '已闭环' }) +}); +``` + +**来源跳转**:使用 `sourceModuleKey` 切换监管端左侧菜单模块(与原型 `openRegSource()` 一致)。 + +--- + +## 6. 代码位置 + +| 类型 | 路径 | +|------|------| +| Controller(含 Mock) | `safety-eval-adapter/.../web/regulator/RegulatorRiskCenterController.java` | +| 响应模型 | `safety-eval-client/.../co/regulator/RegulatorRiskOverviewCO.java` | +| | `safety-eval-client/.../co/regulator/RegulatorRiskPriorityAlertCO.java` | +| | `safety-eval-client/.../co/regulator/RegulatorRiskMessageCO.java` | +| 入参模型 | `safety-eval-client/.../dto/regulator/RegulatorRiskPriorityAlertQuery.java` | +| | `safety-eval-client/.../dto/regulator/RegulatorRiskMessagePageQuery.java` | +| | `safety-eval-client/.../dto/regulator/RegulatorRiskHandleCmd.java` | + +--- + +## 7. 后续真实数据对接 + +保留上述 4 个接口契约不变,将 Controller 内 Mock 逻辑替换为领域服务调用即可,前端无需改动。 + +| 日期 | 说明 | +|------|------| +| 2026-07-14 | 初版:风险预警中心 3 接口 + Controller 内 Mock | +| 2026-07-14 | 拆分 highPriorityAlerts 为独立接口 `/high-priority-alerts` | diff --git a/pom.xml b/pom.xml index 942842e..6c2f662 100644 --- a/pom.xml +++ b/pom.xml @@ -46,8 +46,7 @@ 1.18.30 - - 1.7.0-SNAPSHOT + 1.7.1.1-SNAPSHOT 2.2.0 @@ -60,9 +59,8 @@ com.jjb.saas jjb-saas-system-client - 1.7.1.1-SNAPSHOT + ${jjb-saas-system-client.version} - com.zcloud.gbscommon zcloud_gbscommon @@ -232,18 +230,13 @@ - gbs-snapshots - GBS Snapshots Repository - http://192.168.20.100:8578/repository/maven-snapshots/ + gbs-public + GBS Public Repository (group) + http://192.168.20.100:8578/repository/maven-public/ true always - - - gbs-releases - GBS Releases Repository - http://192.168.20.100:8578/repository/maven-releases/ true diff --git a/safety-eval-adapter/src/main/java/org/qinan/safetyeval/adapter/web/regulator/RegulatorRiskCenterController.java b/safety-eval-adapter/src/main/java/org/qinan/safetyeval/adapter/web/regulator/RegulatorRiskCenterController.java new file mode 100644 index 0000000..5541926 --- /dev/null +++ b/safety-eval-adapter/src/main/java/org/qinan/safetyeval/adapter/web/regulator/RegulatorRiskCenterController.java @@ -0,0 +1,274 @@ +package org.qinan.safetyeval.adapter.web.regulator; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.qinan.safetyeval.client.co.regulator.RegulatorRiskMessageCO; +import org.qinan.safetyeval.client.co.regulator.RegulatorRiskOverviewCO; +import org.qinan.safetyeval.client.co.regulator.RegulatorRiskPriorityAlertCO; +import org.qinan.safetyeval.client.dto.PageResponse; +import org.qinan.safetyeval.client.dto.SingleResponse; +import org.qinan.safetyeval.client.dto.regulator.RegulatorRiskHandleCmd; +import org.qinan.safetyeval.client.dto.regulator.RegulatorRiskMessagePageQuery; +import org.qinan.safetyeval.client.dto.regulator.RegulatorRiskPriorityAlertQuery; +import org.springframework.util.StringUtils; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.PostConstruct; +import java.util.*; +import java.util.stream.Collectors; + +/** + * 监管端-风险预警中心(Mock,数据暂存于 Controller 内存) + */ +@Api(tags = "监管端-风险预警中心") +@RestController +@RequestMapping("/safetyEval/regulator/risk-center") +public class RegulatorRiskCenterController { + + private static final String PROCESS_GUIDE = "查看来源 → 核查材料/字段 → 发函或转办 → 设置处理结论 → 标记闭环。所有按钮均写入处置记录,用于监管留痕。"; + + private final List messages = new ArrayList<>(); + + @PostConstruct + public void initMockData() { + messages.clear(); + messages.add(message("W-2026-008", "证书过期", "urgent", "评价师信息管理", + Arrays.asList("人员姓名", "证书类型", "有效期至"), + "张建国一级安全评价师证书已过期,机构未上传延续材料。", "未处理", "evaluator")); + messages.add(message("W-2026-007", "社保异常", "urgent", "资质保持监控", + Arrays.asList("人员姓名", "所在机构", "社保缴纳单位"), + "王丽萍在恒安安全评价和渝安风险评估同时缴纳社保。", "未处理", "qual-monitor")); + messages.add(message("W-2026-006", "证书临期", "important", "资质保持监控", + Arrays.asList("证书有效期", "预警阈值"), + "陈华安全评价师二级证书将于 2026-08-01 到期,距到期不足 30 天。", "处理中", "evaluator")); + messages.add(message("W-2026-005", "信息变更", "normal", "备案变更管理", + Arrays.asList("注册地址", "变更材料"), + "恒安安全评价注册地址变更材料超过 5 个工作日未确认。", "待确认", "qual-change")); + messages.add(message("W-2026-004", "项目超期", "important", "项目过程控制", + Arrays.asList("项目名称", "计划完成日期"), + "某化工项目安全评价报告超过计划节点 7 天未完成。", "未处理", "qual-monitor")); + messages.add(message("W-2026-003", "账号限制", "normal", "机构账号管理", + Arrays.asList("机构名称", "账号状态"), + "渝安风险评估中心账号处于禁用状态,仍有新业务备案尝试。", "待确认", "institution-account")); + messages.add(message("W-2026-002", "证书过期", "urgent", "评价师信息管理", + Arrays.asList("人员姓名", "证书类型", "有效期至"), + "李明华注册安全工程师证书已过期。", "已闭环", "evaluator")); + messages.add(message("W-2026-001", "社保异常", "urgent", "资质保持监控", + Arrays.asList("人员姓名", "社保缴纳单位"), + "赵磊社保缴纳单位与备案机构不一致。", "已发函", "qual-monitor")); + } + + @ApiOperation("页面概览(统计卡片 + 处理动作说明)") + @GetMapping("/overview") + public SingleResponse overview() { + RegulatorRiskOverviewCO co = new RegulatorRiskOverviewCO(); + co.setStats(buildStats()); + co.setProcessGuide(PROCESS_GUIDE); + return SingleResponse.success(co); + } + + @ApiOperation("高优先级消息列表") + @GetMapping("/high-priority-alerts") + public SingleResponse> highPriorityAlerts(RegulatorRiskPriorityAlertQuery query) { + if (query == null) { + query = new RegulatorRiskPriorityAlertQuery(); + } + return SingleResponse.success(buildHighPriorityAlerts(query)); + } + + @ApiOperation("分页查询预警消息") + @GetMapping("/page") + public PageResponse page(@Validated RegulatorRiskMessagePageQuery query) { + List filtered = messages.stream() + .filter(item -> matchQuery(query, item)) + .collect(Collectors.toList()); + long current = query.getCurrent() == null || query.getCurrent() < 1 ? 1L : query.getCurrent(); + long size = query.getSize() == null || query.getSize() < 1 ? 10L : query.getSize(); + int from = (int) ((current - 1) * size); + List page; + if (from >= filtered.size()) { + page = Collections.emptyList(); + } else { + int to = Math.min(from + (int) size, filtered.size()); + page = filtered.subList(from, to); + } + return PageResponse.of(page, (long) filtered.size()); + } + + @ApiOperation("处置预警(处理/发函/闭环/提醒等)") + @PostMapping("/handle") + public SingleResponse handle(@Validated @RequestBody RegulatorRiskHandleCmd cmd) { + Optional optional = messages.stream() + .filter(m -> m.getId().equals(cmd.getId())) + .findFirst(); + if (!optional.isPresent()) { + return SingleResponse.error("404", "预警不存在"); + } + RegulatorRiskMessageCO message = optional.get(); + message.setStatus(resolveStatus(cmd)); + return SingleResponse.success(message); + } + + private List buildStats() { + long untreated = messages.stream().filter(m -> isUntreated(m.getStatus())).count(); + long urgent = messages.stream().filter(m -> "urgent".equals(m.getLevel())).count(); + long important = messages.stream().filter(m -> "important".equals(m.getLevel())).count(); + long handledToday = messages.stream().filter(m -> isHandledToday(m.getStatus())).count(); + return Arrays.asList( + stat("未处理预警", String.valueOf(untreated), "需监管人员处置"), + stat("紧急消息", String.valueOf(urgent), "证书过期、社保异常"), + stat("重要提醒", String.valueOf(important), "证书临期、变更停滞"), + stat("今日已处置", String.valueOf(handledToday), "含发函、确认、转办") + ); + } + + private List buildHighPriorityAlerts(RegulatorRiskPriorityAlertQuery query) { + Map titles = new HashMap<>(); + titles.put("W-2026-008", new String[]{"评价师证书已过期", "来源:评价师信息管理.证书有效期;触发:有效期至 2026-06-01。"}); + titles.put("W-2026-007", new String[]{"社保多处缴纳", "来源:资质保持监控.社保缴纳单位;触发:同一人员两家机构。"}); + int limit = query.getLimit() == null || query.getLimit() < 1 ? 2 : query.getLimit(); + return messages.stream() + .filter(m -> matchPriorityQuery(query, m)) + .limit(limit) + .map(m -> toPriorityAlert(m, titles)) + .collect(Collectors.toList()); + } + + private boolean matchPriorityQuery(RegulatorRiskPriorityAlertQuery query, RegulatorRiskMessageCO item) { + if (StringUtils.hasText(query.getLevel()) && !query.getLevel().equals(item.getLevel())) { + return false; + } + if (StringUtils.hasText(query.getWarningType()) && !query.getWarningType().equals(item.getWarningType())) { + return false; + } + if (StringUtils.hasText(query.getSourceModule()) && !query.getSourceModule().equals(item.getSourceModule())) { + return false; + } + if (Boolean.TRUE.equals(query.getOnlyUntreated()) && !isUntreated(item.getStatus())) { + return false; + } + if (StringUtils.hasText(query.getKeyword())) { + String kw = query.getKeyword().toLowerCase(); + String text = (item.getId() + item.getContent() + item.getWarningType() + item.getSourceModule()).toLowerCase(); + if (!text.contains(kw)) { + return false; + } + } + return true; + } + + private RegulatorRiskPriorityAlertCO toPriorityAlert(RegulatorRiskMessageCO m, Map titles) { + RegulatorRiskPriorityAlertCO alert = new RegulatorRiskPriorityAlertCO(); + String[] preset = titles.get(m.getId()); + if (preset != null) { + alert.setTitle(preset[0]); + alert.setDescription(preset[1]); + } else { + alert.setTitle(m.getWarningType()); + alert.setDescription("来源:" + m.getSourceModule() + ";" + m.getContent()); + } + alert.setMessageId(m.getId()); + alert.setLevel(alertLevel(m.getLevel())); + alert.setWarningType(m.getWarningType()); + alert.setSourceModule(m.getSourceModule()); + alert.setStatus(m.getStatus()); + return alert; + } + + private String alertLevel(String level) { + if ("urgent".equals(level)) { + return "danger"; + } + if ("important".equals(level)) { + return "warning"; + } + return "info"; + } + + private boolean matchQuery(RegulatorRiskMessagePageQuery query, RegulatorRiskMessageCO item) { + if (StringUtils.hasText(query.getKeyword())) { + String kw = query.getKeyword().toLowerCase(); + String text = (item.getId() + item.getContent() + item.getWarningType()).toLowerCase(); + if (!text.contains(kw)) { + return false; + } + } + if (StringUtils.hasText(query.getWarningType()) && !query.getWarningType().equals(item.getWarningType())) { + return false; + } + if (StringUtils.hasText(query.getLevel()) && !query.getLevel().equals(item.getLevel())) { + return false; + } + if (StringUtils.hasText(query.getFilterKind()) && !"all".equals(query.getFilterKind())) { + if ("urgent".equals(query.getFilterKind()) && !"urgent".equals(item.getLevel())) { + return false; + } + if ("unread".equals(query.getFilterKind()) && !isUntreated(item.getStatus())) { + return false; + } + } + return true; + } + + private String resolveStatus(RegulatorRiskHandleCmd cmd) { + if (StringUtils.hasText(cmd.getStatus())) { + return cmd.getStatus(); + } + String type = cmd.getHandleType(); + if (type.contains("闭环")) { + return "已闭环"; + } + if (type.contains("发函")) { + return "已发函"; + } + if (type.contains("提醒")) { + return "已提醒"; + } + if (type.contains("转办") || type.contains("转备案")) { + return "处理中"; + } + return "已处置"; + } + + private boolean isUntreated(String status) { + return Arrays.asList("未处理", "待确认", "处理中").contains(status); + } + + private boolean isHandledToday(String status) { + return Arrays.asList("已闭环", "已发函", "已提醒", "已处置").contains(status); + } + + private RegulatorRiskOverviewCO.StatCardCO stat(String label, String value, String hint) { + RegulatorRiskOverviewCO.StatCardCO card = new RegulatorRiskOverviewCO.StatCardCO(); + card.setLabel(label); + card.setValue(value); + card.setHint(hint); + return card; + } + + private RegulatorRiskMessageCO message(String id, String type, String level, String module, + List fields, String content, String status, String moduleKey) { + RegulatorRiskMessageCO co = new RegulatorRiskMessageCO(); + co.setId(id); + co.setWarningType(type); + co.setLevel(level); + co.setLevelName(levelName(level)); + co.setSourceModule(module); + co.setSourceFields(fields); + co.setContent(content); + co.setStatus(status); + co.setSourceModuleKey(moduleKey); + return co; + } + + private String levelName(String level) { + if ("urgent".equals(level)) { + return "紧急"; + } + if ("important".equals(level)) { + return "重要"; + } + return "一般"; + } +} diff --git a/safety-eval-client/src/main/java/org/qinan/safetyeval/client/co/regulator/RegulatorRiskMessageCO.java b/safety-eval-client/src/main/java/org/qinan/safetyeval/client/co/regulator/RegulatorRiskMessageCO.java new file mode 100644 index 0000000..2bcf26e --- /dev/null +++ b/safety-eval-client/src/main/java/org/qinan/safetyeval/client/co/regulator/RegulatorRiskMessageCO.java @@ -0,0 +1,40 @@ +package org.qinan.safetyeval.client.co.regulator; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.List; + +/** + * 风险预警消息 + */ +@Data +public class RegulatorRiskMessageCO { + + @ApiModelProperty("预警编号") + private String id; + + @ApiModelProperty("预警类型") + private String warningType; + + @ApiModelProperty("等级编码:urgent/important/normal") + private String level; + + @ApiModelProperty("等级名称:紧急/重要/一般") + private String levelName; + + @ApiModelProperty("来源模块") + private String sourceModule; + + @ApiModelProperty("来源字段") + private List sourceFields; + + @ApiModelProperty("预警内容") + private String content; + + @ApiModelProperty("状态") + private String status; + + @ApiModelProperty("来源模块跳转标识") + private String sourceModuleKey; +} diff --git a/safety-eval-client/src/main/java/org/qinan/safetyeval/client/co/regulator/RegulatorRiskOverviewCO.java b/safety-eval-client/src/main/java/org/qinan/safetyeval/client/co/regulator/RegulatorRiskOverviewCO.java new file mode 100644 index 0000000..673a69a --- /dev/null +++ b/safety-eval-client/src/main/java/org/qinan/safetyeval/client/co/regulator/RegulatorRiskOverviewCO.java @@ -0,0 +1,32 @@ +package org.qinan.safetyeval.client.co.regulator; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.List; + +/** + * 风险预警中心页面概览 + */ +@Data +public class RegulatorRiskOverviewCO { + + @ApiModelProperty("统计卡片") + private List stats; + + @ApiModelProperty("消息处理动作说明") + private String processGuide; + + @Data + public static class StatCardCO { + + @ApiModelProperty("标签") + private String label; + + @ApiModelProperty("数值") + private String value; + + @ApiModelProperty("提示") + private String hint; + } +} diff --git a/safety-eval-client/src/main/java/org/qinan/safetyeval/client/co/regulator/RegulatorRiskPriorityAlertCO.java b/safety-eval-client/src/main/java/org/qinan/safetyeval/client/co/regulator/RegulatorRiskPriorityAlertCO.java new file mode 100644 index 0000000..25d0dc4 --- /dev/null +++ b/safety-eval-client/src/main/java/org/qinan/safetyeval/client/co/regulator/RegulatorRiskPriorityAlertCO.java @@ -0,0 +1,32 @@ +package org.qinan.safetyeval.client.co.regulator; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * 高优先级预警消息 + */ +@Data +public class RegulatorRiskPriorityAlertCO { + + @ApiModelProperty("标题") + private String title; + + @ApiModelProperty("描述") + private String description; + + @ApiModelProperty("关联预警编号") + private String messageId; + + @ApiModelProperty("级别:danger/warning/info") + private String level; + + @ApiModelProperty("预警类型") + private String warningType; + + @ApiModelProperty("来源模块") + private String sourceModule; + + @ApiModelProperty("消息状态") + private String status; +} diff --git a/safety-eval-client/src/main/java/org/qinan/safetyeval/client/dto/regulator/RegulatorRiskHandleCmd.java b/safety-eval-client/src/main/java/org/qinan/safetyeval/client/dto/regulator/RegulatorRiskHandleCmd.java new file mode 100644 index 0000000..58a8441 --- /dev/null +++ b/safety-eval-client/src/main/java/org/qinan/safetyeval/client/dto/regulator/RegulatorRiskHandleCmd.java @@ -0,0 +1,30 @@ +package org.qinan.safetyeval.client.dto.regulator; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotBlank; + +/** + * 风险预警处置 + */ +@Data +public class RegulatorRiskHandleCmd { + + @NotBlank + @ApiModelProperty("预警编号") + private String id; + + @NotBlank + @ApiModelProperty("处置方式:发函核查/转备案审核/要求整改/标记闭环/已发函/已提醒等") + private String handleType; + + @ApiModelProperty("办理期限 yyyy-MM-dd") + private String deadline; + + @ApiModelProperty("处置意见") + private String opinion; + + @ApiModelProperty("处置后状态,不传则根据 handleType 推断") + private String status; +} diff --git a/safety-eval-client/src/main/java/org/qinan/safetyeval/client/dto/regulator/RegulatorRiskMessagePageQuery.java b/safety-eval-client/src/main/java/org/qinan/safetyeval/client/dto/regulator/RegulatorRiskMessagePageQuery.java new file mode 100644 index 0000000..5877c41 --- /dev/null +++ b/safety-eval-client/src/main/java/org/qinan/safetyeval/client/dto/regulator/RegulatorRiskMessagePageQuery.java @@ -0,0 +1,26 @@ +package org.qinan.safetyeval.client.dto.regulator; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.qinan.safetyeval.client.dto.BasePageQuery; + +/** + * 风险预警消息分页查询 + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class RegulatorRiskMessagePageQuery extends BasePageQuery { + + @ApiModelProperty("关键词:机构/人员/项目/预警编号") + private String keyword; + + @ApiModelProperty("预警类型:证书过期/社保异常/信息变更/项目超期/账号限制") + private String warningType; + + @ApiModelProperty("等级:urgent/important/normal") + private String level; + + @ApiModelProperty("Tab筛选:all/urgent/unread") + private String filterKind; +} diff --git a/safety-eval-client/src/main/java/org/qinan/safetyeval/client/dto/regulator/RegulatorRiskPriorityAlertQuery.java b/safety-eval-client/src/main/java/org/qinan/safetyeval/client/dto/regulator/RegulatorRiskPriorityAlertQuery.java new file mode 100644 index 0000000..0bedc04 --- /dev/null +++ b/safety-eval-client/src/main/java/org/qinan/safetyeval/client/dto/regulator/RegulatorRiskPriorityAlertQuery.java @@ -0,0 +1,29 @@ +package org.qinan.safetyeval.client.dto.regulator; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * 高优先级预警查询 + */ +@Data +public class RegulatorRiskPriorityAlertQuery { + + @ApiModelProperty("等级:urgent/important/normal,默认 urgent") + private String level = "urgent"; + + @ApiModelProperty("预警类型:证书过期/社保异常/信息变更/项目超期/账号限制") + private String warningType; + + @ApiModelProperty("来源模块") + private String sourceModule; + + @ApiModelProperty("关键词:标题/预警编号/预警内容") + private String keyword; + + @ApiModelProperty("仅未处理:true 时筛选 未处理/待确认/处理中,默认 true") + private Boolean onlyUntreated = true; + + @ApiModelProperty("返回条数上限,默认 2") + private Integer limit = 2; +} diff --git a/safety-eval-start/src/main/resources/nacos/config-spring.yml b/safety-eval-start/src/main/resources/nacos/config-spring.yml index 68a2311..cff5f3a 100644 --- a/safety-eval-start/src/main/resources/nacos/config-spring.yml +++ b/safety-eval-start/src/main/resources/nacos/config-spring.yml @@ -156,6 +156,7 @@ safety-eval: - /qual-filing-personnel-cert - /file-storage - /file + - /regulator authenticated-paths: [] authenticated-prefixes: [] public-api: