- 复制来源: /home/yueli/track @ 192c8ee (feature/ai-audit-update) - 组织隔离目标: LICA - 端口规划: 前端 8030 / 后端 8031 / 数据库 8032 - 已排除 deploy.sh、deploy_full.sh、docker-compose.prod.yml(IRIS 生产发布脚本) - 已排除工作区未提交改动,取干净的 192c8ee 状态
89 lines
2.9 KiB
Python
89 lines
2.9 KiB
Python
"""审计日志 Pydantic Schema"""
|
||
from __future__ import annotations
|
||
|
||
import uuid
|
||
from datetime import datetime
|
||
|
||
from pydantic import BaseModel
|
||
|
||
|
||
class AuditLogResponse(BaseModel):
|
||
"""单条审计记录"""
|
||
id: uuid.UUID
|
||
user_id: str | None = None
|
||
display_name: str | None = None
|
||
role: str | None = None
|
||
|
||
action: str
|
||
action_label: str | None = None # 服务端补的中文标签,避免前端各处硬编码
|
||
module: str
|
||
module_label: str | None = None
|
||
|
||
target_type: str | None = None
|
||
target_id: str | None = None
|
||
target_name: str | None = None
|
||
details: dict | None = None
|
||
|
||
ip_address: str | None = None
|
||
user_agent: str | None = None
|
||
method: str | None = None
|
||
url: str | None = None
|
||
status_code: int | None = None
|
||
error_message: str | None = None
|
||
|
||
# 与结构化日志对账用:拿着它就能捞到对应的接口日志
|
||
request_id: str | None = None
|
||
|
||
created_at: datetime
|
||
|
||
model_config = {"from_attributes": True}
|
||
|
||
|
||
class AuditLogListResponse(BaseModel):
|
||
"""审计日志分页列表"""
|
||
items: list[AuditLogResponse]
|
||
total: int
|
||
|
||
|
||
class DailyUsageRow(BaseModel):
|
||
"""某个操作人在某一天的用量汇总(北京时间自然日)"""
|
||
day: str # YYYY-MM-DD(北京时间)
|
||
user_id: str | None = None
|
||
display_name: str | None = None
|
||
role: str | None = None
|
||
|
||
login_count: int = 0 # 登录次数(当天成功登录)
|
||
logout_count: int = 0 # 登出次数(当天成功登出)
|
||
op_count: int = 0 # 操作次数(当天全部审计记录数)
|
||
|
||
# ⚠️ 上线/下线时间取【当天首次/末次活动】,不是登录/登出时间:
|
||
# token 有效期内(refresh 7 天)用户不会重新登录,按登录算会导致
|
||
# 「登录次数 0 但操作 35 次」这种自相矛盾。
|
||
first_active_at: datetime | None = None # 上线时间(当天首次活动)
|
||
last_active_at: datetime | None = None # 下线时间(当天末次活动)
|
||
|
||
|
||
class DailyUsageResponse(BaseModel):
|
||
"""日活 / 使用统计"""
|
||
start_date: str
|
||
end_date: str
|
||
items: list[DailyUsageRow]
|
||
total: int # 行数(= 天数 × 人数),不是审计记录数
|
||
|
||
|
||
class AuditOption(BaseModel):
|
||
"""筛选项(value/label 结构,直接喂给前端下拉)"""
|
||
value: str
|
||
label: str
|
||
|
||
|
||
class AuditOptionsResponse(BaseModel):
|
||
"""筛选项集合"""
|
||
modules: list[AuditOption]
|
||
actions: list[AuditOption]
|
||
# 导出可选的列(value=后端列 key,label=中文表头)。
|
||
# 由后端下发而非前端硬编码:列的中文名与取值口径都在后端,
|
||
# 两端各写一份迟早会出现"导出的列和页面上的对不上"。
|
||
log_export_columns: list[AuditOption] = []
|
||
usage_export_columns: list[AuditOption] = []
|