fix: 对齐运维页面原型并收口权限边界
- 删除模型大类概览和细分银行概览中原型未包含的过渡跳转按钮,保留卡片点击、筛选、指标趋势和详情入口。 - 移除运维系统配置页中的模型平台新增页面依赖、登录角色来源等内部说明,仅保留实际配置内容。 - 将开发工作台访问控制统一收敛到 dashboard:view,业务团队仅保留运维工作台权限;直接访问开发工作台时自动回到运维工作台。 - 补充架构实现基线、外部写入协议、运维 API 清单、三角色权限验收说明和首条纵向链路联调手册。 - 按当前实现更新架构变更记录和本周目标完成情况。
This commit is contained in:
@@ -1,6 +1,13 @@
|
||||
# 架构设计变更记录
|
||||
|
||||
## **当前最新版本:V0.2**
|
||||
## **当前最新版本:V0.3**
|
||||
|
||||
### V0.3 · 2026-09-02
|
||||
|
||||
- 将设计稿与当前工程实现对齐,明确首条链路实际读取 `model_deploy + model_operations`。
|
||||
- 补充已实现的模型列表、模型详情、单月监控结果和运维工作台接口说明。
|
||||
- 补充三角色权限来源、页面/操作权限校验以及 `dashboard:view` 与运维工作台权限的边界。
|
||||
- 标记真实非空数据联调、Workspace 映射和三角色实账号验收为本周剩余事项。
|
||||
|
||||
### V0.2 · 2026-08-31
|
||||
|
||||
|
||||
@@ -81,7 +81,6 @@ SELECT r.role_id, p.permission_id
|
||||
FROM roles AS r
|
||||
JOIN permissions AS p
|
||||
ON p.permission_code IN (
|
||||
'dashboard:view',
|
||||
'operations:workbench:view',
|
||||
'operations:model-overview:view',
|
||||
'operations:bank-overview:view',
|
||||
@@ -103,6 +102,16 @@ ON DUPLICATE KEY UPDATE
|
||||
is_deleted = 0,
|
||||
deleted_at = NULL;
|
||||
|
||||
-- 矩阵修正:业务团队只进入运维工作台,不允许进入开发工作台。
|
||||
UPDATE role_permissions AS rp
|
||||
JOIN roles AS r ON r.role_id = rp.role_id
|
||||
JOIN permissions AS p ON p.permission_id = rp.permission_id
|
||||
SET rp.is_deleted = 1,
|
||||
rp.deleted_at = CURRENT_TIMESTAMP(3)
|
||||
WHERE r.role_code = 'business_team'
|
||||
AND p.permission_code = 'dashboard:view'
|
||||
AND rp.is_deleted = 0;
|
||||
|
||||
-- 模型团队:developer 角色对应模型团队。
|
||||
INSERT INTO role_permissions (role_id, permission_id)
|
||||
SELECT r.role_id, p.permission_id
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
# A 卡模型运维模块三角色权限验收说明 V0.1
|
||||
|
||||
> 状态:前后端权限接入完成,等待真实账号执行验收
|
||||
> 日期:2026-09-02
|
||||
|
||||
## 一、权限来源
|
||||
|
||||
1. 当前用户登录后通过 `/api/v1/auth/me` 返回 `role_code` 和 `permissions`。
|
||||
2. `/api/v1/platform/permissions` 只用于管理员维护权限目录,不作为当前用户权限来源。
|
||||
3. 运维前端菜单、页面直达和操作按钮读取 `/auth/me` 的权限集合。
|
||||
4. 运维后端在 `OperationsContext` 中加载同一权限集合,并对已实现接口再次校验。
|
||||
5. 管理员由服务端管理员身份兜底拥有全部运维权限。
|
||||
|
||||
## 二、角色约定
|
||||
|
||||
- `admin`:管理员。
|
||||
- `developer`:模型团队。
|
||||
- `business_team`:业务团队。
|
||||
|
||||
开发工作台使用 `dashboard:view`;运维工作台使用 `operations:workbench:view`。业务团队不得拥有 `dashboard:view`。
|
||||
|
||||
## 三、页面验收
|
||||
|
||||
### 业务团队
|
||||
|
||||
可以访问:运维工作台、平台模型大类、细分银行、监控概览、监控详情、监控诊断报告、历史报告汇总和全流程进度。
|
||||
|
||||
可以操作:监控详情终审、报告导出、流程发起、流程反馈和流程确认。
|
||||
|
||||
不能访问:开发工作台、平台使用统计、已上线模型详情、文档知识库、监控等级规则、报告 Prompt 管理和系统配置。
|
||||
|
||||
### 模型团队
|
||||
|
||||
可以访问:开发工作台、运维工作台、模型大类、细分银行、已上线模型详情、监控概览、监控详情、监控诊断报告、历史报告汇总、全流程进度、文档知识库、监控等级规则和报告 Prompt 管理。
|
||||
|
||||
可以操作:监控详情初审、报告编辑/导出/发送、流程提交材料/推进/上线、规则只读、Prompt 编辑和提交回归。
|
||||
|
||||
不能访问:平台使用统计和系统配置。
|
||||
|
||||
### 管理员
|
||||
|
||||
可以访问全部开发、运维和系统管理页面。
|
||||
|
||||
可以操作全部运维配置、规则发布/回滚/测算、Prompt 管理、用户管理、项目管理和角色权限管理。
|
||||
|
||||
## 四、验收用例
|
||||
|
||||
1. 使用业务账号登录,确认 `/auth/me` 返回 `business_team`,菜单不出现开发工作台。
|
||||
2. 业务账号直接访问 `/workbench`,应跳转到 `/operations`。
|
||||
3. 业务账号直接访问 `/operations/deployed-models`,应返回无权限页面或被路由拦截。
|
||||
4. 业务账号打开模型监控详情,只出现终审处理能力,不出现初审能力。
|
||||
5. 使用模型账号登录,确认 `developer` 映射为模型团队,开发工作台和模型侧操作可用。
|
||||
6. 模型账号打开监控详情,只出现初审处理能力,不出现终审能力。
|
||||
7. 模型账号打开规则页面,只读查看,不能发布、回滚或测算。
|
||||
8. 使用管理员账号登录,确认全部页面和全部管理操作可用。
|
||||
9. 删除或软删除某个权限关联后,重新登录确认菜单和后端接口同时拒绝访问。
|
||||
10. 三种角色分别请求无权限接口,后端返回 `403 OPERATIONS_PERMISSION_DENIED`。
|
||||
|
||||
## 五、执行前提
|
||||
|
||||
1. 在 `model_platform` 执行角色权限矩阵 SQL。
|
||||
2. 给业务账号分配 `business_team` 角色。
|
||||
3. 撤销业务团队的 `dashboard:view`。
|
||||
4. 三个账号退出后重新登录,重新加载权限。
|
||||
5. 记录菜单截图、`/auth/me` 响应和接口状态码作为验收附件。
|
||||
@@ -0,0 +1,144 @@
|
||||
# A 卡模型运维模块数据库外部写入协议 V0.1
|
||||
|
||||
> 状态:模型方评估稿;首条接口链路按本协议准备数据
|
||||
> 日期:2026-09-02
|
||||
> 目标:明确模型方写入哪些表,运维平台读取哪些字段,哪些字段由运维平台自行生成
|
||||
|
||||
## 一、当前首条链路的实际数据来源
|
||||
|
||||
当前后端首条链路不是读取 `ops_banks/ops_model_instances/ops_model_versions`,而是:
|
||||
|
||||
1. 模型部署和版本信息从 `model_deploy` 库读取。
|
||||
2. 月度监控批次和监控结果从 `model_operations` 库读取。
|
||||
3. 判级、复核和处理快照从 `model_operations` 库读取。
|
||||
|
||||
因此,模型方需要先按现有部署库表写入模型基础信息,再按运维库监控源表写入月度结果。`ops_banks`、`ops_model_instances`、`ops_model_versions` 如继续保留,应在后续确认后再接入,不能与当前链路同时作为模型主源。
|
||||
|
||||
## 二、模型方负责写入的部署库表
|
||||
|
||||
### 2.1 `model_deploy`
|
||||
|
||||
至少需要提供:
|
||||
|
||||
- `id`:部署实例主键。
|
||||
- `code`:业务模型 ID,建议 Workspace 内唯一。
|
||||
- `name`:模型名称。
|
||||
- `modelType`:模型类型。
|
||||
- `status`:部署状态;当前接口映射为正常/下线。
|
||||
- `role`:部署角色;陪跑状态需要与现有枚举确认。
|
||||
- `currentVersion`:当前版本号。
|
||||
- `group_code`:Workspace 或模型大类映射信息。
|
||||
- `space_id`:关联 `sys_project_space.id`。
|
||||
- `gmtCreated`、`gmtModified`:创建和最后变更时间。
|
||||
|
||||
### 2.2 `model_bank`
|
||||
|
||||
- `bankNo`:银行编码。
|
||||
- `bankName`:银行名称。
|
||||
- `isWuji`:是否无极银行。
|
||||
- `status`:银行是否有效。
|
||||
|
||||
### 2.3 `model_deploy_bank_map`
|
||||
|
||||
- `deployId`:对应 `model_deploy.id`。
|
||||
- `bankNo`:对应 `model_bank.bankNo`。
|
||||
- `status`:关系是否有效。
|
||||
|
||||
### 2.4 `model_version`
|
||||
|
||||
- `id`:版本主键。
|
||||
- `deployId`:对应部署实例。
|
||||
- `version`:版本号。
|
||||
- `versionName`:版本展示名称。
|
||||
- `isCurrent`:是否当前版本。
|
||||
- `gmtCreated`、`gmtModified`:版本时间。
|
||||
|
||||
### 2.5 Workspace 映射
|
||||
|
||||
模型部署记录至少需要满足以下一种映射:
|
||||
|
||||
- `sys_project_space.name = 认证 Workspace 名称`;
|
||||
- `sys_project_space.name = 认证 Workspace code`;
|
||||
- `model_deploy.group_code = 认证 Workspace code`。
|
||||
|
||||
最终映射方式需要模型方和运维方共同确认。
|
||||
|
||||
## 三、模型方负责写入的运维库源表
|
||||
|
||||
### 3.1 `ops_monitor_batches`
|
||||
|
||||
模型方每次生成一个月度批次,至少写入:
|
||||
|
||||
- `batch_id`:批次 ID。
|
||||
- `workspace_id`:认证 Workspace ID。
|
||||
- `source_system`:来源系统。
|
||||
- `source_batch_no`:来源批次号,必须幂等。
|
||||
- `monitor_month`:监控月份,保存为该月第一天。
|
||||
- `revision_no`:同月修订号,从 1 开始递增。
|
||||
- `batch_status`:先写 `writing`,校验完成后改为 `published`。
|
||||
- `expected_model_count`、`written_model_count`:模型数量校验。
|
||||
- `feature_row_count`、`distribution_row_count`:明细行数校验。
|
||||
- `checksum_sha256`、`generated_at`、`published_at`。
|
||||
|
||||
只有 `published` 批次对运维页面可见。
|
||||
|
||||
### 3.2 `ops_monitor_results`
|
||||
|
||||
每个模型每个月一行,至少写入:
|
||||
|
||||
- `monitor_result_id`:结果 ID。
|
||||
- `workspace_id`:必须与批次和认证 Workspace 一致。
|
||||
- `batch_id`:所属批次。
|
||||
- `model_instance_id`:建议写 `model_deploy.id`,以便当前接口直接关联。
|
||||
- `model_version_id`:对应 `model_version.id`。
|
||||
- `monitor_month`:监控月份。
|
||||
- `source_result_ref`:来源结果编号,可辅助追溯。
|
||||
- `ranking_result`:`matched`、`unmatched` 或 `not_applicable`。
|
||||
- `ks_value`、`psi_value`:数据库保存 0~1 比率。
|
||||
- `sample_count`、`good_count`、`bad_count`。
|
||||
- `source_result_json`、`source_calculated_at`:可选追溯字段。
|
||||
|
||||
当前查询服务兼容用 `model_deploy.id`、`model_deploy.code` 或版本 ID 作为关联标识,但生产环境必须固定一种主规则。
|
||||
|
||||
### 3.3 `ops_monitor_feature_metrics`
|
||||
|
||||
后续特征级页面需要时写入:特征编码、名称、IV、CSI、前期值、变化率以及来源 JSON。该表不用于首条三页面链路的最低验收。
|
||||
|
||||
### 3.4 `ops_monitor_distributions`
|
||||
|
||||
后续评分分布和特征分布页面需要时写入:分箱顺序、分箱标签、基准期/当期账户数和占比、好坏账户数、坏账率、PSI/CSI 分量。该表不用于首条三页面链路的最低验收。
|
||||
|
||||
## 四、运维平台自行生成的数据
|
||||
|
||||
以下数据不由模型方写入:
|
||||
|
||||
1. A/B/C 监控结果等级。
|
||||
2. 一级/二级/三级异常等级。
|
||||
3. 命中原因、处理建议和阈值解释。
|
||||
4. 模型团队初审、业务团队终审和默认不处理记录。
|
||||
5. 报告正文、报告版本、Prompt 版本和发送状态。
|
||||
6. 流程进度、材料确认、知识库索引和平台使用统计。
|
||||
|
||||
模型方只负责提供原始指标及其追溯信息,不能直接写入判级和处理结果字段。
|
||||
|
||||
## 五、发布协议
|
||||
|
||||
1. 创建 `writing` 批次。
|
||||
2. 写入模型月度结果和后续明细。
|
||||
3. 校验模型数量、结果数量、指标范围、Workspace 和关联 ID。
|
||||
4. 完成校验后将批次改为 `published`。
|
||||
5. 同月旧批次改为 `superseded`,不覆盖历史数据。
|
||||
6. 失败批次保留 `failed` 状态并记录原因。
|
||||
|
||||
## 六、最小联调数据
|
||||
|
||||
首条链路只需要:
|
||||
|
||||
- 1 条有效银行。
|
||||
- 1 条有效模型部署。
|
||||
- 1 条有效银行关系。
|
||||
- 1 条有效模型版本。
|
||||
- 1 条 `published` 监控批次。
|
||||
- 1 条对应月份的监控结果。
|
||||
|
||||
如果需要展示等级和处理状态,再补 1 条当前判级记录及对应复核记录。
|
||||
@@ -54,7 +54,7 @@
|
||||
|
||||
### 3. API 清单
|
||||
|
||||
状态:首条链路接口已实现,完整 API 契约文档尚未完成。
|
||||
状态:首条链路接口已实现,独立 API 清单已完成初稿。
|
||||
|
||||
当前已注册并可从 OpenAPI 查到:
|
||||
|
||||
@@ -92,7 +92,7 @@
|
||||
|
||||
### 5. 三角色登录与 RBAC 基础能力
|
||||
|
||||
状态:登录和角色适配已有,三角色真实账号验收未完成。
|
||||
状态:登录、角色适配、权限读取和前后端基础校验已完成,三角色真实账号验收未完成。
|
||||
|
||||
已具备:
|
||||
|
||||
@@ -137,26 +137,26 @@
|
||||
|
||||
1. **没有非空真实数据**:这是首条纵向链路还不能验收的首要原因。
|
||||
2. **三角色没有完成真实账号矩阵验收**:现有代码具备基础,但还没有形成可签字的验收记录。
|
||||
3. **设计文档与实现状态未同步**:现有架构 V0.2 仍写着“接口尚未实现”,需要新版本勘误。
|
||||
3. **三角色真实账号验收**:权限代码和 SQL 已准备完成,还需要用业务、模型和管理员账号实际验证菜单、页面、按钮和接口。
|
||||
|
||||
## 四、现在可以先写的文档
|
||||
|
||||
以下内容不依赖全部业务功能完成,可以立即起草:
|
||||
以下内容已先完成初稿,不依赖真实非空数据:
|
||||
|
||||
1. **技术架构与实现说明 V0.3**:以当前双数据库、FastAPI、React 和真实接口代码为准,标出已实现/待实现边界。
|
||||
2. **数据库模型与外部写入协议 V0.2**:列出模型方需要写入的表、字段、写入时机、批次状态、幂等和发布规则。
|
||||
3. **运维 API 清单 V0.1**:先固化已实现的 5 个接口,再把后续接口标为规划项。
|
||||
4. **三角色登录/RBAC 验收说明 V0.1**:列出角色、菜单、页面、接口和写操作验收项。
|
||||
5. **首条纵向链路联调手册 V0.1**:写清测试数据准备、请求顺序、预期响应和数值核对点。
|
||||
6. **本周目标验收记录 V0.1**:等模型方提供非空数据后,直接补充实际请求和截图结果。
|
||||
1. **技术架构与实现说明 V0.3**:已完成,标出当前双数据库、FastAPI、React 和真实接口边界。
|
||||
2. **数据库外部写入协议 V0.1**:已完成,列出模型方写入表、字段、批次发布和关联要求。
|
||||
3. **运维 API 清单 V0.1**:已完成,固化已实现的 5 个接口并列出规划接口。
|
||||
4. **三角色登录/RBAC 验收说明 V0.1**:已完成,列出角色、菜单、页面、接口和操作验收项。
|
||||
5. **首条纵向链路联调手册 V0.1**:已完成,写清测试数据、请求顺序、预期响应和核对点。
|
||||
6. **本周目标验收记录 V0.1**:已完成基线,待非空数据后补实际请求和截图结果。
|
||||
|
||||
## 五、建议本周剩余顺序
|
||||
|
||||
1. 先让模型方补一套最小非空数据,不等待全部页面完成。
|
||||
2. 先完成列表—详情—单月结果的真实联调和数值核对。
|
||||
3. 同时用三种角色做登录、菜单和接口权限验收。
|
||||
4. 根据联调结果更新架构 V0.3、数据库外部写入协议 V0.2 和 API 清单 V0.1。
|
||||
5. 最后再扩展工作台、监控明细、报告和流程等页面的接口。
|
||||
4. 根据联调结果补充本周目标验收记录,不再重复调整已冻结的基础文档。
|
||||
5. 在首条链路验收后扩展工作台、监控明细、报告和流程等页面的接口。
|
||||
|
||||
## 六、当前不可对外承诺的内容
|
||||
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
# A 卡模型运维模块运维 API 清单 V0.1
|
||||
|
||||
> 状态:首条真实接口链路已实现;其余业务接口列为后续实现项
|
||||
> 日期:2026-09-02
|
||||
> 鉴权:复用登录 Cookie;需要 Workspace 的接口必须传 `workspace_id`
|
||||
|
||||
## 一、统一约定
|
||||
|
||||
1. 浏览器请求使用同源 `/api/v1/*`,Cookie 由浏览器自动携带。
|
||||
2. 成功响应统一使用 `{ request_id, data, meta }` 包装。
|
||||
3. `workspace_id` 为 26 位 Workspace ID;后端同时校验登录身份、Workspace 成员关系和运维权限。
|
||||
4. 月份参数格式固定为 `YYYY-MM`,数据库月份使用当月第一天保存。
|
||||
5. 数据库中的 KS、PSI、IV、CSI 等比率按 0~1 保存,API 返回前端展示百分数。
|
||||
6. 没有数据时返回空数组或业务层空结果,不使用演示数据填充页面。
|
||||
|
||||
## 二、已实现接口
|
||||
|
||||
### 2.1 运维健康检查
|
||||
|
||||
`GET /api/v1/operations/health`
|
||||
|
||||
- 用途:检查运维库、部署只读库和关键表状态。
|
||||
- 鉴权:服务健康检查接口,是否要求登录以部署配置为准。
|
||||
- 返回:服务状态、数据库状态、关键表检查结果。
|
||||
|
||||
### 2.2 模型列表
|
||||
|
||||
`GET /api/v1/operations/models`
|
||||
|
||||
查询参数:
|
||||
|
||||
- `workspace_id`:必填。
|
||||
- `bank`:可选,银行名称。
|
||||
- `category`:可选,`std`、`bai`、`big`、`afd`。
|
||||
- `status`:可选,模型状态。
|
||||
- `keyword`:可选,匹配银行、模型名称、模型 ID 或版本。
|
||||
|
||||
权限:`operations:model-overview:view`。
|
||||
|
||||
数据来源:
|
||||
|
||||
- `model_deploy.model_deploy`
|
||||
- `model_deploy.model_bank`
|
||||
- `model_deploy.model_deploy_bank_map`
|
||||
- `model_deploy.model_version`
|
||||
- `model_operations.ops_monitor_batches`
|
||||
- `model_operations.ops_monitor_results`
|
||||
- 当前判级和处理快照表(存在时读取)
|
||||
|
||||
返回字段包括:银行、模型大类、模型名称、模型 ID、模型版本、模型状态、最近迭代日期、排序性、KS、PSI、KS 环比降幅、异常命中次数、最近处理日期和历史处理建议。
|
||||
|
||||
### 2.3 模型详情
|
||||
|
||||
`GET /api/v1/operations/models/{model_id}`
|
||||
|
||||
查询参数:
|
||||
|
||||
- `workspace_id`:必填。
|
||||
|
||||
权限:`operations:monitoring-detail:view`。
|
||||
|
||||
模型 ID 当前支持使用 `model_deploy.code`;后端同时兼容部署表主键和版本关联标识。模型不存在返回:
|
||||
|
||||
```json
|
||||
{
|
||||
"detail": {
|
||||
"code": "MODEL_NOT_FOUND",
|
||||
"message": "模型不存在"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2.4 单月监控结果
|
||||
|
||||
`GET /api/v1/operations/models/{model_id}/monitor-results`
|
||||
|
||||
查询参数:
|
||||
|
||||
- `workspace_id`:必填。
|
||||
- `month`:必填,格式 `YYYY-MM`。
|
||||
|
||||
权限:`operations:monitoring-detail:view`。
|
||||
|
||||
返回字段:模型实例 ID、监控月份、排序性、KS、PSI、KS 环比降幅和近 6 个月二级异常命中次数。
|
||||
|
||||
错误码:
|
||||
|
||||
- `INVALID_MONITOR_MONTH`:月份格式不正确。
|
||||
- `MODEL_NOT_FOUND`:模型不存在。
|
||||
- `MONITOR_RESULT_NOT_FOUND`:该月份没有已发布监控结果。
|
||||
- `OPERATIONS_SCHEMA_NOT_READY`:关键数据表未完成初始化。
|
||||
|
||||
### 2.5 运维工作台
|
||||
|
||||
`GET /api/v1/operations/workbench`
|
||||
|
||||
查询参数:
|
||||
|
||||
- `workspace_id`:必填。
|
||||
|
||||
权限:`operations:workbench:view`。
|
||||
|
||||
返回工作台的提醒、KPI、我的待办、我的关注和最近动态。空数据时各数组为空,KPI 数值为 0。
|
||||
|
||||
## 三、权限与页面映射
|
||||
|
||||
- `operations:workbench:view`:运维工作台。
|
||||
- `operations:usage:view`:平台使用统计。
|
||||
- `operations:model-overview:view`:模型大类概览。
|
||||
- `operations:bank-overview:view`:细分银行概览。
|
||||
- `operations:deployed-models:view`:已上线模型详情。
|
||||
- `operations:monitoring-overview:view`:模型监控概览/监控明细。
|
||||
- `operations:monitoring-detail:view`:模型监控详情。
|
||||
- `operations:report:view`、`operations:report:edit`、`operations:report:export`、`operations:report:send`:监控诊断报告。
|
||||
- `operations:report-summary:view`:历史报告汇总。
|
||||
- `operations:workflow:view`:全流程进度。
|
||||
- `operations:knowledge:view`:文档知识库。
|
||||
- `operations:rules:view`、`operations:rules:publish`、`operations:rules:rollback`、`operations:rules:simulate`:监控等级规则。
|
||||
- `operations:prompt:view`、`operations:prompt:edit`、`operations:prompt:regression`:报告 Prompt 管理。
|
||||
- `operations:settings:view`:运维系统配置。
|
||||
|
||||
## 四、规划接口
|
||||
|
||||
后续按页面逐步实现:
|
||||
|
||||
1. 模型大类和银行概览查询接口。
|
||||
2. 监控明细多条件筛选、特征指标和评分分布接口。
|
||||
3. 模型团队初审、业务团队终审和默认不处理接口。
|
||||
4. 报告生成、编辑、发送、历史汇总和文件导出接口。
|
||||
5. 流程、阶段材料、知识库、规则、Prompt 和系统配置接口。
|
||||
|
||||
规划接口必须沿用本文件的鉴权、Workspace、错误码、空数据和百分比单位约定。
|
||||
@@ -0,0 +1,105 @@
|
||||
# A 卡模型运维模块首条纵向链路联调手册 V0.1
|
||||
|
||||
> 状态:接口和前端调用已完成;真实非空数据到位后即可执行
|
||||
> 日期:2026-09-02
|
||||
|
||||
## 一、联调目标
|
||||
|
||||
验证以下链路使用同一套模型和监控结果口径:
|
||||
|
||||
```text
|
||||
model_deploy / model_operations
|
||||
→ GET 模型列表
|
||||
→ GET 模型详情
|
||||
→ GET 指定月份监控结果
|
||||
→ React 页面展示
|
||||
```
|
||||
|
||||
## 二、前置条件
|
||||
|
||||
1. 后端已配置 `model_platform`、`model_deploy` 和 `model_operations` 三个数据库连接。
|
||||
2. 前端 `VITE_OPERATIONS_API_MODE=api`。
|
||||
3. 已执行数据库初始化和角色权限 SQL。
|
||||
4. 已有一个可访问目标 Workspace 的登录账号。
|
||||
5. 模型方按《数据库外部写入协议》提供最小非空数据。
|
||||
|
||||
## 三、请求顺序
|
||||
|
||||
以下命令中的 `<workspace_id>`、`<model_id>` 和 `<cookie>` 替换为实际值。
|
||||
|
||||
### 3.1 检查服务
|
||||
|
||||
```bash
|
||||
curl -i http://127.0.0.1:8010/api/v1/health
|
||||
curl -i http://127.0.0.1:8010/api/v1/operations/health
|
||||
```
|
||||
|
||||
### 3.2 获取当前会话和权限
|
||||
|
||||
```bash
|
||||
curl -sS \
|
||||
-H 'Cookie: access_token=<cookie>' \
|
||||
http://127.0.0.1:8010/api/v1/auth/me
|
||||
```
|
||||
|
||||
确认返回 `role_code`、`permissions` 和目标 Workspace。
|
||||
|
||||
### 3.3 查询模型列表
|
||||
|
||||
```bash
|
||||
curl -sS \
|
||||
-H 'Cookie: access_token=<cookie>' \
|
||||
'http://127.0.0.1:8010/api/v1/operations/models?workspace_id=<workspace_id>'
|
||||
```
|
||||
|
||||
记录返回的 `model_id`、模型名称、版本和银行。
|
||||
|
||||
### 3.4 查询模型详情
|
||||
|
||||
```bash
|
||||
curl -sS \
|
||||
-H 'Cookie: access_token=<cookie>' \
|
||||
'http://127.0.0.1:8010/api/v1/operations/models/<model_id>?workspace_id=<workspace_id>'
|
||||
```
|
||||
|
||||
核对列表与详情的银行、模型名称、模型 ID、版本、KS、PSI 和排序性。
|
||||
|
||||
### 3.5 查询单月监控结果
|
||||
|
||||
```bash
|
||||
curl -sS \
|
||||
-H 'Cookie: access_token=<cookie>' \
|
||||
'http://127.0.0.1:8010/api/v1/operations/models/<model_id>/monitor-results?workspace_id=<workspace_id>&month=2026-07'
|
||||
```
|
||||
|
||||
核对详情页和单月接口的监控月份、KS、PSI、排序性、环比降幅和异常命中次数。
|
||||
|
||||
## 四、前端验收路径
|
||||
|
||||
1. 打开 `/operations/models`。
|
||||
2. 从模型列表点击目标模型。
|
||||
3. 进入模型监控详情。
|
||||
4. 选择目标监控月份。
|
||||
5. 检查页面顶部模型信息和单月监控结果。
|
||||
6. 打开浏览器 Network,确认三次请求均为 `/api/v1/operations/*`,没有本地 Mock 请求。
|
||||
|
||||
## 五、空数据验收
|
||||
|
||||
在模型方数据未到位前,也应确认:
|
||||
|
||||
- 模型列表页面正常展示空列表,不跳转说明页。
|
||||
- 工作台 KPI 卡片保留且显示 0。
|
||||
- 缺表时返回明确的 `OPERATIONS_SCHEMA_NOT_READY`。
|
||||
- 不存在月份返回 `MONITOR_RESULT_NOT_FOUND`,详情页面保持结构。
|
||||
- 前端没有硬编码模型、银行、报告和流程示例数据。
|
||||
|
||||
## 六、最终验收标准
|
||||
|
||||
真实非空数据到位后,以下内容必须全部满足:
|
||||
|
||||
1. 列表返回至少 1 个模型。
|
||||
2. 列表点击可以进入详情。
|
||||
3. 详情可以获取指定月份结果。
|
||||
4. 三个接口中的模型 ID、版本、月份、KS、PSI、排序性一致。
|
||||
5. `published` 批次可见,`writing`、`failed` 和 `superseded` 批次不可作为当前结果展示。
|
||||
6. 业务团队、模型团队和管理员分别通过权限验收。
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useMemo, useRef, useState } from "react";
|
||||
import { ArrowRight, Download, TrendingDown, TrendingUp } from "lucide-react";
|
||||
import { Download, TrendingDown, TrendingUp } from "lucide-react";
|
||||
import { useNavigate, useSearchParams } from "react-router";
|
||||
|
||||
import { Button } from "~/components/ui/button";
|
||||
@@ -127,7 +127,7 @@ export default function BankOverviewPage() {
|
||||
return (
|
||||
<section className="h-full overflow-auto bg-bg p-6">
|
||||
<div className="flex w-full flex-col gap-6 pb-8">
|
||||
<OperationsPageHeader title="细分银行概览" description="按银行和模型大类查看本行表现,并与同业均值对照。" actions={<Button variant="outline" onClick={() => navigate("/operations/deployed-models")}>查看已上线模型 <ArrowRight /></Button>} />
|
||||
<OperationsPageHeader title="细分银行概览" description="按银行和模型大类查看本行表现,并与同业均值对照。" />
|
||||
|
||||
<Card size="sm"><CardContent className="flex items-end gap-4"><FilterSelect className="w-56" label="筛选银行" value={bank} allLabel="请选择银行" options={banks} onChange={selectBank} /><p className="pb-2 text-sm text-muted-foreground">选择银行后,卡片展示本行指标及同业对比</p></CardContent></Card>
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useMemo, useRef, useState } from "react";
|
||||
import { ArrowRight, Download, TrendingDown, TrendingUp } from "lucide-react";
|
||||
import { Download, TrendingDown, TrendingUp } from "lucide-react";
|
||||
import { useNavigate, useSearchParams } from "react-router";
|
||||
|
||||
import { Button } from "~/components/ui/button";
|
||||
@@ -120,7 +120,7 @@ export default function ModelOverviewPage() {
|
||||
return (
|
||||
<section className="h-full overflow-auto bg-bg p-6">
|
||||
<div className="flex w-full flex-col gap-6 pb-8">
|
||||
<OperationsPageHeader title="模型大类概览" description="按模型大类汇总全部银行;点击大类卡片可定位到对应指标趋势。" actions={<Button variant="outline" onClick={() => navigate("/operations/monitoring")}>查看监控明细 <ArrowRight /></Button>} />
|
||||
<OperationsPageHeader title="模型大类概览" description="按模型大类汇总全部银行;点击大类卡片可定位到对应指标趋势。" />
|
||||
|
||||
<CategoryCardRail>
|
||||
{categoryCards.map((item) => {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useState } from "react";
|
||||
import { Database, Download, History, RefreshCw, Save, Settings2, Users } from "lucide-react";
|
||||
import { Database, Download, History, RefreshCw, Save } from "lucide-react";
|
||||
import { toast } from "sonner";
|
||||
|
||||
import { Button } from "~/components/ui/button";
|
||||
@@ -56,17 +56,10 @@ export default function SystemConfigPage() {
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-2 gap-6">
|
||||
<Card>
|
||||
<CardHeader className="border-b border-border"><CardTitle>通知与催办</CardTitle><CardDescription>邮件通道已取消</CardDescription><CardAction><Button variant="outline" size="xs" onClick={() => void exportRowsToExcel({ fileName: "通知与催办配置", sheetName: "通知配置", headers: ["配置项", "配置值"], rows: notificationRows })}><Download />导出 Excel</Button></CardAction></CardHeader>
|
||||
<CardContent className="px-0"><Table><TableBody>{notificationRows.map(([item, value]) => <TableRow key={item}><TableCell className="w-52 font-medium text-foreground">{item}</TableCell><TableCell>{value}</TableCell></TableRow>)}</TableBody></Table></CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader><CardTitle className="flex items-center gap-2"><Users className="size-5 text-primary" />登录角色来源</CardTitle><CardDescription>角色及权限由统一权限模块维护</CardDescription></CardHeader>
|
||||
<CardContent className="space-y-4"><div className="rounded-xl bg-brand-soft p-4 text-sm leading-6 text-primary">运维前端不单独维护角色或权限数据。登录成功后读取统一认证返回的 <code className="rounded bg-white/70 px-1.5 py-0.5 font-mono text-xs">role_code</code> 和 <code className="rounded bg-white/70 px-1.5 py-0.5 font-mono text-xs">permissions</code>,用于适配业务团队、模型团队和管理员三种界面及操作。</div><div className="grid grid-cols-3 gap-3">{[["业务团队", "business / business_team"], ["模型团队", "developer / model_team"], ["管理员", "admin"]].map(([label, code]) => <div className="rounded-xl border border-border p-4" key={label}><b className="block text-sm text-foreground">{label}</b><small className="mt-1 block font-mono text-xs text-muted-foreground">{code}</small></div>)}</div><p className="text-xs leading-5 text-muted-foreground">角色和权限由统一权限模块维护;本页仅用于运维配置,不保存、不修改角色权限数据。</p></CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
<Card>
|
||||
<CardHeader className="border-b border-border"><CardTitle>通知与催办</CardTitle><CardDescription>邮件通道已取消</CardDescription><CardAction><Button variant="outline" size="xs" onClick={() => void exportRowsToExcel({ fileName: "通知与催办配置", sheetName: "通知配置", headers: ["配置项", "配置值"], rows: notificationRows })}><Download />导出 Excel</Button></CardAction></CardHeader>
|
||||
<CardContent className="px-0"><Table><TableBody>{notificationRows.map(([item, value]) => <TableRow key={item}><TableCell className="w-52 font-medium text-foreground">{item}</TableCell><TableCell>{value}</TableCell></TableRow>)}</TableBody></Table></CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader className="border-b border-border"><CardTitle>报告时间维度与输出日期</CardTitle><CardDescription>按银行单独配置,不强制统一为每月 15 日</CardDescription><CardAction className="flex items-end gap-2"><FilterSelect className="w-44" label="选择银行" value={selectedBank} allLabel="暂无银行数据" options={Object.keys(bankConfigs)} onChange={setSelectedBank} /><Button variant="outline" size="xs" onClick={() => void exportRowsToExcel({ fileName: "报告周期配置", sheetName: "报告周期", headers: ["银行", "报告时间维度", "输出日期", "下次生成"], rows: Object.entries(bankConfigs).map(([bank, config]) => [bank, config.frequency, `每月 ${config.day} 日`, nextGeneration(config.frequency, config.day)]) })}><Download />导出 Excel</Button></CardAction></CardHeader>
|
||||
@@ -74,10 +67,6 @@ export default function SystemConfigPage() {
|
||||
<CardContent className="px-0 pt-0"><Table><TableHeader><TableRow><TableHead>银行</TableHead><TableHead>报告时间维度</TableHead><TableHead>输出日期</TableHead><TableHead>下次生成</TableHead></TableRow></TableHeader><TableBody>{Object.entries(bankConfigs).length ? Object.entries(bankConfigs).map(([bank, config]) => <TableRow data-state={bank === selectedBank ? "selected" : undefined} key={bank}><TableCell className="font-medium text-foreground">{bank}</TableCell><TableCell>{config.frequency}</TableCell><TableCell>每月 {config.day} 日</TableCell><TableCell>{nextGeneration(config.frequency, config.day)}</TableCell></TableRow>) : <TableRow><TableCell colSpan={4} className="h-28 text-center text-muted-foreground">暂无银行报告周期数据</TableCell></TableRow>}</TableBody></Table></CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader><CardTitle className="flex items-center gap-2"><Settings2 className="size-5 text-primary" />模型平台新增页面依赖</CardTitle><CardDescription>非本平台交付范围</CardDescription><CardAction><span className="rounded-full bg-muted px-2.5 py-1 text-xs text-muted-foreground">待模型平台提供</span></CardAction></CardHeader>
|
||||
<CardContent className="space-y-4"><div className="rounded-xl bg-warning-soft p-4 text-sm leading-6 text-foreground">需求明确由模型平台侧新增模型信息页面,本平台只读消费。该页面是模型大类概览、已上线模型详情和监控明细的数据底座。</div><div className="rounded-xl bg-bg-log p-5 font-mono text-xs leading-6 text-white/80">主键:银行 × 模型ID<br />字段:模型名称 / 模型版本 / 开发日期 / 开发人员 / 上线日期 / 陪跑开始日期 / 陪跑结束日期 / 最近迭代日期 / 迭代原因 / 迭代人员 / 下线日期</div></CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
|
||||
@@ -1,18 +1,24 @@
|
||||
import { useEffect } from "react";
|
||||
import { useNavigate } from "react-router";
|
||||
import { Navigate, useNavigate } from "react-router";
|
||||
|
||||
import { useAuth } from "~/context/AuthContext";
|
||||
import { useAuth, usePermission } from "~/context/AuthContext";
|
||||
import { DashboardPage } from "../admin/DashboardPage";
|
||||
import { useScriptWorkspaceStore } from "./state/scriptWorkspaceStore";
|
||||
|
||||
export default function DashboardRoute() {
|
||||
const canViewDevelopmentWorkbench = usePermission("dashboard:view");
|
||||
const { currentWorkspace } = useAuth();
|
||||
const scripts = useScriptWorkspaceStore((s) => s.scripts);
|
||||
const scriptCount = useScriptWorkspaceStore((s) => s.scriptCount);
|
||||
const loadScriptCount = useScriptWorkspaceStore((s) => s.loadScriptCount);
|
||||
const apiOnline = useScriptWorkspaceStore((s) => s.apiOnline);
|
||||
const workspaceId = useAuth().currentWorkspace?.workspace_id;
|
||||
const workspaceId = currentWorkspace?.workspace_id;
|
||||
const navigate = useNavigate();
|
||||
|
||||
if (!canViewDevelopmentWorkbench) {
|
||||
return <Navigate to="/operations" replace />;
|
||||
}
|
||||
|
||||
// Reload on workspace switch — DashboardRoute is not keyed by
|
||||
// workspace/user (only ScriptsPage is), so without this dep the
|
||||
// previous workspace's count would persist.
|
||||
@@ -31,4 +37,4 @@ export default function DashboardRoute() {
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@ export const navigation: NavigationItem[] = [
|
||||
icon: Home,
|
||||
page: "home",
|
||||
children: [
|
||||
{ label: "开发工作台", icon: Home, page: "home", activePath: "/workbench", targetPath: "/workbench" },
|
||||
{ label: "开发工作台", icon: Home, page: "home", activePath: "/workbench", targetPath: "/workbench", permission: "dashboard:view" },
|
||||
{ label: "运维工作台", icon: Gauge, page: "operations", activePath: "/operations", targetPath: "/operations", permission: "operations:workbench:view", visibleToOperationsRoles: ["business", "model", "admin"] },
|
||||
{ label: "平台使用统计", icon: ChartNoAxesColumn, page: "operations", activePath: "/operations/usage", targetPath: "/operations/usage", permission: "operations:usage:view", visibleToOperationsRoles: ["admin"] },
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user