diff --git a/.workbuddy/memory/CHANGELOG.md b/.workbuddy/memory/CHANGELOG.md index 542bd13..74db646 100644 --- a/.workbuddy/memory/CHANGELOG.md +++ b/.workbuddy/memory/CHANGELOG.md @@ -1,6 +1,7 @@ # admin.xpcool.com 变更记录 > 倒序:最新在上。格式:YYYY-MM-DD | 类型 | 摘要 +2026-08-27 | CHG | 服务器安全日志页(挂在系统监控菜单下,id=96):views/monitor/security/index.vue——顶部 4 统计卡片(SSH爆破/fail2ban封禁/成功登录/总数)+ TOP 攻击源标签区 + 筛选(来源IP/事件类型/时间范围 t-date-range-picker)+ Vben VxeTable 列表(时间/来源IP/来源端口/目标端口/事件类型标签/详情 tooltip,事件标签按类型配色);api/serverSecurity.ts(list/stats 全 POST,无 URL 参数);typecheck 通过 2026-08-27 | CHG | 全量表格重构:views 下全部 11 个 t-table 页面统一改为 Vben Vxe Table(useVbenVxeGrid,#/adapter/vxe-table)+ Vben TableAction 行操作——system/{log(范式),login-log,admin,role}、recruitment/{info,crawler,push}、house/{data,listing,community,presale}、dashboard/workbench(两处本地小表 proxyConfig.enabled=false + gridApi.setGridOptions 写数据)。要点:gridOptions 需注解 VxeTableGridOptions(否则 type:'seq' 推断 string 报错);单元格自定义用 columns[].slots.default + h(TDesign组件);远程分页走 proxyConfig.ajax.query 返回 {items,total};筛选区保留手写 TDesign 组件不动;admin/role/listing/community 行操作 ActionItem 带 auth 权限码、删除 danger 标红;listing 多选批量标记改 vxe checkboxConfig + gridApi.grid.getCheckboxRecords();confirm 弹窗交互(删除/重置密码)保留 DialogPlugin 不变;typecheck 通过 2026-08-27 | FIX | 恢复丢失的前端代码:recovery 分支经 rebase/改名(dev↔main)折腾后工作树回退,未提交改动全丢;从悬空提交 f02a514(recovery 工作树快照,含 HEAD 缺失的全部文件)整体恢复 apps/web-tdesign/src——含 styles/theme.css 全局主题、dashboard/workbench 工作台页、system 五页卡片化美化、操作日志增强版(VxeTable)、house 预售/楼盘地图、recruitment 页面;另补 log 页卡片美化(wb-page-head+t-card)。已提交保护 diff --git a/apps/web-tdesign/src/api/serverSecurity.ts b/apps/web-tdesign/src/api/serverSecurity.ts new file mode 100644 index 0000000..a7b98dc --- /dev/null +++ b/apps/web-tdesign/src/api/serverSecurity.ts @@ -0,0 +1,78 @@ +// 服务器安全日志模块 API 客户端。 +// 接口规范:全部 POST;URL 不含参数(查询/路径参数均禁止);入参一律走 body。 +import { requestClient } from '#/api/request'; + +// ---------- 数据类型 ---------- +export interface SecurityLogItem { + id: number; + logTime: string; + srcIp: string; + srcPort: number; + destPort: number; + eventType: string; + eventName: string; + detail: string; + createdAt: string; +} + +export interface SecurityLogListResp { + list: SecurityLogItem[]; + total: number; +} + +export interface SecurityTopIp { + srcIp: string; + count: number; +} + +export interface SecurityByType { + eventType: string; + eventName: string; + count: number; +} + +export interface SecurityLogStatsResp { + total: number; + failed: number; + banned: number; + accepted: number; + topIps: SecurityTopIp[]; + byType: SecurityByType[]; +} + +// ---------- 列表 ---------- +export interface SecurityLogQuery { + page: number; + size: number; + srcIp?: string; + eventType?: string; + destPort?: number; + dateFrom?: string; + dateTo?: string; +} + +export function getSecurityLogList(data: SecurityLogQuery) { + return requestClient.post( + '/api/service/admin/server-security/log/list', + data, + ); +} + +// ---------- 统计 ---------- +export function getSecurityLogStats(data: { + dateFrom?: string; + dateTo?: string; +}) { + return requestClient.post( + '/api/service/admin/server-security/log/stats', + data, + ); +} + +// ---------- 事件类型选项(与后端 SecurityEventName 对应) ---------- +export const SECURITY_EVENT_OPTIONS = [ + { label: 'SSH爆破尝试', value: 'failed_ssh' }, + { label: 'SSH成功登录', value: 'accepted_ssh' }, + { label: 'fail2ban封禁', value: 'banned' }, + { label: 'fail2ban解封', value: 'unbanned' }, +]; diff --git a/apps/web-tdesign/src/views/monitor/security/index.vue b/apps/web-tdesign/src/views/monitor/security/index.vue new file mode 100644 index 0000000..4219936 --- /dev/null +++ b/apps/web-tdesign/src/views/monitor/security/index.vue @@ -0,0 +1,200 @@ + + +