refactor(frontend): api/components/pages 目录架构统一对齐菜单域 + 日志中心修复
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 <noreply@anthropic.com>
This commit is contained in:
1 parent
da01cbb119
commit
c0ee8e4ddd
74 files changed
+229
-216
No files matched your search
@@ -64,6 +64,12 @@ services:
|
|||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
ports:
|
ports:
|
||||||
- "8080:8080"
|
- "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:
|
environment:
|
||||||
TZ: Asia/Shanghai
|
TZ: Asia/Shanghai
|
||||||
MODE: release
|
MODE: release
|
||||||
|
|||||||
+12
-12
@@ -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 K8sShortcutRedirect = lazy(() => import('@/components/kubernetes/K8sShortcutRedirect').then(m => ({ default: m.default })));
|
||||||
const AlertManager = lazy(() => import('@/components/monitor/AlertManager').then(m => ({ default: m.AlertManager })));
|
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 ApprovalFlowManager = lazy(() => import('@/components/approval/ApprovalFlow').then(m => ({ default: m.ApprovalFlowManager })));
|
||||||
const ApprovalResourcePage = lazy(() => import('@/pages/ApprovalResourcePage').then(m => ({ default: m.ApprovalResourcePage })));
|
const ApprovalResourcePage = lazy(() => import('@/pages/approval/ApprovalResourcePage').then(m => ({ default: m.ApprovalResourcePage })));
|
||||||
const ApprovalAppPage = lazy(() => import('@/pages/ApprovalAppPage').then(m => ({ default: m.ApprovalAppPage })));
|
const ApprovalAppPage = lazy(() => import('@/pages/approval/ApprovalAppPage').then(m => ({ default: m.ApprovalAppPage })));
|
||||||
const ApprovalPermissionPage = lazy(() => import('@/pages/ApprovalPermissionPage').then(m => ({ default: m.ApprovalPermissionPage })));
|
const ApprovalPermissionPage = lazy(() => import('@/pages/approval/ApprovalPermissionPage').then(m => ({ default: m.ApprovalPermissionPage })));
|
||||||
const ApprovalWorkflowPage = lazy(() => import('@/pages/ApprovalWorkflowPage').then(m => ({ default: m.default })));
|
const ApprovalWorkflowPage = lazy(() => import('@/pages/approval/ApprovalWorkflowPage').then(m => ({ default: m.default })));
|
||||||
const ScriptManager = lazy(() => import('@/components/automation/ScriptManager').then(m => ({ default: m.ScriptManager })));
|
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 SystemManager = lazy(() => import('@/components/system/SystemManager').then(m => ({ default: m.SystemManager })));
|
||||||
const ProfilePage = lazy(() => import('@/components/user/ProfilePage'));
|
const ProfilePage = lazy(() => import('@/components/user/ProfilePage'));
|
||||||
const TerminalAuditTab = lazy(() => import('@/pages/TerminalAuditTab').then(m => ({ default: m.TerminalAuditTab })));
|
const TerminalAuditTab = lazy(() => import('@/pages/audit/TerminalAuditTab').then(m => ({ default: m.TerminalAuditTab })));
|
||||||
const AuditOperationsTab = lazy(() => import('@/pages/AuditOperationsTab').then(m => ({ default: m.AuditOperationsTab })));
|
const AuditOperationsTab = lazy(() => import('@/pages/audit/AuditOperationsTab').then(m => ({ default: m.AuditOperationsTab })));
|
||||||
const LoginLogsTab = lazy(() => import('@/pages/LoginLogsTab').then(m => ({ default: m.LoginLogsTab })));
|
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 CredentialManager = lazy(() => import('@/components/deploy/CredentialManager').then(m => ({ default: m.default })));
|
||||||
const PipelineManager = lazy(() => import('@/components/deploy/PipelineManager').then(m => ({ default: m.PipelineManager })));
|
const PipelineManager = lazy(() => import('@/components/deploy/PipelineManager').then(m => ({ default: m.PipelineManager })));
|
||||||
const DeployCredentials = lazy(() => import('@/components/deploy/DeployCredentials').then(m => ({ default: m.default })));
|
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 PipelineRunDetail = lazy(() => import('@/components/deploy/PipelineRunDetail').then(m => ({ default: m.default })));
|
||||||
const DeployRBAC = lazy(() => import('@/components/deploy/DeployRBAC').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 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 AIOpsAssistant = lazy(() => import('@/components/aiops/AIOpsAssistant').then(m => ({ default: m.AIOpsAssistant })));
|
||||||
const AIAlertAnalyzer = lazy(() => import('@/components/aiops/AIAlertAnalyzer').then(m => ({ default: m.AIAlertAnalyzer })));
|
const AIAlertAnalyzer = lazy(() => import('@/components/aiops/AIAlertAnalyzer').then(m => ({ default: m.AIAlertAnalyzer })));
|
||||||
const AIPredictiveAnalytics = lazy(() => import('@/components/aiops/AIPredictiveAnalytics').then(m => ({ default: m.AIPredictiveAnalytics })));
|
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 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 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 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 GrafanaDashboard = lazy(() => import('@/components/monitor/dashboard/GrafanaDashboard').then(m => ({ default: m.default })));
|
||||||
const MonitorCenter = lazy(() => import('@/pages/MonitorCenter').then(m => ({ default: m.MonitorCenter })));
|
const MonitorCenter = lazy(() => import('@/pages/monitor/MonitorCenter').then(m => ({ default: m.MonitorCenter })));
|
||||||
const MetricsExplorer = lazy(() => import('@/pages/MetricsExplorer').then(m => ({ default: m.MetricsExplorer })));
|
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 DatasourcePage = lazy(() => import('@/components/monitor/datasource/DatasourcePage').then(m => ({ default: m.default })));
|
||||||
const LogCenter = lazy(() => import('@/components/monitor/log-center/LogCenter'));
|
const LogCenter = lazy(() => import('@/components/monitor/log-center/LogCenter'));
|
||||||
|
|
||||||
|
|||||||
File renamed without changes.
@@ -0,0 +1,3 @@
|
|||||||
|
// 资源监控 Agent API 聚合出口 // Logan.Li
|
||||||
|
|
||||||
|
export * from './agent';
|
||||||
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,4 @@
|
|||||||
|
// AIOps 智能 API 聚合出口 // Logan.Li
|
||||||
|
|
||||||
|
export * from './assistant';
|
||||||
|
export * from './agent-cli';
|
||||||
File renamed without changes.
@@ -0,0 +1,3 @@
|
|||||||
|
// 资源申请 API 聚合出口 // Logan.Li
|
||||||
|
|
||||||
|
export * from './approval';
|
||||||
File renamed without changes.
@@ -0,0 +1,4 @@
|
|||||||
|
// 安全审计 API 聚合出口 // Logan.Li
|
||||||
|
|
||||||
|
export * from './audit';
|
||||||
|
export * from './terminal';
|
||||||
File renamed without changes.
@@ -1,10 +1,9 @@
|
|||||||
// 用户认证 & LDAP
|
// 用户认证 API — login / profile / password / api-key(自服务)// Logan.Li
|
||||||
// 从 services/api.ts 拆分 — Q3 api.ts 模块化
|
// 用户·角色·LDAP 管理已拆到 system/user.ts
|
||||||
|
|
||||||
import { http, getApiBase, type ListResponse } from '@/utils/request';
|
import { http } from '@/utils/request';
|
||||||
import { useUserStore } from '@/store';
|
|
||||||
|
|
||||||
export const userApi = {
|
export const authApi = {
|
||||||
login: async (username: string, password: string) => {
|
login: async (username: string, password: string) => {
|
||||||
return http.post<{ token: string; expires_in: number; user: unknown; permissions?: string[] }>(
|
return http.post<{ token: string; expires_in: number; user: unknown; permissions?: string[] }>(
|
||||||
'/auth/login',
|
'/auth/login',
|
||||||
@@ -80,81 +79,4 @@ export const userApi = {
|
|||||||
revokeApiAccessKey: async () => {
|
revokeApiAccessKey: async () => {
|
||||||
return http.delete('/user/api-access-key');
|
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<ListResponse>('/admin/users', params);
|
|
||||||
},
|
|
||||||
createUser: async ( data: Record<string, unknown>) => {
|
|
||||||
return http.post('/admin/users', data);
|
|
||||||
},
|
|
||||||
updateUser: async (id: number | string, data: Record<string, unknown>) => {
|
|
||||||
return http.put(`/admin/users/${id}`, data);
|
|
||||||
},
|
|
||||||
deleteUser: async (id: number | string) => {
|
|
||||||
return http.delete(`/admin/users/${id}`);
|
|
||||||
},
|
|
||||||
batchImport: async (data: { users: Record<string, unknown>[]; 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<ListResponse>('/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<ListResponse>('/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<string, unknown>[]) => {
|
|
||||||
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 ====================
|
|
||||||
@@ -4,12 +4,14 @@
|
|||||||
export * from './auth';
|
export * from './auth';
|
||||||
export * from './dashboard';
|
export * from './dashboard';
|
||||||
export * from './server';
|
export * from './server';
|
||||||
|
export * from './cloud';
|
||||||
export * from './kubernetes';
|
export * from './kubernetes';
|
||||||
export * from './deploy';
|
export * from './deploy';
|
||||||
export * from './automation';
|
|
||||||
export * from './monitor';
|
export * from './monitor';
|
||||||
|
export * from './log';
|
||||||
|
export * from './task';
|
||||||
|
export * from './aiops';
|
||||||
export * from './agent';
|
export * from './agent';
|
||||||
export * from './cloud';
|
export * from './approval';
|
||||||
|
export * from './audit';
|
||||||
export * from './system';
|
export * from './system';
|
||||||
export * from './ai';
|
|
||||||
export * from './agentCli';
|
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
// 日志中心 API 聚合出口 // Logan.Li
|
||||||
|
|
||||||
|
export {
|
||||||
|
logCenterApi,
|
||||||
|
type LogDataSource,
|
||||||
|
type LogQueryEntry,
|
||||||
|
type TestConnectionResult,
|
||||||
|
} from './log-center';
|
||||||
File renamed without changes.
@@ -7,5 +7,4 @@ export { traceApi } from './trace';
|
|||||||
export { traceDatasourceApi, type TraceDataSource } from './trace-datasource';
|
export { traceDatasourceApi, type TraceDataSource } from './trace-datasource';
|
||||||
export { dashboardApi } from './grafana';
|
export { dashboardApi } from './grafana';
|
||||||
export { promDatasourceApi, zabbixDatasourceApi } from './datasource';
|
export { promDatasourceApi, zabbixDatasourceApi } from './datasource';
|
||||||
export { logCenterApi, type LogDataSource, type LogQueryEntry } from './log-center';
|
|
||||||
export { metricsApi, snmpApi, prometheusProxyApi, zabbixProxyApi } from './metrics';
|
export { metricsApi, snmpApi, prometheusProxyApi, zabbixProxyApi } from './metrics';
|
||||||
@@ -1,10 +1,3 @@
|
|||||||
// 系统域 API — 子模块 re-export // Logan.Li
|
// 系统域 API — 子模块 re-export // Logan.Li
|
||||||
|
|
||||||
export {
|
export * from './system/index';
|
||||||
auditApi,
|
|
||||||
terminalSessionApi,
|
|
||||||
sessionCommandApi,
|
|
||||||
loginLogApi,
|
|
||||||
approvalWorkflowApi,
|
|
||||||
approvalApi,
|
|
||||||
} from './system/index';
|
|
||||||
@@ -1,5 +1,3 @@
|
|||||||
// 系统域 API 聚合出口 // Logan.Li
|
// 系统管理 API 聚合出口 // Logan.Li
|
||||||
|
|
||||||
export { auditApi } from './audit';
|
export { userApi, ldapApi } from './user';
|
||||||
export { terminalSessionApi, sessionCommandApi, loginLogApi } from './terminal';
|
|
||||||
export { approvalWorkflowApi, approvalApi } from './approval';
|
|
||||||
@@ -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<ListResponse>('/admin/users', params);
|
||||||
|
},
|
||||||
|
createUser: async ( data: Record<string, unknown>) => {
|
||||||
|
return http.post('/admin/users', data);
|
||||||
|
},
|
||||||
|
updateUser: async (id: number | string, data: Record<string, unknown>) => {
|
||||||
|
return http.put(`/admin/users/${id}`, data);
|
||||||
|
},
|
||||||
|
deleteUser: async (id: number | string) => {
|
||||||
|
return http.delete(`/admin/users/${id}`);
|
||||||
|
},
|
||||||
|
batchImport: async (data: { users: Record<string, unknown>[]; 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<ListResponse>('/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<ListResponse>('/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<string, unknown>[]) => {
|
||||||
|
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);
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -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<ListResponse>('/cron-jobs', params);
|
||||||
|
},
|
||||||
|
getJob: async (id: number | string) => {
|
||||||
|
return http.get(`/cron-jobs/${id}`);
|
||||||
|
},
|
||||||
|
createJob: async ( data: Record<string, unknown>) => {
|
||||||
|
return http.post('/cron-jobs', data);
|
||||||
|
},
|
||||||
|
updateJob: async (id: number | string, data: Record<string, unknown>) => {
|
||||||
|
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 });
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
// 作业任务 API 聚合出口 // Logan.Li
|
||||||
|
|
||||||
|
export * from './cron-job';
|
||||||
|
export * from './script';
|
||||||
|
export * from './remote-exec';
|
||||||
@@ -1,71 +1,15 @@
|
|||||||
// 自动化运维 (定时任务/脚本/Ansible)
|
// 作业任务 — 远程执行 API(/ansible + /task-executions)// Logan.Li
|
||||||
// 从 services/api.ts 拆分 — Q3 api.ts 模块化
|
|
||||||
|
|
||||||
import { http, type ListResponse } from '@/utils/request';
|
import { http, type ListResponse } from '@/utils/request';
|
||||||
|
|
||||||
export const cronJobApi = {
|
// 任务执行记录 API
|
||||||
getJobs: async (params?: { page?: number; page_size?: number }) => {
|
|
||||||
return http.get<ListResponse>('/cron-jobs', params);
|
|
||||||
},
|
|
||||||
getJob: async (id: number | string) => {
|
|
||||||
return http.get(`/cron-jobs/${id}`);
|
|
||||||
},
|
|
||||||
createJob: async ( data: Record<string, unknown>) => {
|
|
||||||
return http.post('/cron-jobs', data);
|
|
||||||
},
|
|
||||||
updateJob: async (id: number | string, data: Record<string, unknown>) => {
|
|
||||||
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<ListResponse>('/scripts', params);
|
|
||||||
},
|
|
||||||
getScript: async (id: number | string) => {
|
|
||||||
return http.get(`/scripts/${id}`);
|
|
||||||
},
|
|
||||||
createScript: async ( data: Record<string, unknown>) => {
|
|
||||||
return http.post('/scripts', data);
|
|
||||||
},
|
|
||||||
updateScript: async (id: number | string, data: Record<string, unknown>) => {
|
|
||||||
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 ====================
|
|
||||||
|
|
||||||
export const taskExecutionApi = {
|
export const taskExecutionApi = {
|
||||||
getExecutions: async (params?: { task_type?: string; task_id?: string; page?: number; page_size?: number }) => {
|
getExecutions: async (params?: { task_type?: string; task_id?: string; page?: number; page_size?: number }) => {
|
||||||
return http.get<ListResponse>('/task-executions', params);
|
return http.get<ListResponse>('/task-executions', params);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// ==================== 审批流程 API ====================
|
// Ansible / 远程执行 API
|
||||||
|
|
||||||
export const ansibleApi = {
|
export const ansibleApi = {
|
||||||
// Playbook 管理
|
// Playbook 管理
|
||||||
getPlaybooks: async (params?: { page?: number; page_size?: number; keyword?: string }) => {
|
getPlaybooks: async (params?: { page?: number; page_size?: number; keyword?: string }) => {
|
||||||
@@ -119,6 +63,3 @@ export const ansibleApi = {
|
|||||||
return http.delete(`/ansible/inventories/${id}`);
|
return http.delete(`/ansible/inventories/${id}`);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// ==================== 告警中心 API(基于 /alerts 真实路由) ====================
|
|
||||||
// 说明:alertCenterApi 与 alertApi 共用同一套后端 /alerts 路由,此处独立封装以便告警中心页使用
|
|
||||||
@@ -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<ListResponse>('/scripts', params);
|
||||||
|
},
|
||||||
|
getScript: async (id: number | string) => {
|
||||||
|
return http.get(`/scripts/${id}`);
|
||||||
|
},
|
||||||
|
createScript: async ( data: Record<string, unknown>) => {
|
||||||
|
return http.post('/scripts', data);
|
||||||
|
},
|
||||||
|
updateScript: async (id: number | string, data: Record<string, unknown>) => {
|
||||||
|
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`);
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -3,7 +3,7 @@ import { useNavigate } from 'react-router-dom';
|
|||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { User, Lock, Palette, Check, Loader2, AlertCircle, Eye, EyeOff, Languages } from 'lucide-react';
|
import { User, Lock, Palette, Check, Loader2, AlertCircle, Eye, EyeOff, Languages } from 'lucide-react';
|
||||||
import { useUserStore, useLanguageStore } from '@/store';
|
import { useUserStore, useLanguageStore } from '@/store';
|
||||||
import { userApi } from '@/api';
|
import { authApi } from '@/api';
|
||||||
import { useTheme, THEME_OPTIONS } from '@/hooks/useTheme';
|
import { useTheme, THEME_OPTIONS } from '@/hooks/useTheme';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
import { SUPPORTED_LANGUAGES, type AppLanguage } from '@/i18n';
|
import { SUPPORTED_LANGUAGES, type AppLanguage } from '@/i18n';
|
||||||
@@ -89,7 +89,7 @@ export function Login() {
|
|||||||
setError('');
|
setError('');
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
try {
|
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);
|
useUserStore.getState().login(result.user, result.token, result.permissions ?? null);
|
||||||
localStorage.setItem('token', result.token);
|
localStorage.setItem('token', result.token);
|
||||||
navigate('/', { replace: true });
|
navigate('/', { replace: true });
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { useEffect, useMemo, useState } from 'react';
|
|||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import { Loader2 } from 'lucide-react';
|
import { Loader2 } from 'lucide-react';
|
||||||
import { CodeSnippetBlock } from '@/components/ui/code-snippet-block';
|
import { CodeSnippetBlock } from '@/components/ui/code-snippet-block';
|
||||||
import { userApi } from '@/api';
|
import { authApi } from '@/api';
|
||||||
import { getPublicApiBase } from '@/utils/request';
|
import { getPublicApiBase } from '@/utils/request';
|
||||||
import { getSessionApiAccessKey } from '@/utils/storage';
|
import { getSessionApiAccessKey } from '@/utils/storage';
|
||||||
|
|
||||||
@@ -37,7 +37,7 @@ export function CICDWebhookContent({
|
|||||||
const cached = getSessionApiAccessKey();
|
const cached = getSessionApiAccessKey();
|
||||||
if (cached) setAccessKey(cached);
|
if (cached) setAccessKey(cached);
|
||||||
try {
|
try {
|
||||||
const meta = await userApi.getApiAccessKey();
|
const meta = await authApi.getApiAccessKey();
|
||||||
if (!cancelled) {
|
if (!cancelled) {
|
||||||
setHasKey(!!meta?.has_token);
|
setHasKey(!!meta?.has_token);
|
||||||
setKeyExpired(!!meta?.expired);
|
setKeyExpired(!!meta?.expired);
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { useThemeStore, useUserStore } from '@/store';
|
|||||||
import { Sidebar } from './Sidebar';
|
import { Sidebar } from './Sidebar';
|
||||||
import { Header } from './Header';
|
import { Header } from './Header';
|
||||||
import { Breadcrumb } from './Breadcrumb';
|
import { Breadcrumb } from './Breadcrumb';
|
||||||
import { userApi } from '@/api';
|
import { authApi } from '@/api';
|
||||||
import type { JsonData } from '@/types/common';
|
import type { JsonData } from '@/types/common';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -30,7 +30,7 @@ export function MainLayout() {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!token || permissions !== null) return;
|
if (!token || permissions !== null) return;
|
||||||
let cancelled = false;
|
let cancelled = false;
|
||||||
userApi.getMyPermissions()
|
authApi.getMyPermissions()
|
||||||
.then((data: JsonData) => {
|
.then((data: JsonData) => {
|
||||||
if (cancelled) return;
|
if (cancelled) return;
|
||||||
const perms: string[] = data?.permissions ?? [];
|
const perms: string[] = data?.permissions ?? [];
|
||||||
|
|||||||
@@ -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: [
|
children: [
|
||||||
{ id: 'cronjobs', name: '定时任务', labelKey: 'menu.cronJobs', icon: PlayCircle, path: '/cronjobs', permission: 'auto:cron' },
|
{ 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' },
|
{ id: 'scripts', name: '脚本库', labelKey: 'menu.scripts', icon: FileCode, path: '/scripts', permission: 'auto:script' },
|
||||||
|
|||||||
@@ -13,8 +13,7 @@ import {
|
|||||||
DialogTitle,
|
DialogTitle,
|
||||||
} from '@/components/ui/dialog';
|
} from '@/components/ui/dialog';
|
||||||
import { Loader2 } from 'lucide-react';
|
import { Loader2 } from 'lucide-react';
|
||||||
import { alertApi } from '@/api';
|
import { alertApi, logCenterApi, type LogDataSource } from '@/api';
|
||||||
import { logCenterApi, type LogDataSource } from '@/api/monitor/log-center';
|
|
||||||
import { parseChannels, getChannelIcon, getChannelTypeLabel } from './alertShared';
|
import { parseChannels, getChannelIcon, getChannelTypeLabel } from './alertShared';
|
||||||
import type { JsonData } from '@/types/common';
|
import type { JsonData } from '@/types/common';
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import {
|
|||||||
} from '@/components/ui/select';
|
} from '@/components/ui/select';
|
||||||
import { Loader2, Plug, RefreshCw } from 'lucide-react';
|
import { Loader2, Plug, RefreshCw } from 'lucide-react';
|
||||||
import { useToast } from '@/hooks/use-toast';
|
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';
|
import type { LogEngine } from './log-center-types';
|
||||||
|
|
||||||
export function LogDatasourceDialog({
|
export function LogDatasourceDialog({
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import {
|
|||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
import { useToast } from '@/hooks/use-toast';
|
import { useToast } from '@/hooks/use-toast';
|
||||||
import { useConfirm } from '@/components/ui/confirm-dialog';
|
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 { LogDatasourceDialog } from './LogDatasourceDialog';
|
||||||
import type { LogEngine } from './log-center-types';
|
import type { LogEngine } from './log-center-types';
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import { LogClusterPanel } from './LogClusterPanel';
|
|||||||
import { SaveQueryDialog, SaveAlertDialog } from './SaveQueryDialog';
|
import { SaveQueryDialog, SaveAlertDialog } from './SaveQueryDialog';
|
||||||
import { QueryHistoryPanel } from './QueryHistoryPanel';
|
import { QueryHistoryPanel } from './QueryHistoryPanel';
|
||||||
import { LogAlertFromQueryDialog } from './LogAlertFromQueryDialog';
|
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 type { LogEngine, TimeRange, ResultTab, ViewMode, LogEntry, StatTable, LogCluster, QueryHistoryItem } from './types-v3';
|
||||||
import { ENGINE_META, buildStatTableFromEntries, buildClustersFromEntries, extractFields, generateHistogramData, historyStorage } from './types-v3';
|
import { ENGINE_META, buildStatTableFromEntries, buildClustersFromEntries, extractFields, generateHistogramData, historyStorage } from './types-v3';
|
||||||
import { useToast } from '@/hooks/use-toast';
|
import { useToast } from '@/hooks/use-toast';
|
||||||
@@ -280,8 +280,13 @@ export function UnifiedQueryPanel({ engine, onRuleCreated }: Props) {
|
|||||||
<span className="text-[11px] font-semibold" style={{ color: badge.dotColor }}>{badge.label}</span>
|
<span className="text-[11px] font-semibold" style={{ color: badge.dotColor }}>{badge.label}</span>
|
||||||
</div>
|
</div>
|
||||||
<SyntaxHighlightInput value={query} onChange={setQuery} engine={effEngine} placeholder={meta.queryPlaceholder} />
|
<SyntaxHighlightInput value={query} onChange={setQuery} engine={effEngine} placeholder={meta.queryPlaceholder} />
|
||||||
|
<button onClick={handleRun} disabled={loading || !currentSource} className="h-10 px-4 rounded text-xs font-medium text-white flex items-center gap-1.5 flex-shrink-0 transition-opacity hover:opacity-90" style={{ background: '#22c55e' }}>
|
||||||
|
{loading ? <Loader2 className="h-4 w-4 animate-spin" /> : <Play className="h-4 w-4" />} 查询
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
{/* 次级控件行(时间 / 数据源 / 索引 / 上限 / 另存为 / 历史)// Logan.Li */}
|
||||||
|
<div className="flex items-center gap-2 flex-wrap">
|
||||||
<TimeRangePicker value={timeRange} onChange={setTimeRange} />
|
<TimeRangePicker value={timeRange} onChange={setTimeRange} />
|
||||||
|
|
||||||
<select value={dsId} onChange={e => setDsId(e.target.value)} className="h-10 px-2 text-xs rounded flex-shrink-0" style={{ background: 'var(--dg-bg-tertiary)', border: '1px solid var(--dg-border)', color: 'var(--dg-text-primary)' }}>
|
<select value={dsId} onChange={e => setDsId(e.target.value)} className="h-10 px-2 text-xs rounded flex-shrink-0" style={{ background: 'var(--dg-bg-tertiary)', border: '1px solid var(--dg-border)', color: 'var(--dg-text-primary)' }}>
|
||||||
@@ -316,10 +321,6 @@ export function UnifiedQueryPanel({ engine, onRuleCreated }: Props) {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button onClick={handleRun} disabled={loading || !currentSource} className="h-10 px-4 rounded text-xs font-medium text-white flex items-center gap-1.5 flex-shrink-0 transition-opacity hover:opacity-90" style={{ background: '#22c55e' }}>
|
|
||||||
{loading ? <Loader2 className="h-4 w-4 animate-spin" /> : <Play className="h-4 w-4" />} 查询
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<div className="relative flex-shrink-0">
|
<div className="relative flex-shrink-0">
|
||||||
<button onClick={() => setSaveMenuOpen(!saveMenuOpen)} className="h-10 px-3 rounded text-xs flex items-center gap-1" style={{ border: '1px solid var(--dg-border)', color: 'var(--dg-text-secondary)', background: 'var(--dg-bg-tertiary)' }}>
|
<button onClick={() => setSaveMenuOpen(!saveMenuOpen)} className="h-10 px-3 rounded text-xs flex items-center gap-1" style={{ border: '1px solid var(--dg-border)', color: 'var(--dg-text-secondary)', background: 'var(--dg-bg-tertiary)' }}>
|
||||||
<Save className="h-3.5 w-3.5" /> 另存为 <ChevronDown className="h-3 w-3" />
|
<Save className="h-3.5 w-3.5" /> 另存为 <ChevronDown className="h-3 w-3" />
|
||||||
|
|||||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -14,7 +14,7 @@ import {
|
|||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
import { useToast } from '@/hooks/use-toast';
|
import { useToast } from '@/hooks/use-toast';
|
||||||
import { useConfirm } from '@/components/ui/confirm-dialog';
|
import { useConfirm } from '@/components/ui/confirm-dialog';
|
||||||
import { userApi } from '@/api';
|
import { authApi } from '@/api';
|
||||||
import { getPublicApiBase } from '@/utils/request';
|
import { getPublicApiBase } from '@/utils/request';
|
||||||
import { getSessionApiAccessKey, setSessionApiAccessKey } from '@/utils/storage';
|
import { getSessionApiAccessKey, setSessionApiAccessKey } from '@/utils/storage';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
@@ -93,7 +93,7 @@ export function ApiAccessKeySection() {
|
|||||||
try {
|
try {
|
||||||
const cached = getSessionApiAccessKey();
|
const cached = getSessionApiAccessKey();
|
||||||
if (cached) setPlainToken(cached);
|
if (cached) setPlainToken(cached);
|
||||||
const meta = await userApi.getApiAccessKey().catch(() => ({ has_token: false }));
|
const meta = await authApi.getApiAccessKey().catch(() => ({ has_token: false }));
|
||||||
setKeyMeta(meta);
|
setKeyMeta(meta);
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
@@ -130,7 +130,7 @@ export function ApiAccessKeySection() {
|
|||||||
if (formMode === 'edit') {
|
if (formMode === 'edit') {
|
||||||
setActionLoading(true);
|
setActionLoading(true);
|
||||||
try {
|
try {
|
||||||
const res = await userApi.updateApiAccessKey({
|
const res = await authApi.updateApiAccessKey({
|
||||||
description: formDescription,
|
description: formDescription,
|
||||||
expires_at: formExpiresAt,
|
expires_at: formExpiresAt,
|
||||||
});
|
});
|
||||||
@@ -156,7 +156,7 @@ export function ApiAccessKeySection() {
|
|||||||
|
|
||||||
setActionLoading(true);
|
setActionLoading(true);
|
||||||
try {
|
try {
|
||||||
const res = await userApi.regenerateApiAccessKey({
|
const res = await authApi.regenerateApiAccessKey({
|
||||||
description: formDescription,
|
description: formDescription,
|
||||||
expires_at: formExpiresAt,
|
expires_at: formExpiresAt,
|
||||||
});
|
});
|
||||||
@@ -195,7 +195,7 @@ export function ApiAccessKeySection() {
|
|||||||
if (!ok) return;
|
if (!ok) return;
|
||||||
setActionLoading(true);
|
setActionLoading(true);
|
||||||
try {
|
try {
|
||||||
await userApi.revokeApiAccessKey();
|
await authApi.revokeApiAccessKey();
|
||||||
setPlainToken('');
|
setPlainToken('');
|
||||||
setSessionApiAccessKey('');
|
setSessionApiAccessKey('');
|
||||||
setKeyMeta({ has_token: false });
|
setKeyMeta({ has_token: false });
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { Label } from '@/components/ui/label';
|
|||||||
import { Badge } from '@/components/ui/badge';
|
import { Badge } from '@/components/ui/badge';
|
||||||
import { User, Shield, Loader2 } from 'lucide-react';
|
import { User, Shield, Loader2 } from 'lucide-react';
|
||||||
import { useToast } from '@/hooks/use-toast';
|
import { useToast } from '@/hooks/use-toast';
|
||||||
import { userApi } from '@/api';
|
import { authApi } from '@/api';
|
||||||
import { useUserStore } from '@/store';
|
import { useUserStore } from '@/store';
|
||||||
import { ApiAccessKeySection } from './ApiAccessKeySection';
|
import { ApiAccessKeySection } from './ApiAccessKeySection';
|
||||||
|
|
||||||
@@ -25,7 +25,7 @@ export default function ProfilePage() {
|
|||||||
const load = useCallback(async () => {
|
const load = useCallback(async () => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
try {
|
try {
|
||||||
const p = await userApi.getProfile();
|
const p = await authApi.getProfile();
|
||||||
setProfile(p);
|
setProfile(p);
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
@@ -41,7 +41,7 @@ export default function ProfilePage() {
|
|||||||
if (!oldPwd || newPwd.length < 6) return;
|
if (!oldPwd || newPwd.length < 6) return;
|
||||||
setPwdSaving(true);
|
setPwdSaving(true);
|
||||||
try {
|
try {
|
||||||
await userApi.changePassword({ old_password: oldPwd, new_password: newPwd });
|
await authApi.changePassword({ old_password: oldPwd, new_password: newPwd });
|
||||||
toast({ title: '密码已修改' });
|
toast({ title: '密码已修改' });
|
||||||
setOldPwd('');
|
setOldPwd('');
|
||||||
setNewPwd('');
|
setNewPwd('');
|
||||||
|
|||||||
@@ -115,7 +115,7 @@
|
|||||||
"esQuery": "ES Query",
|
"esQuery": "ES Query",
|
||||||
"logLibrary": "Log Library",
|
"logLibrary": "Log Library",
|
||||||
"logAlerts": "Log Alerts",
|
"logAlerts": "Log Alerts",
|
||||||
"automation": "Automation",
|
"automation": "Task",
|
||||||
"cronJobs": "Cron Jobs",
|
"cronJobs": "Cron Jobs",
|
||||||
"scripts": "Scripts",
|
"scripts": "Scripts",
|
||||||
"remoteExec": "Remote Exec",
|
"remoteExec": "Remote Exec",
|
||||||
|
|||||||
@@ -115,7 +115,7 @@
|
|||||||
"esQuery": "ES查询",
|
"esQuery": "ES查询",
|
||||||
"logLibrary": "日志库",
|
"logLibrary": "日志库",
|
||||||
"logAlerts": "日志告警",
|
"logAlerts": "日志告警",
|
||||||
"automation": "自动化运维",
|
"automation": "作业任务",
|
||||||
"cronJobs": "定时任务",
|
"cronJobs": "定时任务",
|
||||||
"scripts": "脚本库",
|
"scripts": "脚本库",
|
||||||
"remoteExec": "远程执行",
|
"remoteExec": "远程执行",
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
// 安全审计 — 内容由侧边栏路由分发 | v2 (0603)
|
|
||||||
import { useLocation } from 'react-router-dom';
|
|
||||||
import { TerminalAuditTab } from './TerminalAuditTab';
|
|
||||||
import { AuditOperationsTab } from './AuditOperationsTab';
|
|
||||||
import { LoginLogsTab } from './LoginLogsTab';
|
|
||||||
|
|
||||||
export function AuditPage() {
|
|
||||||
const { pathname } = useLocation();
|
|
||||||
console.debug('[AuditPage v2] pathname:', pathname);
|
|
||||||
|
|
||||||
if (pathname.includes('/audit/terminal')) return <TerminalAuditTab />;
|
|
||||||
if (pathname.includes('/audit/operations')) return <AuditOperationsTab />;
|
|
||||||
if (pathname.includes('/audit/login-logs')) return <LoginLogsTab />;
|
|
||||||
|
|
||||||
return <TerminalAuditTab />;
|
|
||||||
}
|
|
||||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Reference in new issue
Block a user