2026-09-12 20:42:33 +08:00
|
|
|
"""审计台账(PRD §4.6):本人操作记录筛选 + CSV 导出。"""
|
|
|
|
|
from __future__ import annotations
|
|
|
|
|
|
|
|
|
|
import csv
|
|
|
|
|
import io
|
|
|
|
|
from datetime import datetime
|
|
|
|
|
|
|
|
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
|
|
|
|
|
|
from model.sys_user import SysUser
|
|
|
|
|
from repositories.audit_log import AuditLogRepo
|
2026-09-13 22:21:49 +08:00
|
|
|
from utils.pagination import normalize_pagination, pagination_result
|
2026-09-12 20:42:33 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def _audit_item(a) -> dict:
|
|
|
|
|
return {
|
|
|
|
|
"id": a.id,
|
|
|
|
|
"module": a.module,
|
|
|
|
|
"action": a.action,
|
|
|
|
|
"target": a.target,
|
|
|
|
|
"detail": a.detail,
|
|
|
|
|
"trace_id": a.trace_id,
|
|
|
|
|
"status": a.status,
|
|
|
|
|
"create_time": a.create_time.isoformat() if a.create_time else None,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async def list_ledger(
|
|
|
|
|
db: AsyncSession,
|
|
|
|
|
user: SysUser,
|
|
|
|
|
*,
|
|
|
|
|
action: str | None = None,
|
2026-09-13 16:19:24 +08:00
|
|
|
customer_id: int | None = None,
|
2026-09-12 20:42:33 +08:00
|
|
|
keyword: str | None = None,
|
|
|
|
|
start: datetime | None = None,
|
|
|
|
|
end: datetime | None = None,
|
|
|
|
|
page: int = 1,
|
2026-09-13 22:21:49 +08:00
|
|
|
page_size: int = 10,
|
2026-09-12 20:42:33 +08:00
|
|
|
) -> dict:
|
2026-09-13 22:21:49 +08:00
|
|
|
page, page_size, offset = normalize_pagination(page, page_size)
|
2026-09-12 20:42:33 +08:00
|
|
|
repo = AuditLogRepo(db)
|
|
|
|
|
items = await repo.list_by_advisor(
|
2026-09-13 16:19:24 +08:00
|
|
|
user_id=user.id, action=action, customer_id=customer_id, keyword=keyword, start=start, end=end,
|
2026-09-13 22:21:49 +08:00
|
|
|
limit=page_size, offset=offset,
|
2026-09-12 20:42:33 +08:00
|
|
|
)
|
|
|
|
|
total = await repo.count_by_advisor(
|
|
|
|
|
user_id=user.id, action=action, keyword=keyword, start=start, end=end
|
|
|
|
|
)
|
2026-09-13 22:21:49 +08:00
|
|
|
return pagination_result(
|
|
|
|
|
[_audit_item(a) for a in items], total, page=page, page_size=page_size
|
|
|
|
|
)
|
2026-09-12 20:42:33 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def _to_csv(rows: list[dict]) -> str:
|
|
|
|
|
"""行列表 → CSV 文本(空列表返回空串)。"""
|
|
|
|
|
if not rows:
|
|
|
|
|
return ""
|
|
|
|
|
buf = io.StringIO()
|
|
|
|
|
writer = csv.DictWriter(buf, fieldnames=list(rows[0].keys()))
|
|
|
|
|
writer.writeheader()
|
|
|
|
|
writer.writerows(rows)
|
|
|
|
|
return buf.getvalue()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async def export_ledger(
|
|
|
|
|
db: AsyncSession,
|
|
|
|
|
user: SysUser,
|
|
|
|
|
*,
|
|
|
|
|
action: str | None = None,
|
2026-09-13 16:19:24 +08:00
|
|
|
customer_id: int | None = None,
|
2026-09-12 20:42:33 +08:00
|
|
|
keyword: str | None = None,
|
|
|
|
|
start: datetime | None = None,
|
|
|
|
|
end: datetime | None = None,
|
|
|
|
|
) -> str:
|
|
|
|
|
"""导出本人审计台账为 CSV 文本(全量,不限分页大小,上限 10000 条)。"""
|
|
|
|
|
repo = AuditLogRepo(db)
|
|
|
|
|
items = await repo.list_by_advisor(
|
2026-09-13 16:19:24 +08:00
|
|
|
user_id=user.id, action=action, customer_id=customer_id, keyword=keyword, start=start, end=end,
|
2026-09-12 20:42:33 +08:00
|
|
|
limit=10000, offset=0,
|
|
|
|
|
)
|
|
|
|
|
return _to_csv([_audit_item(a) for a in items])
|