|
|
7d203b20c1
|
feat(audit): 按条件导出审计日志,并修 module 口径断裂与详情接口权限漏洞
需求是"想看某天或某段时间的入库的修改,支持下载或当场查看"。
核查后:筛选与查看审计页早已具备,缺的是导出 —— 但直接加导出会撞上两个
既有问题,故一并处理。
1. 「入库」的 module 口径在 2026-09-10 断过一次
那天旧的全局监听器 app/utils/audit_events.py 被现行的
app/core/audit_listener.py 取代(旧模块现已无人 import,是死代码),
新监听器把入库三表 stock_buy/stock_semi/stock_product 统一归为
「库存管理」,不再产出「入库管理」:
入库管理 16118 条 2026-04-22 ~ 2026-09-10
采购入库 1196 条 2026-03-18 ~ 2026-04-20
成品入库 8 条 2026-03-23 ~ 2026-04-17
库存管理 1371 条 2026-09-10 ~
后果:按单个 module 值筛「入库」会正好在那天断掉,现象是"入库记录突然
没了"。解法是**查询期别名展开**(audit_labels.MODULE_GROUPS),不迁移
历史数据 —— 改数据不可逆,而聚合查询无损。
2. GET /audit/logs/<id> 缺权限校验,也没有公司隔离
此前只有 @jwt_required(),任何登录用户改一下 URL 里的 id 就能读到全部
审计明细(含 details 里的完整快照)。列表接口有 system_audit 把关,
详情提供的信息是列表的超集,没道理比列表更宽松。
现补权限码 + 与列表同一个公司判据;越权与不存在**统一返回 404**,
区分开来等于告诉探测者"这个 id 存在,只是你没权限"。
3. 筛选逻辑只写一份
抽出 _build_audit_query(),/logs 与 /logs/export 共用。两处各写一份迟早
出现"页面上 300 条、导出来 280 条",而报表对不上比没有报表更糟。
导出实现:
- GET /audit/logs/export,权限码同 /logs;忽略分页参数,导全量。
- 三个工作表:汇总(含本次生效的筛选条件,收件人看不到页面上的筛选框)、
审计日志(一行一条)、变更明细(一行一个变更字段,可对「字段」列筛选)。
- EXPORT_LIMIT=100000 作熔断。实测全库 5.8 万条导出 2.5MB / 约 3 秒,
故走同步返回,不引入 export_service 那套异步框架(它还会落盘且无清理)。
触顶时在文件名与汇总表显式写明,不静默丢弃。
- 顺带补 /audit/modules 的公司隔离(下拉选项此前会跨公司)。
前端(AuditLog.vue / api/audit.ts):
- 模块下拉分「业务聚合 / 具体模块」两组,聚合项由后端下发,前端不硬编成员;
- 操作类型改多选,提交时 join(',')(后端 split(',') 接收);
- 导出按钮沿用仓库既有的 blob 下载写法,文件名前端自定。
验证:后端 21 项断言全过(口径断裂、多选别名归一、日期闭区间、公司隔离、
401/403/200 权限矩阵、导出口径与列表 total 一致、附件为合法 xlsx);
vue-tsc --noEmit 与 vite build 均 exit=0。
|
2026-09-28 09:46:34 +08:00 |
|
|
|
ad2d27cd72
|
refactor(audit): 审计中文映射收敛为后端唯一来源
问题:同一套「字段名 → 中文」映射存了三份手工同步的副本 ——
前端 AuditLog.vue 的 fieldMap(约 95 个字段)、后端 api/v1/audit.py 的
ACTION_ALIASES,另有若干内联的 status 映射散落在 service 层。
改一边漏一边就会漂移,页面上冒出英文列名或对不上的中文。
改动:
· 新增 app/utils/audit_labels.py 作为**唯一来源**,统一提供
操作类型归一化(canon_action)、字段名中文化(field_label)、
码值中文化(enum_label / bool_label / person_name_label)、
ID 指向登记(id_ref_of)。
· api/v1/audit.py 改为从该模块 import,删掉本地副本。
· 新增 GET /audit/labels 下发映射(静态标签,免权限码;审计页本身
已由 system_audit 把关)。
· 前端 AuditLog.vue 删除本地 95 行 fieldMap,改从接口拉取;
拉取失败时未命中项原样显示,是可控降级。
★ 码值必须**按模块**翻译:同名 status 在出库/借还/报废里含义完全不同
(出库的 3 是「已出库」,报废的 3 是「已执行(已报废)」),
不区分模块会把报废单显示成已出库。借还模块下还混着字符串状态
(borrowed/returned),因其两张表共用 status 列名。
故映射按 (模块, 字段) 匹配,未登记再退回字段名。
★ ID 字段同理:parent_id 在「系统管理」里是菜单的上级菜单,在「BOM管理」
里是物料节点 —— 指向完全不同的表。
验证:前端 vue-tsc 改前改后均为 565 个错误、去除行号后**报错集合完全相同**,
未引入新错误;GET /audit/labels 实测返回 200。
|
2026-09-23 17:16:20 +08:00 |
|