From c0ee8e4ddd75f567e025573139d7d99c41a96810 Mon Sep 17 00:00:00 2001 From: attacker Date: Sun, 28 Jun 2026 06:06:48 +0000 Subject: [PATCH] =?UTF-8?q?refactor(frontend):=20api/components/pages=20?= =?UTF-8?q?=E7=9B=AE=E5=BD=95=E6=9E=B6=E6=9E=84=E7=BB=9F=E4=B8=80=E5=AF=B9?= =?UTF-8?q?=E9=BD=90=E8=8F=9C=E5=8D=95=E5=9F=9F=20+=20=E6=97=A5=E5=BF=97?= =?UTF-8?q?=E4=B8=AD=E5=BF=83=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 目录架构统一(API = components = 菜单域,一域一目录 + barrel) - log/ 提为独立顶层域(日志中心在菜单中与监控中心平级,不再塞在 monitor/) - task/ 拆分原 automation.ts → cron-job / script / remote-exec - aiops/ 合并 ai.ts + agentCli.ts → assistant + agent-cli - agent/ approval/ audit/ 提升为域目录 - auth 拆分:authApi(认证自服务) + system/user.ts(userApi+ldapApi 管理端) - components/automation → components/task,菜单"自动化运维"→"作业任务" - pages/ 按域分子目录(approval/audit/monitor),删孤儿 AuditPage.tsx - 所有 API 符号名不变,组件经 @/api 聚合引用,运行时行为零变化 2. Loki 查询无返回修复:aiops 容器 DNS 解析外网域名失败 (宿主机 systemd-resolved 转发链路异常),docker-compose 显式配 dns 上游 3. ES 查询框布局:工具栏单行挤 7 控件(ES 多 150px 索引框),拆两行—— 查询输入独占一行(+查询按钮),次级控件换行 flex-wrap Co-Authored-By: Claude --- docker-compose.yml | 6 ++ frontend/src/App.tsx | 24 +++--- frontend/src/api/{ => agent}/agent.ts | 0 frontend/src/api/agent/index.ts | 3 + .../api/{agentCli.ts => aiops/agent-cli.ts} | 0 .../src/api/{ai.ts => aiops/assistant.ts} | 0 frontend/src/api/aiops/index.ts | 4 + .../src/api/{system => approval}/approval.ts | 0 frontend/src/api/approval/index.ts | 3 + frontend/src/api/{system => audit}/audit.ts | 0 frontend/src/api/audit/index.ts | 4 + .../src/api/{system => audit}/terminal.ts | 0 frontend/src/api/auth.ts | 86 +------------------ frontend/src/api/index.ts | 10 ++- frontend/src/api/log/index.ts | 8 ++ .../src/api/{monitor => log}/log-center.ts | 0 frontend/src/api/monitor/index.ts | 1 - frontend/src/api/system.ts | 9 +- frontend/src/api/system/index.ts | 6 +- frontend/src/api/system/user.ts | 84 ++++++++++++++++++ frontend/src/api/task/cron-job.ts | 30 +++++++ frontend/src/api/task/index.ts | 5 ++ .../{automation.ts => task/remote-exec.ts} | 65 +------------- frontend/src/api/task/script.ts | 27 ++++++ frontend/src/components/auth/Login.tsx | 4 +- .../CICDWebhookContent.tsx | 4 +- frontend/src/components/layout/MainLayout.tsx | 4 +- frontend/src/components/layout/Sidebar.tsx | 2 +- .../components/monitor/AlertRuleDialog.tsx | 3 +- .../log-center/LogDatasourceDialog.tsx | 2 +- .../monitor/log-center/LogDatasourcePage.tsx | 2 +- .../monitor/log-center/UnifiedQueryPanel.tsx | 13 +-- .../CronJobFormDialog.tsx | 0 .../{automation => task}/CronJobManager.tsx | 0 .../ExecutionHistoryDialog.tsx | 0 .../{automation => task}/ScriptCard.tsx | 0 .../ScriptDetailDialog.tsx | 0 .../ScriptExecutionsTable.tsx | 0 .../{automation => task}/ScriptFormDialog.tsx | 0 .../{automation => task}/ScriptLogsDialog.tsx | 0 .../{automation => task}/ScriptManager.tsx | 0 .../{automation => task}/cronJobHelpers.tsx | 0 .../{automation => task}/script-helpers.tsx | 0 .../components/user/ApiAccessKeySection.tsx | 10 +-- frontend/src/components/user/ProfilePage.tsx | 6 +- frontend/src/locales/en-US.json | 2 +- frontend/src/locales/zh-CN.json | 2 +- frontend/src/pages/AuditPage.tsx | 16 ---- .../pages/{ => approval}/ApprovalAppPage.tsx | 0 .../{ => approval}/ApprovalCategoryPage.tsx | 0 .../{ => approval}/ApprovalPermissionPage.tsx | 0 .../{ => approval}/ApprovalResourcePage.tsx | 0 .../{ => approval}/ApprovalWorkflowPage.tsx | 0 .../pages/{ => audit}/AuditOperationsTab.tsx | 0 .../src/pages/{ => audit}/LoginLogsTab.tsx | 0 .../pages/{ => audit}/TerminalAuditTab.tsx | 0 .../terminal-audit/ActiveSessionsPanel.tsx | 0 .../terminal-audit/HistorySessionsPanel.tsx | 0 .../terminal-audit/SessionCommandsPanel.tsx | 0 .../{ => audit}/terminal-audit/helpers.tsx | 0 .../pages/{ => audit}/terminal-audit/types.ts | 0 .../src/pages/{ => monitor}/HostMonitor.tsx | 0 .../pages/{ => monitor}/MetricsExplorer.tsx | 0 .../pages/{ => monitor}/MiddlewareMonitor.tsx | 0 .../src/pages/{ => monitor}/MonitorCenter.tsx | 0 .../src/pages/{ => monitor}/SNMPMonitor.tsx | 0 .../src/pages/{ => monitor}/SiteMonitor.tsx | 0 .../host-monitor/DualLineChart.tsx | 0 .../host-monitor/HealthProbeSection.tsx | 0 .../host-monitor/MetricChartCard.tsx | 0 .../host-monitor/PortPolicyDialog.tsx | 0 .../host-monitor/SystemInfoSection.tsx | 0 .../pages/{ => monitor}/host-monitor/types.ts | 0 .../pages/{ => monitor}/host-monitor/utils.ts | 0 74 files changed, 229 insertions(+), 216 deletions(-) rename frontend/src/api/{ => agent}/agent.ts (100%) create mode 100644 frontend/src/api/agent/index.ts rename frontend/src/api/{agentCli.ts => aiops/agent-cli.ts} (100%) rename frontend/src/api/{ai.ts => aiops/assistant.ts} (100%) create mode 100644 frontend/src/api/aiops/index.ts rename frontend/src/api/{system => approval}/approval.ts (100%) create mode 100644 frontend/src/api/approval/index.ts rename frontend/src/api/{system => audit}/audit.ts (100%) create mode 100644 frontend/src/api/audit/index.ts rename frontend/src/api/{system => audit}/terminal.ts (100%) create mode 100644 frontend/src/api/log/index.ts rename frontend/src/api/{monitor => log}/log-center.ts (100%) create mode 100644 frontend/src/api/system/user.ts create mode 100644 frontend/src/api/task/cron-job.ts create mode 100644 frontend/src/api/task/index.ts rename frontend/src/api/{automation.ts => task/remote-exec.ts} (54%) create mode 100644 frontend/src/api/task/script.ts rename frontend/src/components/{automation => task}/CronJobFormDialog.tsx (100%) rename frontend/src/components/{automation => task}/CronJobManager.tsx (100%) rename frontend/src/components/{automation => task}/ExecutionHistoryDialog.tsx (100%) rename frontend/src/components/{automation => task}/ScriptCard.tsx (100%) rename frontend/src/components/{automation => task}/ScriptDetailDialog.tsx (100%) rename frontend/src/components/{automation => task}/ScriptExecutionsTable.tsx (100%) rename frontend/src/components/{automation => task}/ScriptFormDialog.tsx (100%) rename frontend/src/components/{automation => task}/ScriptLogsDialog.tsx (100%) rename frontend/src/components/{automation => task}/ScriptManager.tsx (100%) rename frontend/src/components/{automation => task}/cronJobHelpers.tsx (100%) rename frontend/src/components/{automation => task}/script-helpers.tsx (100%) delete mode 100644 frontend/src/pages/AuditPage.tsx rename frontend/src/pages/{ => approval}/ApprovalAppPage.tsx (100%) rename frontend/src/pages/{ => approval}/ApprovalCategoryPage.tsx (100%) rename frontend/src/pages/{ => approval}/ApprovalPermissionPage.tsx (100%) rename frontend/src/pages/{ => approval}/ApprovalResourcePage.tsx (100%) rename frontend/src/pages/{ => approval}/ApprovalWorkflowPage.tsx (100%) rename frontend/src/pages/{ => audit}/AuditOperationsTab.tsx (100%) rename frontend/src/pages/{ => audit}/LoginLogsTab.tsx (100%) rename frontend/src/pages/{ => audit}/TerminalAuditTab.tsx (100%) rename frontend/src/pages/{ => audit}/terminal-audit/ActiveSessionsPanel.tsx (100%) rename frontend/src/pages/{ => audit}/terminal-audit/HistorySessionsPanel.tsx (100%) rename frontend/src/pages/{ => audit}/terminal-audit/SessionCommandsPanel.tsx (100%) rename frontend/src/pages/{ => audit}/terminal-audit/helpers.tsx (100%) rename frontend/src/pages/{ => audit}/terminal-audit/types.ts (100%) rename frontend/src/pages/{ => monitor}/HostMonitor.tsx (100%) rename frontend/src/pages/{ => monitor}/MetricsExplorer.tsx (100%) rename frontend/src/pages/{ => monitor}/MiddlewareMonitor.tsx (100%) rename frontend/src/pages/{ => monitor}/MonitorCenter.tsx (100%) rename frontend/src/pages/{ => monitor}/SNMPMonitor.tsx (100%) rename frontend/src/pages/{ => monitor}/SiteMonitor.tsx (100%) rename frontend/src/pages/{ => monitor}/host-monitor/DualLineChart.tsx (100%) rename frontend/src/pages/{ => monitor}/host-monitor/HealthProbeSection.tsx (100%) rename frontend/src/pages/{ => monitor}/host-monitor/MetricChartCard.tsx (100%) rename frontend/src/pages/{ => monitor}/host-monitor/PortPolicyDialog.tsx (100%) rename frontend/src/pages/{ => monitor}/host-monitor/SystemInfoSection.tsx (100%) rename frontend/src/pages/{ => monitor}/host-monitor/types.ts (100%) rename frontend/src/pages/{ => monitor}/host-monitor/utils.ts (100%) diff --git a/docker-compose.yml b/docker-compose.yml index 6258ebd..4d1f318 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -64,6 +64,12 @@ services: restart: unless-stopped ports: - "8080:8080" + # 容器 DNS:宿主机 systemd-resolved(127.0.0.53) 转发链路异常,导致外网域名 + # (如 Loki 数据源 loki-cex.51aipay.com)在容器内解析失败 → 查询无返回。 + # 显式指定公网上游 DNS 修复 // Logan.Li + dns: + - 223.5.5.5 + - 8.8.8.8 environment: TZ: Asia/Shanghai MODE: release diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 658ffa2..1b2e5e3 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -33,16 +33,16 @@ const CapacityPage = lazy(() => import('@/components/kubernetes/CapacityPage').t const K8sShortcutRedirect = lazy(() => import('@/components/kubernetes/K8sShortcutRedirect').then(m => ({ default: m.default }))); const AlertManager = lazy(() => import('@/components/monitor/AlertManager').then(m => ({ default: m.AlertManager }))); const ApprovalFlowManager = lazy(() => import('@/components/approval/ApprovalFlow').then(m => ({ default: m.ApprovalFlowManager }))); -const ApprovalResourcePage = lazy(() => import('@/pages/ApprovalResourcePage').then(m => ({ default: m.ApprovalResourcePage }))); -const ApprovalAppPage = lazy(() => import('@/pages/ApprovalAppPage').then(m => ({ default: m.ApprovalAppPage }))); -const ApprovalPermissionPage = lazy(() => import('@/pages/ApprovalPermissionPage').then(m => ({ default: m.ApprovalPermissionPage }))); -const ApprovalWorkflowPage = lazy(() => import('@/pages/ApprovalWorkflowPage').then(m => ({ default: m.default }))); -const ScriptManager = lazy(() => import('@/components/automation/ScriptManager').then(m => ({ default: m.ScriptManager }))); +const ApprovalResourcePage = lazy(() => import('@/pages/approval/ApprovalResourcePage').then(m => ({ default: m.ApprovalResourcePage }))); +const ApprovalAppPage = lazy(() => import('@/pages/approval/ApprovalAppPage').then(m => ({ default: m.ApprovalAppPage }))); +const ApprovalPermissionPage = lazy(() => import('@/pages/approval/ApprovalPermissionPage').then(m => ({ default: m.ApprovalPermissionPage }))); +const ApprovalWorkflowPage = lazy(() => import('@/pages/approval/ApprovalWorkflowPage').then(m => ({ default: m.default }))); +const ScriptManager = lazy(() => import('@/components/task/ScriptManager').then(m => ({ default: m.ScriptManager }))); const SystemManager = lazy(() => import('@/components/system/SystemManager').then(m => ({ default: m.SystemManager }))); const ProfilePage = lazy(() => import('@/components/user/ProfilePage')); -const TerminalAuditTab = lazy(() => import('@/pages/TerminalAuditTab').then(m => ({ default: m.TerminalAuditTab }))); -const AuditOperationsTab = lazy(() => import('@/pages/AuditOperationsTab').then(m => ({ default: m.AuditOperationsTab }))); -const LoginLogsTab = lazy(() => import('@/pages/LoginLogsTab').then(m => ({ default: m.LoginLogsTab }))); +const TerminalAuditTab = lazy(() => import('@/pages/audit/TerminalAuditTab').then(m => ({ default: m.TerminalAuditTab }))); +const AuditOperationsTab = lazy(() => import('@/pages/audit/AuditOperationsTab').then(m => ({ default: m.AuditOperationsTab }))); +const LoginLogsTab = lazy(() => import('@/pages/audit/LoginLogsTab').then(m => ({ default: m.LoginLogsTab }))); const CredentialManager = lazy(() => import('@/components/deploy/CredentialManager').then(m => ({ default: m.default }))); const PipelineManager = lazy(() => import('@/components/deploy/PipelineManager').then(m => ({ default: m.PipelineManager }))); const DeployCredentials = lazy(() => import('@/components/deploy/DeployCredentials').then(m => ({ default: m.default }))); @@ -50,7 +50,7 @@ const PipelineEditor = lazy(() => import('@/components/deploy/PipelineEditor').t const PipelineRunDetail = lazy(() => import('@/components/deploy/PipelineRunDetail').then(m => ({ default: m.default }))); const DeployRBAC = lazy(() => import('@/components/deploy/DeployRBAC').then(m => ({ default: m.default }))); const UserGroupsManager = lazy(() => import('@/components/deploy/UserGroupsManager').then(m => ({ default: m.default }))); -const CronJobManager = lazy(() => import('@/components/automation/CronJobManager').then(m => ({ default: m.CronJobManager }))); +const CronJobManager = lazy(() => import('@/components/task/CronJobManager').then(m => ({ default: m.CronJobManager }))); const AIOpsAssistant = lazy(() => import('@/components/aiops/AIOpsAssistant').then(m => ({ default: m.AIOpsAssistant }))); const AIAlertAnalyzer = lazy(() => import('@/components/aiops/AIAlertAnalyzer').then(m => ({ default: m.AIAlertAnalyzer }))); const AIPredictiveAnalytics = lazy(() => import('@/components/aiops/AIPredictiveAnalytics').then(m => ({ default: m.AIPredictiveAnalytics }))); @@ -58,10 +58,10 @@ const AgentCLI = lazy(() => import('@/components/aiops/AgentCLI').then(m => ({ d const LLMConfigPage = lazy(() => import('@/components/aiops/LLMConfig').then(m => ({ default: m.default }))); const AlertCenter = lazy(() => import('@/components/monitor/alert-center/AlertCenter').then(m => ({ default: m.default }))); const TraceManager = lazy(() => import('@/components/monitor/trace/TraceManager').then(m => ({ default: m.default }))); -const HostMonitor = lazy(() => import('@/pages/HostMonitor').then(m => ({ default: m.HostMonitor }))); +const HostMonitor = lazy(() => import('@/pages/monitor/HostMonitor').then(m => ({ default: m.HostMonitor }))); const GrafanaDashboard = lazy(() => import('@/components/monitor/dashboard/GrafanaDashboard').then(m => ({ default: m.default }))); -const MonitorCenter = lazy(() => import('@/pages/MonitorCenter').then(m => ({ default: m.MonitorCenter }))); -const MetricsExplorer = lazy(() => import('@/pages/MetricsExplorer').then(m => ({ default: m.MetricsExplorer }))); +const MonitorCenter = lazy(() => import('@/pages/monitor/MonitorCenter').then(m => ({ default: m.MonitorCenter }))); +const MetricsExplorer = lazy(() => import('@/pages/monitor/MetricsExplorer').then(m => ({ default: m.MetricsExplorer }))); const DatasourcePage = lazy(() => import('@/components/monitor/datasource/DatasourcePage').then(m => ({ default: m.default }))); const LogCenter = lazy(() => import('@/components/monitor/log-center/LogCenter')); diff --git a/frontend/src/api/agent.ts b/frontend/src/api/agent/agent.ts similarity index 100% rename from frontend/src/api/agent.ts rename to frontend/src/api/agent/agent.ts diff --git a/frontend/src/api/agent/index.ts b/frontend/src/api/agent/index.ts new file mode 100644 index 0000000..d8cd228 --- /dev/null +++ b/frontend/src/api/agent/index.ts @@ -0,0 +1,3 @@ +// 资源监控 Agent API 聚合出口 // Logan.Li + +export * from './agent'; diff --git a/frontend/src/api/agentCli.ts b/frontend/src/api/aiops/agent-cli.ts similarity index 100% rename from frontend/src/api/agentCli.ts rename to frontend/src/api/aiops/agent-cli.ts diff --git a/frontend/src/api/ai.ts b/frontend/src/api/aiops/assistant.ts similarity index 100% rename from frontend/src/api/ai.ts rename to frontend/src/api/aiops/assistant.ts diff --git a/frontend/src/api/aiops/index.ts b/frontend/src/api/aiops/index.ts new file mode 100644 index 0000000..b4b8d71 --- /dev/null +++ b/frontend/src/api/aiops/index.ts @@ -0,0 +1,4 @@ +// AIOps 智能 API 聚合出口 // Logan.Li + +export * from './assistant'; +export * from './agent-cli'; diff --git a/frontend/src/api/system/approval.ts b/frontend/src/api/approval/approval.ts similarity index 100% rename from frontend/src/api/system/approval.ts rename to frontend/src/api/approval/approval.ts diff --git a/frontend/src/api/approval/index.ts b/frontend/src/api/approval/index.ts new file mode 100644 index 0000000..6c3c15a --- /dev/null +++ b/frontend/src/api/approval/index.ts @@ -0,0 +1,3 @@ +// 资源申请 API 聚合出口 // Logan.Li + +export * from './approval'; diff --git a/frontend/src/api/system/audit.ts b/frontend/src/api/audit/audit.ts similarity index 100% rename from frontend/src/api/system/audit.ts rename to frontend/src/api/audit/audit.ts diff --git a/frontend/src/api/audit/index.ts b/frontend/src/api/audit/index.ts new file mode 100644 index 0000000..aa9f2ad --- /dev/null +++ b/frontend/src/api/audit/index.ts @@ -0,0 +1,4 @@ +// 安全审计 API 聚合出口 // Logan.Li + +export * from './audit'; +export * from './terminal'; diff --git a/frontend/src/api/system/terminal.ts b/frontend/src/api/audit/terminal.ts similarity index 100% rename from frontend/src/api/system/terminal.ts rename to frontend/src/api/audit/terminal.ts diff --git a/frontend/src/api/auth.ts b/frontend/src/api/auth.ts index 5aa5950..7b73025 100644 --- a/frontend/src/api/auth.ts +++ b/frontend/src/api/auth.ts @@ -1,10 +1,9 @@ -// 用户认证 & LDAP -// 从 services/api.ts 拆分 — Q3 api.ts 模块化 +// 用户认证 API — login / profile / password / api-key(自服务)// Logan.Li +// 用户·角色·LDAP 管理已拆到 system/user.ts -import { http, getApiBase, type ListResponse } from '@/utils/request'; -import { useUserStore } from '@/store'; +import { http } from '@/utils/request'; -export const userApi = { +export const authApi = { login: async (username: string, password: string) => { return http.post<{ token: string; expires_in: number; user: unknown; permissions?: string[] }>( '/auth/login', @@ -80,81 +79,4 @@ export const userApi = { revokeApiAccessKey: async () => { return http.delete('/user/api-access-key'); }, - resetUserPassword: async (id: number | string, new_password: string) => { - return http.post(`/admin/users/${id}/reset-password`, { new_password }); - }, - getUsers: async (params?: { page?: number; page_size?: number; keyword?: string }) => { - return http.get('/admin/users', params); - }, - createUser: async ( data: Record) => { - return http.post('/admin/users', data); - }, - updateUser: async (id: number | string, data: Record) => { - return http.put(`/admin/users/${id}`, data); - }, - deleteUser: async (id: number | string) => { - return http.delete(`/admin/users/${id}`); - }, - batchImport: async (data: { users: Record[]; skip_existing?: boolean }) => { - return http.post('/admin/users/batch-import', data); - }, - downloadTemplate: () => { - const token = useUserStore.getState().token || localStorage.getItem('token') || ''; - window.open(`${getApiBase()}/admin/users/import-template?token=${token}`, '_blank'); - }, - // 角色列表 // Logan.Li - getRoles: async () => { - return http.get('/user/roles'); - }, - // 角色管理(管理员) // Logan.Li - createRole: async (data: { name: string; code: string; description?: string; permission_ids?: number[] }) => { - return http.post('/admin/roles', data); - }, - updateRole: async (id: number | string, data: { name?: string; code?: string; description?: string; permission_ids?: number[] }) => { - return http.put(`/admin/roles/${id}`, data); - }, - deleteRole: async (id: number | string) => { - return http.delete(`/admin/roles/${id}`); - }, - // 权限列表(供角色权限选择) - getPermissions: async () => { - return http.get('/admin/permissions'); - }, }; - -// ==================== LDAP 配置 API ==================== - -export const ldapApi = { - getConfig: async () => { - return http.get('/admin/ldap-config'); - }, - updateConfig: async ( data: object) => { - return http.put('/admin/ldap-config', data); - }, - testConnection: async (data?: { test_user?: string; test_password?: string }) => { - return http.post('/admin/ldap-config/test', data || {}); - }, - listUsers: async (ouDn?: string) => { - return http.post('/admin/ldap-config/users', { ou_dn: ouDn || '' }); - }, - batchImport: async ( users: Record[]) => { - return http.post('/admin/ldap-config/import', { users }); - }, - listOUs: async () => { - return http.post('/admin/ldap-config/ou-list', {}); - }, - createOU: async (data: { ou_name: string; parent_dn?: string; description?: string }) => { - return http.post('/admin/ldap-config/create-ou', data); - }, - createUser: async (data: { username: string; password: string; display_name?: string; email?: string; ou_dn?: string }) => { - return http.post('/admin/ldap-config/create-user', data); - }, - deleteUser: async (dn: string) => { - return http.post('/admin/ldap-config/delete-user', { dn }); - }, - updateUser: async (data: { dn: string; cn?: string; mail?: string; phone?: string; title?: string }) => { - return http.post('/admin/ldap-config/update-user', data); - }, -}; - -// ==================== 仪表盘 API ==================== diff --git a/frontend/src/api/index.ts b/frontend/src/api/index.ts index e583e24..5bfe348 100644 --- a/frontend/src/api/index.ts +++ b/frontend/src/api/index.ts @@ -4,12 +4,14 @@ export * from './auth'; export * from './dashboard'; export * from './server'; +export * from './cloud'; export * from './kubernetes'; export * from './deploy'; -export * from './automation'; export * from './monitor'; +export * from './log'; +export * from './task'; +export * from './aiops'; export * from './agent'; -export * from './cloud'; +export * from './approval'; +export * from './audit'; export * from './system'; -export * from './ai'; -export * from './agentCli'; diff --git a/frontend/src/api/log/index.ts b/frontend/src/api/log/index.ts new file mode 100644 index 0000000..1f3ea58 --- /dev/null +++ b/frontend/src/api/log/index.ts @@ -0,0 +1,8 @@ +// 日志中心 API 聚合出口 // Logan.Li + +export { + logCenterApi, + type LogDataSource, + type LogQueryEntry, + type TestConnectionResult, +} from './log-center'; diff --git a/frontend/src/api/monitor/log-center.ts b/frontend/src/api/log/log-center.ts similarity index 100% rename from frontend/src/api/monitor/log-center.ts rename to frontend/src/api/log/log-center.ts diff --git a/frontend/src/api/monitor/index.ts b/frontend/src/api/monitor/index.ts index e6d0461..129e744 100644 --- a/frontend/src/api/monitor/index.ts +++ b/frontend/src/api/monitor/index.ts @@ -7,5 +7,4 @@ export { traceApi } from './trace'; export { traceDatasourceApi, type TraceDataSource } from './trace-datasource'; export { dashboardApi } from './grafana'; export { promDatasourceApi, zabbixDatasourceApi } from './datasource'; -export { logCenterApi, type LogDataSource, type LogQueryEntry } from './log-center'; export { metricsApi, snmpApi, prometheusProxyApi, zabbixProxyApi } from './metrics'; \ No newline at end of file diff --git a/frontend/src/api/system.ts b/frontend/src/api/system.ts index c83c27e..6bb99aa 100644 --- a/frontend/src/api/system.ts +++ b/frontend/src/api/system.ts @@ -1,10 +1,3 @@ // 系统域 API — 子模块 re-export // Logan.Li -export { - auditApi, - terminalSessionApi, - sessionCommandApi, - loginLogApi, - approvalWorkflowApi, - approvalApi, -} from './system/index'; \ No newline at end of file +export * from './system/index'; diff --git a/frontend/src/api/system/index.ts b/frontend/src/api/system/index.ts index 36e1d0e..039673f 100644 --- a/frontend/src/api/system/index.ts +++ b/frontend/src/api/system/index.ts @@ -1,5 +1,3 @@ -// 系统域 API 聚合出口 // Logan.Li +// 系统管理 API 聚合出口 // Logan.Li -export { auditApi } from './audit'; -export { terminalSessionApi, sessionCommandApi, loginLogApi } from './terminal'; -export { approvalWorkflowApi, approvalApi } from './approval'; \ No newline at end of file +export { userApi, ldapApi } from './user'; diff --git a/frontend/src/api/system/user.ts b/frontend/src/api/system/user.ts new file mode 100644 index 0000000..da298fd --- /dev/null +++ b/frontend/src/api/system/user.ts @@ -0,0 +1,84 @@ +// 系统管理 — 用户 / 角色 / LDAP 管理 API(admin)// Logan.Li +// 从 auth.ts 拆出:用户·角色管理(admin)+ LDAP 配置 + +import { http, getApiBase, type ListResponse } from '@/utils/request'; +import { useUserStore } from '@/store'; + +// 用户 & 角色管理(管理员) +export const userApi = { + resetUserPassword: async (id: number | string, new_password: string) => { + return http.post(`/admin/users/${id}/reset-password`, { new_password }); + }, + getUsers: async (params?: { page?: number; page_size?: number; keyword?: string }) => { + return http.get('/admin/users', params); + }, + createUser: async ( data: Record) => { + return http.post('/admin/users', data); + }, + updateUser: async (id: number | string, data: Record) => { + return http.put(`/admin/users/${id}`, data); + }, + deleteUser: async (id: number | string) => { + return http.delete(`/admin/users/${id}`); + }, + batchImport: async (data: { users: Record[]; skip_existing?: boolean }) => { + return http.post('/admin/users/batch-import', data); + }, + downloadTemplate: () => { + const token = useUserStore.getState().token || localStorage.getItem('token') || ''; + window.open(`${getApiBase()}/admin/users/import-template?token=${token}`, '_blank'); + }, + // 角色列表 // Logan.Li + getRoles: async () => { + return http.get('/user/roles'); + }, + // 角色管理(管理员) // Logan.Li + createRole: async (data: { name: string; code: string; description?: string; permission_ids?: number[] }) => { + return http.post('/admin/roles', data); + }, + updateRole: async (id: number | string, data: { name?: string; code?: string; description?: string; permission_ids?: number[] }) => { + return http.put(`/admin/roles/${id}`, data); + }, + deleteRole: async (id: number | string) => { + return http.delete(`/admin/roles/${id}`); + }, + // 权限列表(供角色权限选择) + getPermissions: async () => { + return http.get('/admin/permissions'); + }, +}; + +// ==================== LDAP 配置 API ==================== + +export const ldapApi = { + getConfig: async () => { + return http.get('/admin/ldap-config'); + }, + updateConfig: async ( data: object) => { + return http.put('/admin/ldap-config', data); + }, + testConnection: async (data?: { test_user?: string; test_password?: string }) => { + return http.post('/admin/ldap-config/test', data || {}); + }, + listUsers: async (ouDn?: string) => { + return http.post('/admin/ldap-config/users', { ou_dn: ouDn || '' }); + }, + batchImport: async ( users: Record[]) => { + return http.post('/admin/ldap-config/import', { users }); + }, + listOUs: async () => { + return http.post('/admin/ldap-config/ou-list', {}); + }, + createOU: async (data: { ou_name: string; parent_dn?: string; description?: string }) => { + return http.post('/admin/ldap-config/create-ou', data); + }, + createUser: async (data: { username: string; password: string; display_name?: string; email?: string; ou_dn?: string }) => { + return http.post('/admin/ldap-config/create-user', data); + }, + deleteUser: async (dn: string) => { + return http.post('/admin/ldap-config/delete-user', { dn }); + }, + updateUser: async (data: { dn: string; cn?: string; mail?: string; phone?: string; title?: string }) => { + return http.post('/admin/ldap-config/update-user', data); + }, +}; diff --git a/frontend/src/api/task/cron-job.ts b/frontend/src/api/task/cron-job.ts new file mode 100644 index 0000000..71351b0 --- /dev/null +++ b/frontend/src/api/task/cron-job.ts @@ -0,0 +1,30 @@ +// 作业任务 — 定时任务 API(/cron-jobs)// Logan.Li + +import { http, type ListResponse } from '@/utils/request'; + +export const cronJobApi = { + getJobs: async (params?: { page?: number; page_size?: number }) => { + return http.get('/cron-jobs', params); + }, + getJob: async (id: number | string) => { + return http.get(`/cron-jobs/${id}`); + }, + createJob: async ( data: Record) => { + return http.post('/cron-jobs', data); + }, + updateJob: async (id: number | string, data: Record) => { + return http.put(`/cron-jobs/${id}`, data); + }, + deleteJob: async (id: number | string) => { + return http.delete(`/cron-jobs/${id}`); + }, + toggleJob: async (id: number | string) => { + return http.post(`/cron-jobs/${id}/toggle`); + }, + executeJob: async (id: number | string) => { + return http.post(`/cron-jobs/${id}/execute`); + }, + batchDelete: async (ids: number[]) => { + return http.delete('/cron-jobs/batch-delete', { ids }); + }, +}; diff --git a/frontend/src/api/task/index.ts b/frontend/src/api/task/index.ts new file mode 100644 index 0000000..4a7f24c --- /dev/null +++ b/frontend/src/api/task/index.ts @@ -0,0 +1,5 @@ +// 作业任务 API 聚合出口 // Logan.Li + +export * from './cron-job'; +export * from './script'; +export * from './remote-exec'; diff --git a/frontend/src/api/automation.ts b/frontend/src/api/task/remote-exec.ts similarity index 54% rename from frontend/src/api/automation.ts rename to frontend/src/api/task/remote-exec.ts index e496259..2665322 100644 --- a/frontend/src/api/automation.ts +++ b/frontend/src/api/task/remote-exec.ts @@ -1,71 +1,15 @@ -// 自动化运维 (定时任务/脚本/Ansible) -// 从 services/api.ts 拆分 — Q3 api.ts 模块化 +// 作业任务 — 远程执行 API(/ansible + /task-executions)// Logan.Li import { http, type ListResponse } from '@/utils/request'; -export const cronJobApi = { - getJobs: async (params?: { page?: number; page_size?: number }) => { - return http.get('/cron-jobs', params); - }, - getJob: async (id: number | string) => { - return http.get(`/cron-jobs/${id}`); - }, - createJob: async ( data: Record) => { - return http.post('/cron-jobs', data); - }, - updateJob: async (id: number | string, data: Record) => { - return http.put(`/cron-jobs/${id}`, data); - }, - deleteJob: async (id: number | string) => { - return http.delete(`/cron-jobs/${id}`); - }, - toggleJob: async (id: number | string) => { - return http.post(`/cron-jobs/${id}/toggle`); - }, - executeJob: async (id: number | string) => { - return http.post(`/cron-jobs/${id}/execute`); - }, - batchDelete: async (ids: number[]) => { - return http.delete('/cron-jobs/batch-delete', { ids }); - }, -}; - -// ==================== 脚本 API ==================== - -export const scriptApi = { - getScripts: async (params?: { page?: number; page_size?: number }) => { - return http.get('/scripts', params); - }, - getScript: async (id: number | string) => { - return http.get(`/scripts/${id}`); - }, - createScript: async ( data: Record) => { - return http.post('/scripts', data); - }, - updateScript: async (id: number | string, data: Record) => { - return http.put(`/scripts/${id}`, data); - }, - deleteScript: async (id: number | string) => { - return http.delete(`/scripts/${id}`); - }, - batchDelete: async (ids: number[]) => { - return http.post('/scripts/batch-delete', { ids }); - }, - executeScript: async (id: number | string) => { - return http.post(`/scripts/${id}/execute`); - }, -}; - -// ==================== 任务执行记录 API ==================== - +// 任务执行记录 API export const taskExecutionApi = { getExecutions: async (params?: { task_type?: string; task_id?: string; page?: number; page_size?: number }) => { return http.get('/task-executions', params); }, }; -// ==================== 审批流程 API ==================== - +// Ansible / 远程执行 API export const ansibleApi = { // Playbook 管理 getPlaybooks: async (params?: { page?: number; page_size?: number; keyword?: string }) => { @@ -119,6 +63,3 @@ export const ansibleApi = { return http.delete(`/ansible/inventories/${id}`); }, }; - -// ==================== 告警中心 API(基于 /alerts 真实路由) ==================== -// 说明:alertCenterApi 与 alertApi 共用同一套后端 /alerts 路由,此处独立封装以便告警中心页使用 diff --git a/frontend/src/api/task/script.ts b/frontend/src/api/task/script.ts new file mode 100644 index 0000000..985edf5 --- /dev/null +++ b/frontend/src/api/task/script.ts @@ -0,0 +1,27 @@ +// 作业任务 — 脚本库 API(/scripts)// Logan.Li + +import { http, type ListResponse } from '@/utils/request'; + +export const scriptApi = { + getScripts: async (params?: { page?: number; page_size?: number }) => { + return http.get('/scripts', params); + }, + getScript: async (id: number | string) => { + return http.get(`/scripts/${id}`); + }, + createScript: async ( data: Record) => { + return http.post('/scripts', data); + }, + updateScript: async (id: number | string, data: Record) => { + return http.put(`/scripts/${id}`, data); + }, + deleteScript: async (id: number | string) => { + return http.delete(`/scripts/${id}`); + }, + batchDelete: async (ids: number[]) => { + return http.post('/scripts/batch-delete', { ids }); + }, + executeScript: async (id: number | string) => { + return http.post(`/scripts/${id}/execute`); + }, +}; diff --git a/frontend/src/components/auth/Login.tsx b/frontend/src/components/auth/Login.tsx index fa51cf9..c275c25 100644 --- a/frontend/src/components/auth/Login.tsx +++ b/frontend/src/components/auth/Login.tsx @@ -3,7 +3,7 @@ import { useNavigate } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; import { User, Lock, Palette, Check, Loader2, AlertCircle, Eye, EyeOff, Languages } from 'lucide-react'; import { useUserStore, useLanguageStore } from '@/store'; -import { userApi } from '@/api'; +import { authApi } from '@/api'; import { useTheme, THEME_OPTIONS } from '@/hooks/useTheme'; import { cn } from '@/lib/utils'; import { SUPPORTED_LANGUAGES, type AppLanguage } from '@/i18n'; @@ -89,7 +89,7 @@ export function Login() { setError(''); setLoading(true); try { - const result = await userApi.login(username, password) as { user: any; token: string; permissions?: string[] }; + const result = await authApi.login(username, password) as { user: any; token: string; permissions?: string[] }; useUserStore.getState().login(result.user, result.token, result.permissions ?? null); localStorage.setItem('token', result.token); navigate('/', { replace: true }); diff --git a/frontend/src/components/kubernetes/deployment-workload/CICDWebhookContent.tsx b/frontend/src/components/kubernetes/deployment-workload/CICDWebhookContent.tsx index 9e9ac27..d683e04 100644 --- a/frontend/src/components/kubernetes/deployment-workload/CICDWebhookContent.tsx +++ b/frontend/src/components/kubernetes/deployment-workload/CICDWebhookContent.tsx @@ -3,7 +3,7 @@ import { useEffect, useMemo, useState } from 'react'; import { Link } from 'react-router-dom'; import { Loader2 } from 'lucide-react'; import { CodeSnippetBlock } from '@/components/ui/code-snippet-block'; -import { userApi } from '@/api'; +import { authApi } from '@/api'; import { getPublicApiBase } from '@/utils/request'; import { getSessionApiAccessKey } from '@/utils/storage'; @@ -37,7 +37,7 @@ export function CICDWebhookContent({ const cached = getSessionApiAccessKey(); if (cached) setAccessKey(cached); try { - const meta = await userApi.getApiAccessKey(); + const meta = await authApi.getApiAccessKey(); if (!cancelled) { setHasKey(!!meta?.has_token); setKeyExpired(!!meta?.expired); diff --git a/frontend/src/components/layout/MainLayout.tsx b/frontend/src/components/layout/MainLayout.tsx index abd8325..c235b95 100644 --- a/frontend/src/components/layout/MainLayout.tsx +++ b/frontend/src/components/layout/MainLayout.tsx @@ -5,7 +5,7 @@ import { useThemeStore, useUserStore } from '@/store'; import { Sidebar } from './Sidebar'; import { Header } from './Header'; import { Breadcrumb } from './Breadcrumb'; -import { userApi } from '@/api'; +import { authApi } from '@/api'; import type { JsonData } from '@/types/common'; /** @@ -30,7 +30,7 @@ export function MainLayout() { useEffect(() => { if (!token || permissions !== null) return; let cancelled = false; - userApi.getMyPermissions() + authApi.getMyPermissions() .then((data: JsonData) => { if (cancelled) return; const perms: string[] = data?.permissions ?? []; diff --git a/frontend/src/components/layout/Sidebar.tsx b/frontend/src/components/layout/Sidebar.tsx index 3f546c3..4bcb59f 100644 --- a/frontend/src/components/layout/Sidebar.tsx +++ b/frontend/src/components/layout/Sidebar.tsx @@ -136,7 +136,7 @@ const menuItems: MenuItem[] = [ ], }, { - id: 'automation', name: '自动化运维', labelKey: 'menu.automation', icon: PlayCircle, permission: 'auto:cron', + id: 'automation', name: '作业任务', labelKey: 'menu.automation', icon: PlayCircle, permission: 'auto:cron', children: [ { id: 'cronjobs', name: '定时任务', labelKey: 'menu.cronJobs', icon: PlayCircle, path: '/cronjobs', permission: 'auto:cron' }, { id: 'scripts', name: '脚本库', labelKey: 'menu.scripts', icon: FileCode, path: '/scripts', permission: 'auto:script' }, diff --git a/frontend/src/components/monitor/AlertRuleDialog.tsx b/frontend/src/components/monitor/AlertRuleDialog.tsx index ba8d9ad..1d2851b 100644 --- a/frontend/src/components/monitor/AlertRuleDialog.tsx +++ b/frontend/src/components/monitor/AlertRuleDialog.tsx @@ -13,8 +13,7 @@ import { DialogTitle, } from '@/components/ui/dialog'; import { Loader2 } from 'lucide-react'; -import { alertApi } from '@/api'; -import { logCenterApi, type LogDataSource } from '@/api/monitor/log-center'; +import { alertApi, logCenterApi, type LogDataSource } from '@/api'; import { parseChannels, getChannelIcon, getChannelTypeLabel } from './alertShared'; import type { JsonData } from '@/types/common'; diff --git a/frontend/src/components/monitor/log-center/LogDatasourceDialog.tsx b/frontend/src/components/monitor/log-center/LogDatasourceDialog.tsx index 37730b4..55ca7ab 100644 --- a/frontend/src/components/monitor/log-center/LogDatasourceDialog.tsx +++ b/frontend/src/components/monitor/log-center/LogDatasourceDialog.tsx @@ -12,7 +12,7 @@ import { } from '@/components/ui/select'; import { Loader2, Plug, RefreshCw } from 'lucide-react'; import { useToast } from '@/hooks/use-toast'; -import { logCenterApi, type LogDataSource, type TestConnectionResult } from '@/api/monitor/log-center'; +import { logCenterApi, type LogDataSource, type TestConnectionResult } from '@/api'; import type { LogEngine } from './log-center-types'; export function LogDatasourceDialog({ diff --git a/frontend/src/components/monitor/log-center/LogDatasourcePage.tsx b/frontend/src/components/monitor/log-center/LogDatasourcePage.tsx index d7d1dc2..228c2b2 100644 --- a/frontend/src/components/monitor/log-center/LogDatasourcePage.tsx +++ b/frontend/src/components/monitor/log-center/LogDatasourcePage.tsx @@ -8,7 +8,7 @@ import { } from 'lucide-react'; import { useToast } from '@/hooks/use-toast'; import { useConfirm } from '@/components/ui/confirm-dialog'; -import { logCenterApi, type LogDataSource, type TestConnectionResult } from '@/api/monitor/log-center'; +import { logCenterApi, type LogDataSource, type TestConnectionResult } from '@/api'; import { LogDatasourceDialog } from './LogDatasourceDialog'; import type { LogEngine } from './log-center-types'; diff --git a/frontend/src/components/monitor/log-center/UnifiedQueryPanel.tsx b/frontend/src/components/monitor/log-center/UnifiedQueryPanel.tsx index ac7a650..7baf910 100644 --- a/frontend/src/components/monitor/log-center/UnifiedQueryPanel.tsx +++ b/frontend/src/components/monitor/log-center/UnifiedQueryPanel.tsx @@ -11,7 +11,7 @@ import { LogClusterPanel } from './LogClusterPanel'; import { SaveQueryDialog, SaveAlertDialog } from './SaveQueryDialog'; import { QueryHistoryPanel } from './QueryHistoryPanel'; import { LogAlertFromQueryDialog } from './LogAlertFromQueryDialog'; -import { logCenterApi, type LogDataSource } from '@/api/monitor/log-center'; +import { logCenterApi, type LogDataSource } from '@/api'; import type { LogEngine, TimeRange, ResultTab, ViewMode, LogEntry, StatTable, LogCluster, QueryHistoryItem } from './types-v3'; import { ENGINE_META, buildStatTableFromEntries, buildClustersFromEntries, extractFields, generateHistogramData, historyStorage } from './types-v3'; import { useToast } from '@/hooks/use-toast'; @@ -280,8 +280,13 @@ export function UnifiedQueryPanel({ engine, onRuleCreated }: Props) { {badge.label} + - + + {/* 次级控件行(时间 / 数据源 / 索引 / 上限 / 另存为 / 历史)// Logan.Li */} +