feat: 新增系统日志记录、查看与自动清理,VO 转换改用 MapStruct

- 新增访问/登录日志表与拦截器,登录成功/失败均记录,接口访问同时输出到应用日志
- 新增 /api/log/* 查询与 SSE 实时推送,运行日志默认最近 1 小时并支持日期/级别/关键字筛选
- 新增日志定时清理,保留天数可配置(默认 30 天,0 为永久保留)
- 前端新增系统日志页(独立 URL 子路径、标签偏好记忆),入口位于顶部用户下拉菜单
- 实体到视图对象的属性拷贝改用 MapStruct 编译期生成
This commit is contained in:
2026-09-18 17:18:03 +08:00
parent e49b6b7b81
commit e82e0a4ef9
38 changed files with 2464 additions and 153 deletions
+49
View File
@@ -82,6 +82,7 @@ export default {
transactions: { zh: '收支记录', en: 'Transactions', ja: '収支記録' },
categories: { zh: '分类管理', en: 'Categories', ja: 'カテゴリ管理' },
tags: { zh: '标签管理', en: 'Tags', ja: 'タグ管理' },
logs: { zh: '系统日志', en: 'Logs', ja: 'システムログ' },
settings: { zh: '系统设置', en: 'Settings', ja: 'システム設定' },
user: { zh: '用户', en: 'User', ja: 'ユーザー' },
logout: { zh: '退出', en: 'Sign Out', ja: 'ログアウト' },
@@ -216,6 +217,54 @@ export default {
back: { zh: '返回设置', en: 'Back to Settings', ja: '設定に戻る' },
},
// 系统日志
log: {
title: { zh: '系统日志', en: 'System Logs', ja: 'システムログ' },
httpTab: { zh: '访问日志', en: 'Access Logs', ja: 'アクセスログ' },
loginTab: { zh: '登录日志', en: 'Login Logs', ja: 'ログインログ' },
appTab: { zh: '运行日志', en: 'Application Logs', ja: 'アプリログ' },
keyword: { zh: '关键字', en: 'Keyword', ja: 'キーワード' },
keywordPlaceholder: { zh: '路径 / 参数 / IP', en: 'Path / Query / IP', ja: 'パス / クエリ / IP' },
method: { zh: '请求方法', en: 'Method', ja: 'メソッド' },
status: { zh: '状态码', en: 'Status', ja: 'ステータス' },
result: { zh: '结果', en: 'Result', ja: '結果' },
level: { zh: '级别', en: 'Level', ja: 'レベル' },
date: { zh: '日期', en: 'Date', ja: '日付' },
datePlaceholder: { zh: 'yyyy-MM-dd,留空为当前', en: 'yyyy-MM-dd, blank for current', ja: 'yyyy-MM-dd、空欄で現在' },
range1h: { zh: '最近1小时', en: 'Last 1h', ja: '直近1時間' },
range6h: { zh: '最近6小时', en: 'Last 6h', ja: '直近6時間' },
range24h: { zh: '最近24小时', en: 'Last 24h', ja: '直近24時間' },
rangeAll: { zh: '全部', en: 'All', ja: 'すべて' },
lines: { zh: '行数', en: 'Lines', ja: '行数' },
file: { zh: '文件', en: 'File', ja: 'ファイル' },
totalLines: { zh: '命中 {count} 行', en: '{count} line(s) matched', ja: '{count} 行が一致' },
search: { zh: '查询', en: 'Search', ja: '検索' },
refresh: { zh: '刷新', en: 'Refresh', ja: '更新' },
realtime: { zh: '实时', en: 'Live', ja: 'リアルタイム' },
time: { zh: '时间', en: 'Time', ja: '時刻' },
path: { zh: '路径', en: 'Path', ja: 'パス' },
queryString: { zh: '参数', en: 'Query', ja: 'クエリ' },
duration: { zh: '耗时', en: 'Duration', ja: '所要時間' },
ip: { zh: 'IP', en: 'IP', ja: 'IP' },
user: { zh: '用户', en: 'User', ja: 'ユーザー' },
username: { zh: '用户名', en: 'Username', ja: 'ユーザー名' },
userAgent: { zh: 'User-Agent', en: 'User-Agent', ja: 'User-Agent' },
message: { zh: '说明', en: 'Message', ja: '説明' },
success: { zh: '成功', en: 'Success', ja: '成功' },
failed: { zh: '失败', en: 'Failed', ja: '失敗' },
anonymous: { zh: '未登录', en: 'Anonymous', ja: '未ログイン' },
noData: { zh: '暂无日志', en: 'No logs', ja: 'ログがありません' },
appEmpty: { zh: '暂无运行日志', en: 'No application logs', ja: 'アプリログがありません' },
retention: { zh: '日志保留', en: 'Log retention', ja: 'ログ保持' },
retention30: { zh: '30 天', en: '30 days', ja: '30日' },
retention90: { zh: '90 天', en: '90 days', ja: '90日' },
retention180: { zh: '180 天', en: '180 days', ja: '180日' },
retentionForever: { zh: '永久保留', en: 'Forever', ja: '永久保持' },
retentionSaved: { zh: '日志保留策略已保存', en: 'Log retention saved', ja: 'ログ保持を保存しました' },
retentionFailed: { zh: '保存日志保留策略失败', en: 'Failed to save log retention', ja: 'ログ保持の保存に失敗しました' },
loadFailed: { zh: '加载日志失败', en: 'Failed to load logs', ja: 'ログの読み込みに失敗しました' },
},
// 统计面板
dashboard: {
title: { zh: '统计面板', en: 'Dashboard', ja: 'ダッシュボード' },