feat: 审计日志界面 + DataGrid 分页查询
- index.ui: DataGrid 审计日志列表界面
- audit_service: list_audit_logs 改分页返回 {rows,total}
- audit.dspy: list 返回 DataGrid 格式
- load_path: 注册 /app_audit 界面权限
This commit is contained in:
parent
7e40c80410
commit
55e4ce30b8
@ -87,8 +87,8 @@ def _row_to_dict(row) -> dict:
|
||||
return d
|
||||
|
||||
|
||||
async def list_audit_logs(sor, filters: dict = None, limit: int = 100, offset: int = 0):
|
||||
"""查询审计日志(仅 owner.audit)。"""
|
||||
async def list_audit_logs(sor, filters: dict = None, page: int = 1, rows: int = 60):
|
||||
"""查询审计日志(分页,DataGrid 兼容),返回 {rows, total}。"""
|
||||
filters = filters or {}
|
||||
where = []
|
||||
ns = {}
|
||||
@ -109,17 +109,21 @@ async def list_audit_logs(sor, filters: dict = None, limit: int = 100, offset: i
|
||||
ns["t"] = filters["to"]
|
||||
wsql = (" WHERE " + " AND ".join(where)) if where else ""
|
||||
try:
|
||||
limit = max(1, min(int(limit or 100), 1000))
|
||||
page = max(1, int(page or 1))
|
||||
except (ValueError, TypeError):
|
||||
limit = 100
|
||||
page = 1
|
||||
try:
|
||||
offset = max(0, int(offset or 0))
|
||||
rows = max(1, min(int(rows or 60), 500))
|
||||
except (ValueError, TypeError):
|
||||
offset = 0
|
||||
rows = 60
|
||||
total_recs = await sor.sqlExe(
|
||||
"SELECT COUNT(*) AS c FROM sd_audit_logs" + wsql, ns)
|
||||
total = getattr(total_recs[0], "c", 0) if total_recs else 0
|
||||
offset = (page - 1) * rows
|
||||
recs = await sor.sqlExe(
|
||||
"SELECT * FROM sd_audit_logs" + wsql + " ORDER BY created_at DESC LIMIT "
|
||||
+ str(limit) + " OFFSET " + str(offset), ns)
|
||||
return [_row_to_dict(r) for r in recs]
|
||||
+ str(rows) + " OFFSET " + str(offset), ns)
|
||||
return {"rows": [_row_to_dict(r) for r in recs], "total": total}
|
||||
|
||||
|
||||
async def backup_audit_logs(sor, user_id: str, username: str, filters: dict = None,
|
||||
|
||||
@ -7,8 +7,10 @@ import os, sys, subprocess
|
||||
|
||||
MOD = "app_audit"
|
||||
|
||||
# 审计日志 API:仅 owner.audit 角色
|
||||
# 审计日志界面 + API:仅 owner.audit 角色
|
||||
PATHS_AUDIT = [
|
||||
f"/{MOD}",
|
||||
f"/{MOD}/index.ui",
|
||||
f"/{MOD}/api/audit.dspy",
|
||||
]
|
||||
|
||||
|
||||
@ -41,12 +41,12 @@ if action == 'list':
|
||||
'from': (params_kw or {}).get('from', ''),
|
||||
'to': (params_kw or {}).get('to', ''),
|
||||
}
|
||||
limit = (params_kw or {}).get('limit', 100)
|
||||
offset = (params_kw or {}).get('offset', 0)
|
||||
page = (params_kw or {}).get('page', 1)
|
||||
rows = (params_kw or {}).get('rows', 60)
|
||||
try:
|
||||
async with get_sor_context(request._run_ns, 'pipeline') as sor:
|
||||
rows = await list_audit_logs(sor, filters, limit, offset)
|
||||
return json.dumps({'ok': True, 'logs': rows}, ensure_ascii=False)
|
||||
r = await list_audit_logs(sor, filters, page, rows)
|
||||
return json.dumps(r, ensure_ascii=False)
|
||||
except Exception as e:
|
||||
return json.dumps({'ok': False, 'error': str(e)}, ensure_ascii=False)
|
||||
|
||||
|
||||
34
wwwroot/index.ui
Normal file
34
wwwroot/index.ui
Normal file
@ -0,0 +1,34 @@
|
||||
{
|
||||
"widgettype": "VBox",
|
||||
"options": {"width": "100%", "height": "100%", "padding": "24px", "gap": "16px"},
|
||||
"subwidgets": [
|
||||
{
|
||||
"widgettype": "Title2",
|
||||
"options": {"text": "审计日志"}
|
||||
},
|
||||
{
|
||||
"widgettype": "Text",
|
||||
"options": {"text": "记录关键操作,仅 owner.audit 角色可查看", "cfontsize": 1.1, "color": "#888"}
|
||||
},
|
||||
{
|
||||
"widgettype": "DataGrid",
|
||||
"options": {
|
||||
"width": "100%",
|
||||
"height": "100%",
|
||||
"dataurl": "{{entire_url('/app_audit/api/audit.dspy')}}",
|
||||
"method": "POST",
|
||||
"params": {"action": "list"},
|
||||
"row_height": 40,
|
||||
"fields": [
|
||||
{"name": "created_at", "label": "时间", "datatype": "str", "width": 180},
|
||||
{"name": "username", "label": "用户", "datatype": "str", "width": 120},
|
||||
{"name": "action", "label": "动作", "datatype": "str", "width": 140},
|
||||
{"name": "target", "label": "对象", "datatype": "str", "width": 180},
|
||||
{"name": "result", "label": "结果", "datatype": "str", "width": 80},
|
||||
{"name": "client_ip", "label": "IP", "datatype": "str", "width": 130},
|
||||
{"name": "detail", "label": "详情", "datatype": "str", "width": 320}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user