refactor(frontend): services/api 迁至 src/api,http 迁至 utils/request

对齐 Vue 后台惯例:
- src/api/          域 API(原 services/api)
- src/utils/request.ts  HTTP 封装(原 services/http.ts)
- src/utils/export.ts  客户端导出工具
- src/utils/index.ts   工具统一出口

全局导入改为 @/api 与 @/utils/request,tsc + build 通过。
This commit is contained in:
Logan.Li committed 2026-06-26 00:09:07 +08:00
1 parent 9bf35b369c
commit d19a03d427
145 files changed
+156 -142

No files matched your search

+38
View File
@@ -0,0 +1,38 @@
// Agent 管理
// 从 services/api.ts 拆分 — Q3 api.ts 模块化
import { http, type ListResponse } from '@/utils/request';
export const agentApi = {
getLatest: () => http.get('/agent/latest'),
getHistory: (hostname: string, hours = 1) => http.get(`/agent/history/${hostname}?hours=${hours}`),
createTask: (data: { hostname: string; type: string; command: string; timeout?: number }) => http.post('/agent/tasks', data),
listTasks: (params?: Record<string, string>) => http.get('/agent/tasks', params),
// 直连 SSH 执行命令(即时返回)
execCommand: (data: { hostname: string; command: string; timeout?: number }) => http.post('/agent/exec', data),
// 聚合查询
getAggregate: (params: { hostname: string; metric: string; interval: string; from?: string; to?: string }) => http.get('/agent/aggregate', params),
// 触发聚合
aggregate: (data: { hostname: string; metric: string }) => http.post('/agent/aggregate', data),
listRules: () => http.get('/agent/rules'),
createRule: ( data: any) => http.post('/agent/rules', data),
updateRule: (id: number, data: any) => http.put(`/agent/rules/${id}`, data),
deleteRule: (id: number) => http.delete(`/agent/rules/${id}`),
quickSetup: (type?: string) => http.post('/agent/rules/quick-setup', { type: type || 'ecs' }),
// Agent 安装/卸载
uninstallAgent: (data: { hostname?: string; server_id?: number }) => http.post('/agent/uninstall', data),
batchUninstall: (serverIds: number[]) => http.post('/agent/batch-uninstall', { server_ids: serverIds }),
batchUpgrade: (serverIds: number[]) => http.post('/agent/batch-upgrade', { server_ids: serverIds }),
listAlerts: (params?: Record<string, string>) => http.get('/agent/alerts', params),
resolveAlert: (id: number) => http.post(`/agent/alerts/${id}/resolve`),
// 健康探针
getHealthProbes: (params?: Record<string, string>) => http.get('/agent/health-probes', params),
createHealthProbe: ( data: any) => http.post('/agent/health-probes', data),
updateHealthProbe: (id: number, data: any) => http.put(`/agent/health-probes/${id}`, data),
deleteHealthProbe: (id: number) => http.delete(`/agent/health-probes/${id}`),
// 端口策略
getPortPolicy: (hostname: string) => http.get(`/agent/port-policies/${hostname}`),
savePortPolicy: (hostname: string, data: { port_filter_mode: string; port_whitelist: number[] }) => http.put(`/agent/port-policies/${hostname}`, data),
};
// ==================== 发布系统 API(仓库/镜像仓库认证) ====================
+127
View File
@@ -0,0 +1,127 @@
// AI 智能运维 (LLM 对话/告警分析/容量预测)
// 从 services/api.ts 拆分 — Q3 api.ts 模块化
import { http } from '@/utils/request';
import { useUserStore } from '@/store';
export interface LLMConfigData {
configured?: boolean;
provider: string;
model: string;
api_key: string;
endpoint: string;
temperature: number;
max_tokens: number;
system_prompt: string;
enabled: boolean;
}
export interface ChatResult {
content: string;
model: string;
tokens_used: number;
}
export interface ChatHistoryItem {
id: number;
user_id: number;
session_id: string;
role: 'user' | 'assistant';
content: string;
model?: string;
created_at: string;
}
export const aiApi = {
// 获取 LLM 配置(API Key 已脱敏)
getConfig: () => http.get<LLMConfigData>('/aiops/llm-config'),
// 保存 LLM 配置(api_key 若为脱敏值则后端保留原值)
saveConfig: (data: LLMConfigData) => http.put<LLMConfigData>('/aiops/llm-config', data),
// 测试 LLM 连接(发送 ping)
testConnection: () => http.post('/aiops/llm-config/test'),
// AI 对话(messages 含历史 + 当前用户消息,session_id 区分多轮对话)
chat: (messages: { role: 'user' | 'assistant'; content: string }[], sessionId?: string) =>
http.post<ChatResult>('/aiops/chat', { messages, session_id: sessionId || '' }),
// AI 流式对话(SSE)。逐块回调 onChunk,返回完整内容。错误抛出 Error。
// 使用裸 fetch 绕过 http.ts(后者会 await json() 一次性消费) // Logan.Li
chatStream: async (
messages: { role: 'user' | 'assistant'; content: string }[],
onChunk: (delta: string) => void,
signal?: AbortSignal,
sessionId?: string,
): Promise<string> => {
const token = useUserStore.getState().token;
const res = await fetch('/api/v1/aiops/chat/stream', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
...(token ? { Authorization: `Bearer ${token}` } : {}),
},
body: JSON.stringify({ messages, session_id: sessionId || '' }),
signal,
});
if (res.status === 401) {
useUserStore.getState().logout();
window.location.href = '/login';
throw new Error('登录已过期,请重新登录');
}
if (!res.body) throw new Error('流式响应不可用');
const reader = res.body.getReader();
const decoder = new TextDecoder('utf-8');
let buffer = '';
let fullContent = '';
for (;;) {
const { done, value } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
// SSE 事件之间以 \n\n 分隔
const events = buffer.split('\n\n');
buffer = events.pop() ?? '';
for (const evt of events) {
const lines = evt.split('\n');
let eventType = 'message';
let dataLines: string[] = [];
for (const ln of lines) {
if (ln.startsWith('event:')) eventType = ln.slice(6).trim();
else if (ln.startsWith('data:')) dataLines.push(ln.slice(5).trim());
}
const data = dataLines.join('');
if (!data) continue;
if (eventType === 'error') {
// {code, message}
try {
const obj = JSON.parse(data);
throw new Error(obj.message || 'LLM 流式响应错误');
} catch (parseErr) {
if (parseErr instanceof Error && parseErr.message) throw parseErr;
throw new Error('LLM 流式响应错误');
}
}
if (eventType === 'done') {
// 服务端结束(可能含 model 字段)
continue;
}
// message:data 是 {"content":"..."}
try {
const obj = JSON.parse(data);
if (typeof obj.content === 'string') {
fullContent += obj.content;
onChunk(obj.content);
}
} catch {
// 非 JSON 数据忽略(如 [DONE] 或注释)
}
}
}
return fullContent;
},
// 获取当前用户对话历史(按 session_id 过滤,默认最新 session)
getHistory: (sessionId?: string) => {
const params = sessionId ? `?session_id=${encodeURIComponent(sessionId)}` : '';
return http.get<{ list: ChatHistoryItem[]; total: number }>(`/aiops/chat-history${params}`);
},
// 清空当前用户对话历史
clearHistory: () => http.delete('/aiops/chat-history'),
};
// ==================== 凭据管理 API(SSH密钥/API Token/密码) ==================== // Logan.Li
+103
View File
@@ -0,0 +1,103 @@
// 用户认证 & LDAP
// 从 services/api.ts 拆分 — Q3 api.ts 模块化
import { http, getApiBase, type ListResponse } from '@/utils/request';
import { useUserStore } from '@/store';
export const userApi = {
login: async (username: string, password: string) => {
return http.post<{ token: string; expires_in: number; user: unknown; permissions?: string[] }>(
'/auth/login',
{ username, password }
);
},
getMyPermissions: async () => {
return http.get<{ permissions: string[]; is_admin: boolean }>('/user/permissions');
},
register: async (data: { username: string; password: string; nickname?: string; email?: string }) => {
return http.post('/auth/register', data);
},
getProfile: async () => {
return http.get('/user/profile');
},
updateProfile: async ( data: any) => {
return http.put('/user/profile', data);
},
changePassword: async (data: { old_password: string; new_password: string }) => {
return http.put('/user/password', data);
},
getUsers: async (params?: { page?: number; page_size?: number; keyword?: string }) => {
return http.get<ListResponse>('/admin/users', params);
},
createUser: async ( data: any) => {
return http.post('/admin/users', data);
},
updateUser: async (id: number | string, data: any) => {
return http.put(`/admin/users/${id}`, data);
},
deleteUser: async (id: number | string) => {
return http.delete(`/admin/users/${id}`);
},
batchImport: async (data: { users: any[]; 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: any) => {
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: any[]) => {
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 ====================
+124
View File
@@ -0,0 +1,124 @@
// 自动化运维 (定时任务/脚本/Ansible)
// 从 services/api.ts 拆分 — Q3 api.ts 模块化
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: any) => {
return http.post('/cron-jobs', data);
},
updateJob: async (id: number | string, data: any) => {
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: any) => {
return http.post('/scripts', data);
},
updateScript: async (id: number | string, data: any) => {
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 = {
getExecutions: async (params?: { task_type?: string; task_id?: string; page?: number; page_size?: number }) => {
return http.get<ListResponse>('/task-executions', params);
},
};
// ==================== 审批流程 API ====================
export const ansibleApi = {
// Playbook 管理
getPlaybooks: async (params?: { page?: number; page_size?: number; keyword?: string }) => {
return http.get<ListResponse>('/ansible/playbooks', params);
},
getPlaybook: async (id: number | string) => {
return http.get(`/ansible/playbooks/${id}`);
},
createPlaybook: async ( data: any) => {
return http.post('/ansible/playbooks', data);
},
updatePlaybook: async (id: number | string, data: any) => {
return http.put(`/ansible/playbooks/${id}`, data);
},
deletePlaybook: async (id: number | string) => {
return http.delete(`/ansible/playbooks/${id}`);
},
// 批量删除 Playbook // Logan.Li
batchDeletePlaybooks: async (ids: number[]) => {
return http.delete('/ansible/playbooks/batch-delete', { ids });
},
executePlaybook: async (id: number | string, targetHosts?: string[]) => {
return http.post(`/ansible/playbooks/${id}/execute`, targetHosts ? { target_hosts: targetHosts } : undefined);
},
// 克隆 Playbook 为自定义模板 // Logan.Li
clonePlaybook: async (id: number | string, name?: string) => {
return http.post(`/ansible/playbooks/${id}/clone`, name ? { name } : undefined);
},
// 主机匹配预览 // Logan.Li
matchHosts: async (params: { pattern?: string; match_type?: string; page?: number; page_size?: number }) => {
return http.get<ListResponse>('/ansible/match-hosts', params);
},
// 任务执行记录
getJobs: async (params?: { page?: number; page_size?: number; status?: string }) => {
return http.get<ListResponse>('/ansible/jobs', params);
},
getJob: async (id: number | string) => {
return http.get(`/ansible/jobs/${id}`);
},
// 清单(Inventory)管理
getInventories: async (params?: { page?: number; page_size?: number; keyword?: string }) => {
return http.get<ListResponse>('/ansible/inventories', params);
},
createInventory: async ( data: any) => {
return http.post('/ansible/inventories', data);
},
updateInventory: async (id: number | string, data: any) => {
return http.put(`/ansible/inventories/${id}`, data);
},
deleteInventory: async (id: number | string) => {
return http.delete(`/ansible/inventories/${id}`);
},
};
// ==================== 告警中心 API(基于 /alerts 真实路由) ====================
// 说明:alertCenterApi 与 alertApi 共用同一套后端 /alerts 路由,此处独立封装以便告警中心页使用
+106
View File
@@ -0,0 +1,106 @@
// 云账号/平台/账单
// 从 services/api.ts 拆分 — Q3 api.ts 模块化
import { http, type ListResponse } from '@/utils/request';
export const cloudApi = {
getAccounts: async () => {
return http.get<ListResponse>('/cloud-accounts');
},
createAccount: async ( data: any) => {
return http.post('/cloud-accounts', data);
},
updateAccount: async (id: number | string, data: any) => {
return http.put(`/cloud-accounts/${id}`, data);
},
deleteAccount: async (id: number | string) => {
return http.delete(`/cloud-accounts/${id}`);
},
// ==================== 云同步 API ====================
// 同步云账号的区域列表到本地
syncRegions: async (id: number | string) => {
return http.post(`/cloud-accounts/${id}/sync-regions`);
},
// 获取云账号的区域列表
getAccountRegions: async (id: number | string) => {
return http.get<ListResponse>(`/cloud-accounts/${id}/regions`);
},
// 发现指定区域的云主机实例
discoverInstances: async (id: number | string, regions: string[]) => {
return http.post<{ list: any[]; total: number; errors: string[] }>(`/cloud-accounts/${id}/discover-instances`, { regions });
},
// 导入选中的云主机实例为本地服务器
importInstances: async (id: number | string, instances: any[], opts?: { default_port?: number; credential_id?: number }) => {
return http.post<{ imported: number; skipped: number }>(`/cloud-accounts/${id}/import-instances`, { instances, ...opts });
},
getDomains: async (params?: { page?: number; page_size?: number; keyword?: string }) => {
return http.get<ListResponse>('/domains', params);
},
createDomain: async ( data: any) => {
return http.post('/domains', data);
},
updateDomain: async (id: number | string, data: any) => {
return http.put(`/domains/${id}`, data);
},
deleteDomain: async (id: number | string) => {
return http.delete(`/domains/${id}`);
},
};
// ==================== 云平台 API ====================
export const platformApi = {
list: async () => {
return http.get<ListResponse>('/platforms');
},
create: async ( data: any) => {
return http.post('/platforms', data);
},
update: async (id: number | string, data: any) => {
return http.put(`/platforms/${id}`, data);
},
delete: async (id: number | string) => {
return http.delete(`/platforms/${id}`);
},
};
// ==================== 云账单 API ====================
export const billingApi = {
getStats: async () => {
return http.get('/cloud-billings/stats');
},
list: async (params?: { provider?: string; start_date?: string; end_date?: string; page?: number; page_size?: number }) => {
return http.get<ListResponse>('/cloud-billings', params);
},
create: async ( data: any) => {
return http.post('/cloud-billings', data);
},
batchCreate: async ( records: any[]) => {
return http.post('/cloud-billings/batch', { records });
},
remove: async (id: number | string) => {
return http.delete(`/cloud-billings/${id}`);
},
getProviders: async () => {
return http.get('/cloud-billings/providers');
},
// 预警规则
listAlertRules: async () => {
return http.get<ListResponse>('/billing-alerts');
},
createAlertRule: async ( data: any) => {
return http.post('/billing-alerts', data);
},
updateAlertRule: async (id: number | string, data: any) => {
return http.put(`/billing-alerts/${id}`, data);
},
deleteAlertRule: async (id: number | string) => {
return http.delete(`/billing-alerts/${id}`);
},
toggleAlertRule: async (id: number | string) => {
return http.post(`/billing-alerts/${id}/toggle`);
},
};
// ==================== Agent 监控 API ====================
+21
View File
@@ -0,0 +1,21 @@
// Dashboard 统计数据
// 从 services/api.ts 拆分 — Q3 api.ts 模块化
import { http } from '@/utils/request';
export const dashboardStatsApi = {
getStats: async () => {
return http.get('/dashboard/stats');
},
getAlerts: async (limit?: number) => {
return http.get('/dashboard/recent-alerts', limit ? { limit } : undefined);
},
getReleases: async (limit?: number) => {
return http.get('/dashboard/recent-releases', limit ? { limit } : undefined);
},
getMetrics: async (hours?: number) => {
return http.get('/dashboard/metrics', hours ? { hours } : undefined);
},
};
// ==================== 服务器管理 API ====================
+154
View File
@@ -0,0 +1,154 @@
// CI/CD 流水线/发布配置/凭证
// 从 services/api.ts 拆分 — Q3 api.ts 模块化
import { http, type ListResponse } from '@/utils/request';
export const pipelineApi = {
getPipelines: async (params?: { page?: number; page_size?: number }) => {
return http.get<ListResponse>('/pipelines', params);
},
getPipelineDetail: async (id: number | string) => {
return http.get(`/pipelines/${id}`);
},
createPipeline: async ( data: any) => {
return http.post('/pipelines', data);
},
updatePipeline: async (id: number | string, data: any) => {
return http.put(`/pipelines/${id}`, data);
},
deletePipeline: async (id: number | string) => {
return http.delete(`/pipelines/${id}`);
},
triggerPipeline: async (id: number | string) => {
return http.post(`/pipelines/${id}/trigger`);
},
getRuns: async (id: number | string) => {
return http.get(`/pipelines/${id}/runs`);
},
// 运行控制
stopRun: async (pipelineId: number | string, runId: number | string) => {
return http.post(`/pipelines/${pipelineId}/runs/${runId}/stop`);
},
getRunLog: async (pipelineId: number | string, runId: number | string) => {
return http.get(`/pipelines/${pipelineId}/runs/${runId}/log`);
},
// 成员管理
getMembers: async (pipelineId: number | string) => {
return http.get(`/pipelines/${pipelineId}/members`);
},
addMember: async (pipelineId: number | string, data: { username: string; role: string }) => {
return http.post(`/pipelines/${pipelineId}/members`, data);
},
removeMember: async (pipelineId: number | string, memberId: number | string) => {
return http.delete(`/pipelines/${pipelineId}/members/${memberId}`);
},
// 组授权
assignGroup: async (pipelineId: number | string, data: { group_id: number; role: string }) => {
return http.post(`/pipelines/${pipelineId}/groups`, data);
},
// 按 code 操作(列表页/详情页常用) // Logan.Li
getByCode: (code: string) => http.get(`/pipelines/${code}`),
getRunsByCode: (code: string, pageSize = 50) =>
http.get<ListResponse>(`/pipelines/${code}/runs`, { page_size: pageSize }),
triggerByCode: (code: string) => http.post(`/pipelines/${code}/trigger`, {}),
stopRunByCode: (code: string, runId: number | string) =>
http.post(`/pipelines/${code}/runs/${runId}/stop`, {}),
batchDeleteRuns: (code: string, ids: number[]) =>
http.post(`/pipelines/${code}/runs/batch-delete`, { ids }),
getRunLogStream: (runId: number | string) => http.get(`/pipelines/runs/${runId}/log-stream`),
getQueue: (code: string) => http.get(`/pipelines/${code}/queue`),
removeFromQueue: (code: string, runId: number | string) =>
http.delete(`/pipelines/${code}/queue/${runId}`),
getWorkspace: (runId: number | string) => http.get(`/pipelines/runs/${runId}/workspace`),
listRunFiles: (runId: number | string, path?: string) =>
http.get(`/pipelines/runs/${runId}/files`, path ? { path } : undefined),
};
// ==================== 应用发布 API ====================
export const releaseApi = {
getReleases: async (params?: { page?: number; page_size?: number }) => {
return http.get<ListResponse>('/releases', params);
},
createRelease: async ( data: any) => {
return http.post('/releases', data);
},
approveRelease: async (id: number | string) => {
return http.post(`/releases/${id}/approve`);
},
rejectRelease: async (id: number | string) => {
return http.post(`/releases/${id}/reject`);
},
deployRelease: async (id: number | string) => {
return http.post(`/releases/${id}/deploy`);
},
rollbackRelease: async (id: number | string) => {
return http.post(`/releases/${id}/rollback`);
},
};
// ==================== 定时任务 API ====================
export const deployApi = {
// Git 仓库认证
getRepos: () => http.get<ListResponse>('/deploy/repos'),
getRepo: (id: number | string) => http.get(`/deploy/repos/${id}`),
createRepo: ( data: any) => http.post('/deploy/repos', data),
updateRepo: (id: number | string, data: any) => http.put(`/deploy/repos/${id}`, data),
deleteRepo: (id: number | string) => http.delete(`/deploy/repos/${id}`),
// 镜像仓库认证
getRegistries: () => http.get<ListResponse>('/deploy/registries'),
getRegistry: (id: number | string) => http.get(`/deploy/registries/${id}`),
createRegistry: ( data: any) => http.post('/deploy/registries', data),
updateRegistry: (id: number | string, data: any) => http.put(`/deploy/registries/${id}`, data),
deleteRegistry: (id: number | string) => http.delete(`/deploy/registries/${id}`),
// 环境管理
getEnvironments: () => http.get<ListResponse>('/deploy/environments'),
createEnvironment: ( data: any) => http.post('/deploy/environments', data),
updateEnvironment: (id: number | string, data: any) => http.put(`/deploy/environments/${id}`, data),
deleteEnvironment: (id: number | string) => http.delete(`/deploy/environments/${id}`),
// Item Role 权限管理 (Jenkins Role Strategy 风格)
getItemRoles: () => http.get<ListResponse>('/admin/item-roles'),
createItemRole: ( data: any) => http.post('/admin/item-roles', data),
updateItemRole: (id: number | string, data: any) => http.put(`/admin/item-roles/${id}`, data),
deleteItemRole: (id: number | string) => http.delete(`/admin/item-roles/${id}`),
getUserItemRoles: (userId: number | string) => http.get(`/admin/users/${userId}/item-roles`),
assignItemRole: (userId: number | string, data: { user_id: number; item_role_id: number }) => http.post(`/admin/users/${userId}/item-roles`, data),
removeItemRole: (userId: number | string, roleId: number | string) => http.delete(`/admin/users/${userId}/item-roles/${roleId}`),
// 用户组管理
getGroups: () => http.get<ListResponse>('/deploy/groups'),
createGroup: ( data: any) => http.post('/deploy/groups', data),
updateGroup: (id: number | string, data: any) => http.put(`/deploy/groups/${id}`, data),
deleteGroup: (id: number | string) => http.delete(`/deploy/groups/${id}`),
getGroupMembers: (id: number | string) => http.get(`/deploy/groups/${id}/members`),
addGroupMember: (id: number | string, data: { username: string }) => http.post(`/deploy/groups/${id}/members`, data),
removeGroupMember: (id: number | string, memberId: number | string) => http.delete(`/deploy/groups/${id}/members/${memberId}`),
// 工具配置 // Logan.Li
getTools: () => http.get<ListResponse>('/deploy/tools'),
getTool: (id: number | string) => http.get(`/deploy/tools/${id}`),
updateTool: (id: number | string, data: any) => http.put(`/deploy/tools/${id}`, data),
installTool: (id: number | string, version?: string) =>
http.post(`/deploy/tools/${id}/install`, version ? { version } : {}),
checkTool: (id: number | string) => http.post(`/deploy/tools/${id}/check`),
getToolVersions: (id: number | string) => http.get(`/deploy/tools/${id}/versions`),
};
// ==================== Ansible 自动化 API ====================
export const credentialApi = {
list: (params?: { page?: number; page_size?: number; secret_type?: string; search?: string }) =>
http.get<{ list: any[]; total: number }>('/credentials', params),
get: (id: number | string) => http.get(`/credentials/${id}`),
create: (data: Record<string, unknown>) => http.post('/credentials', data),
update: (id: number | string, data: Record<string, unknown>) => http.put(`/credentials/${id}`, data),
delete: (id: number | string) => http.delete(`/credentials/${id}`),
toggleActive: (id: number | string, isActive: boolean) =>
http.put(`/credentials/${id}`, { is_active: isActive }),
};
// 服务器凭据关联 API
export const serverCredentialApi = {
assign: (serverId: number | string, credentialId: number) =>
http.post(`/servers/${serverId}/assign-credential`, { credential_id: credentialId }),
};
+14
View File
@@ -0,0 +1,14 @@
// API 统一出口 — 从各域模块 re-export
// 所有 API 方法通过 `import { xxxApi } from "@/api"` 访问 // Logan.Li
export * from './auth';
export * from './dashboard';
export * from './server';
export * from './kubernetes';
export * from './deploy';
export * from './automation';
export * from './monitor';
export * from './agent';
export * from './cloud';
export * from './system';
export * from './ai';
+3
View File
@@ -0,0 +1,3 @@
// Kubernetes API — 子模块 re-export(保持 @/api 导入路径不变) // Logan.Li
export { kubernetesApi } from './kubernetes/index';
+22
View File
@@ -0,0 +1,22 @@
// Kubernetes 集群管理 API // Logan.Li
import { http, type ListResponse } from '@/utils/request';
export const clusterApi = {
getClusters: async () => http.get<ListResponse>('/kubernetes-clusters'),
getClusterDetail: async (id: number | string) => http.get(`/kubernetes-clusters/${id}/detail`),
createCluster: async (data: Record<string, unknown>) => http.post('/kubernetes-clusters', data),
updateCluster: async (id: number | string, data: Record<string, unknown>) => http.put(`/kubernetes-clusters/${id}`, data),
deleteCluster: async (id: number | string) => http.delete(`/kubernetes-clusters/${id}`),
getPods: async (clusterId: number | string) => http.get(`/kubernetes-clusters/${clusterId}/pods`),
getDeployments: async (clusterId: number | string) => http.get(`/kubernetes-clusters/${clusterId}/deployments`),
getServices: async (clusterId: number | string) => http.get(`/kubernetes-clusters/${clusterId}/services`),
getIngresses: async (clusterId: number | string) => http.get(`/kubernetes-clusters/${clusterId}/ingresses`),
syncCluster: async (clusterId: number | string) => http.post(`/kubernetes-clusters/${clusterId}/sync`),
exportAllResources: async (clusterCode: string) =>
http.download(`/kubernetes/${clusterCode}/export`, `cluster-${clusterCode}-resources.tar.gz`),
getTopology: async (clusterId: number | string) => http.get(`/kubernetes-clusters/${clusterId}/topology`),
saveTopology: async (clusterId: number | string, layoutData: string) =>
http.put(`/kubernetes-clusters/${clusterId}/topology`, { layout_data: layoutData }),
getMultiClusterComparison: async () => http.get('/kubernetes/compare'),
};
+94
View File
@@ -0,0 +1,94 @@
// Kubernetes API 辅助:流式 URL / WebSocket / 导出 // Logan.Li
import { buildApiUrl, getAuthToken, getWsBase, http } from '@/utils/request';
import { exportAsCSV, exportAsJSON } from '@/utils/export';
export { exportAsCSV, exportAsJSON };
export function buildPodLogsStreamUrl(
clusterCode: string,
namespace: string,
podName: string,
opts: {
container?: string;
tailLines?: number;
previous?: boolean;
sinceTime?: string;
} = {},
): string {
const params = new URLSearchParams();
params.set('stream', 'true');
if (opts.container) params.set('container', opts.container);
if (opts.tailLines && opts.tailLines > 0) params.set('tailLines', String(opts.tailLines));
if (opts.previous) params.set('previous', 'true');
if (opts.sinceTime) params.set('sinceTime', opts.sinceTime);
return buildApiUrl(
`/kubernetes/${clusterCode}/namespace/${namespace}/pods/${podName}/logs`,
params,
);
}
export function buildPodExecWsUrl(
clusterId: number | string,
namespace: string,
podName: string,
container?: string,
command?: string,
): string {
const params = new URLSearchParams();
if (container) params.set('container', container);
if (command) params.set('command', command);
const token = getAuthToken();
if (token) params.set('token', token);
const qs = params.toString();
const wsBase = getWsBase();
return `${wsBase}/ws/kubernetes-exec/${clusterId}/namespaces/${namespace}/pods/${podName}${qs ? `?${qs}` : ''}`;
}
export function buildPodFileDownloadUrl(
clusterCode: string,
namespace: string,
podName: string,
path: string,
container?: string,
): string {
const params = new URLSearchParams({ path });
if (container) params.set('container', container);
const token = getAuthToken();
if (token) params.set('token', token);
return buildApiUrl(
`/kubernetes/${clusterCode}/namespace/${namespace}/pods/${podName}/files/download`,
params,
);
}
export async function readPodFileText(
clusterCode: string,
namespace: string,
podName: string,
path: string,
container?: string,
): Promise<string> {
const url = buildPodFileDownloadUrl(clusterCode, namespace, podName, path, container);
const resp = await fetch(url);
if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
return resp.text();
}
export async function uploadPodFile(
clusterCode: string,
namespace: string,
podName: string,
targetPath: string,
file: File,
container?: string,
): Promise<unknown> {
const formData = new FormData();
formData.append('file', file);
formData.append('path', targetPath);
if (container) formData.append('container', container);
return http.upload(
`/kubernetes/${clusterCode}/namespace/${namespace}/pods/${podName}/files/upload`,
formData,
);
}
+20
View File
@@ -0,0 +1,20 @@
// Kubernetes API 聚合出口 // Logan.Li
import { clusterApi } from './cluster';
import { nodeApi } from './node';
import { podApi } from './pod';
import { workloadApi } from './workload';
import { namespaceApi } from './namespace';
import { resourceApi } from './resource';
import { exportAsCSV, exportAsJSON } from './helpers';
export const kubernetesApi = {
...clusterApi,
...nodeApi,
...podApi,
...workloadApi,
...namespaceApi,
...resourceApi,
exportAsCSV,
exportAsJSON,
};
+14
View File
@@ -0,0 +1,14 @@
// Kubernetes Namespace API // Logan.Li
import { http } from '@/utils/request';
export const namespaceApi = {
getNamespaces: async (clusterCode: string) => http.get(`/kubernetes/${clusterCode}/namespaces`),
getNamespacesDetail: async (clusterCode: string) => http.get(`/kubernetes/${clusterCode}/namespaces/detail`),
getNamespaceDetail: async (clusterCode: string, namespace: string) =>
http.get(`/kubernetes/${clusterCode}/namespace/${namespace}/detail`),
createNamespace: async (clusterCode: string, name: string, labels?: Record<string, string>) =>
http.post(`/kubernetes/${clusterCode}/namespaces`, { name, labels: labels || {} }),
deleteNamespace: async (clusterCode: string, namespace: string) =>
http.delete(`/kubernetes/${clusterCode}/namespaces/${namespace}`),
};
+10
View File
@@ -0,0 +1,10 @@
// Kubernetes 节点 API // Logan.Li
import { http } from '@/utils/request';
export const nodeApi = {
getNodes: async (clusterId: number | string) => http.get(`/kubernetes-clusters/${clusterId}/nodes`),
getClusterNodes: async (clusterCode: string) => http.get(`/kubernetes/${clusterCode}/nodes`),
getNodeDetail: async (clusterCode: string, nodeName: string) =>
http.get(`/kubernetes/${clusterCode}/nodes/${encodeURIComponent(nodeName)}`),
};
+69
View File
@@ -0,0 +1,69 @@
// Kubernetes Pod API(日志 / Exec / 文件 / 指标) // Logan.Li
import { http } from '@/utils/request';
import {
buildPodExecWsUrl,
buildPodFileDownloadUrl,
buildPodLogsStreamUrl,
readPodFileText,
uploadPodFile,
} from './helpers';
export const podApi = {
getPodLogs: async (
clusterCode: string,
namespace: string,
podName: string,
tail = 200,
container?: string,
) => {
const params = new URLSearchParams({ tail: String(tail) });
if (container) params.set('container', container);
return http.get(`/kubernetes/${clusterCode}/namespace/${namespace}/pods/${podName}/logs?${params}`);
},
getPodLogsEnhanced: async (
clusterCode: string,
namespace: string,
podName: string,
opts: {
container?: string;
tailLines?: number;
previous?: boolean;
sinceTime?: string;
} = {},
) => {
const params = new URLSearchParams();
if (opts.container) params.set('container', opts.container);
if (opts.tailLines && opts.tailLines > 0) params.set('tailLines', String(opts.tailLines));
if (opts.previous) params.set('previous', 'true');
if (opts.sinceTime) params.set('sinceTime', opts.sinceTime);
const qs = params.toString();
return http.get(`/kubernetes/${clusterCode}/namespace/${namespace}/pods/${podName}/logs${qs ? `?${qs}` : ''}`);
},
buildPodLogsStreamUrl,
execPod: async (
clusterCode: string,
namespace: string,
podName: string,
command: string[],
container?: string,
) => http.post(`/kubernetes/${clusterCode}/namespace/${namespace}/pods/${podName}/exec`, { command, container }),
buildPodExecWsUrl,
listPodFiles: async (
clusterCode: string,
namespace: string,
podName: string,
path: string,
container?: string,
) => http.post(`/kubernetes/${clusterCode}/namespace/${namespace}/pods/${podName}/files/list`, { path, container }),
buildPodFileDownloadUrl,
readPodFileText,
uploadPodFile,
getPodMetrics: async (clusterCode: string, namespace?: string) => {
const params = namespace ? { namespace } : undefined;
return http.get(`/kubernetes/${clusterCode}/metrics/pods`, params);
},
getAllPods: async (clusterCode: string) => http.get(`/kubernetes/${clusterCode}/pods`),
getNamespacePods: async (clusterCode: string, namespace: string) =>
http.get(`/kubernetes/${clusterCode}/namespace/${namespace}/pods`),
};
+48
View File
@@ -0,0 +1,48 @@
// Kubernetes 命名空间资源 / YAML / 事件 / 容量 API // Logan.Li
import { http } from '@/utils/request';
export const resourceApi = {
getNamespaceServices: async (clusterCode: string, namespace: string) =>
http.get(`/kubernetes/${clusterCode}/namespace/${namespace}/services`),
getNamespaceIngresses: async (clusterCode: string, namespace: string) =>
http.get(`/kubernetes/${clusterCode}/namespace/${namespace}/ingresses`),
getNamespaceConfigMaps: async (clusterCode: string, namespace: string) =>
http.get(`/kubernetes/${clusterCode}/namespace/${namespace}/configmaps`),
getNamespaceSecrets: async (clusterCode: string, namespace: string) =>
http.get(`/kubernetes/${clusterCode}/namespace/${namespace}/secrets`),
getPVCs: async (clusterCode: string, namespace: string) =>
http.get(`/kubernetes/${clusterCode}/namespace/${namespace}/pvcs`),
deletePVC: async (clusterCode: string, namespace: string, name: string) =>
http.delete(`/kubernetes/${clusterCode}/namespace/${namespace}/pvcs/${name}`),
getServiceAccounts: async (clusterCode: string, namespace: string) =>
http.get(`/kubernetes/${clusterCode}/namespace/${namespace}/serviceaccounts`),
getRoles: async (clusterCode: string, namespace: string) =>
http.get(`/kubernetes/${clusterCode}/namespace/${namespace}/roles`),
getRoleBindings: async (clusterCode: string, namespace: string) =>
http.get(`/kubernetes/${clusterCode}/namespace/${namespace}/rolebindings`),
getResourceYaml: async (clusterCode: string, namespace: string, resource: string, name: string) =>
http.getRaw(`/kubernetes/${clusterCode}/namespace/${namespace}/${resource}/${name}/yaml`),
updateResourceYaml: async (clusterCode: string, namespace: string, resource: string, name: string, yaml: string) =>
http.putRaw(`/kubernetes/${clusterCode}/namespace/${namespace}/${resource}/${name}/yaml`, yaml, 'application/yaml'),
deleteResourceYaml: async (clusterCode: string, namespace: string, resource: string, name: string) =>
http.delete(`/kubernetes/${clusterCode}/namespace/${namespace}/${resource}/${name}/yaml`),
getEvents: async (clusterCode: string, namespace?: string, type?: string) => {
const params: Record<string, string> = {};
if (namespace) params.namespace = namespace;
if (type) params.type = type;
return http.get(`/kubernetes/${clusterCode}/events`, params);
},
getEventsSummary: async (clusterCode: string, namespace?: string, hours?: number) => {
const params: Record<string, string | number> = {};
if (namespace) params.namespace = namespace;
if (hours) params.hours = hours;
return http.get(`/kubernetes/${clusterCode}/events/summary`, params);
},
getCapacity: async (clusterCode: string, namespace?: string) => {
const params = namespace ? { namespace } : undefined;
return http.get(`/kubernetes/${clusterCode}/capacity`, params);
},
applyYAML: async (clusterCode: string, yaml: string) =>
http.post(`/kubernetes/${clusterCode}/yaml/apply`, { yaml }),
};
+91
View File
@@ -0,0 +1,91 @@
// Kubernetes 工作负载 API(Deployment / StatefulSet / HPA / CronJob) // Logan.Li
import { http } from '@/utils/request';
export const workloadApi = {
scaleDeployment: async (clusterCode: string, namespace: string, name: string, replicas: number) =>
http.post(`/kubernetes/${clusterCode}/namespace/${namespace}/deployments/${name}/scale`, { replicas }),
restartDeployment: async (clusterCode: string, namespace: string, name: string) =>
http.post(`/kubernetes/${clusterCode}/namespace/${namespace}/deployments/${name}/restart`),
pauseDeployment: async (clusterCode: string, namespace: string, name: string) =>
http.post(`/kubernetes/${clusterCode}/namespace/${namespace}/deployments/${name}/pause`),
resumeDeployment: async (clusterCode: string, namespace: string, name: string) =>
http.post(`/kubernetes/${clusterCode}/namespace/${namespace}/deployments/${name}/resume`),
updateDeploymentImage: async (
clusterCode: string,
namespace: string,
name: string,
image: string,
containerName?: string,
) => http.post(`/kubernetes/${clusterCode}/namespace/${namespace}/deployments/${name}/update-image`, {
image,
container_name: containerName,
}),
getHPAs: async (clusterCode: string, namespace?: string) => {
if (namespace) return http.get(`/kubernetes/${clusterCode}/namespace/${namespace}/hpas`);
return http.get(`/kubernetes/${clusterCode}/hpas`);
},
createHPA: async (
clusterCode: string,
data: {
name: string;
namespace: string;
targetKind: string;
targetName: string;
minReplicas: number;
maxReplicas: number;
cpuPercent: number;
memPercent: number;
},
) => http.post(`/kubernetes/${clusterCode}/namespace/${data.namespace}/hpas`, data),
deleteHPA: async (clusterCode: string, namespace: string, name: string) =>
http.delete(`/kubernetes/${clusterCode}/namespace/${namespace}/hpas/${name}`),
getCronJobs: async (clusterCode: string, namespace?: string) => {
if (namespace) return http.get(`/kubernetes/${clusterCode}/namespace/${namespace}/cronjobs`);
return http.get(`/kubernetes-clusters/${clusterCode}/cronjobs`);
},
createCronJob: async (
clusterCode: string,
data: { name: string; namespace: string; schedule: string; image: string; command: string[] },
) => http.post(`/kubernetes/${clusterCode}/namespace/${data.namespace}/cronjobs`, data),
suspendCronJob: async (clusterCode: string, namespace: string, name: string, suspend: boolean) =>
http.post(`/kubernetes/${clusterCode}/namespace/${namespace}/cronjobs/${name}/suspend`, { suspend }),
triggerCronJob: async (clusterCode: string, namespace: string, name: string) =>
http.post(`/kubernetes/${clusterCode}/namespace/${namespace}/cronjobs/${name}/trigger`),
deleteCronJob: async (clusterCode: string, namespace: string, name: string) =>
http.delete(`/kubernetes/${clusterCode}/namespace/${namespace}/cronjobs/${name}`),
getNamespaceDeployments: async (clusterCode: string, namespace: string) =>
http.get(`/kubernetes/${clusterCode}/namespace/${namespace}/deployments`),
getAllDeployments: async (clusterCode: string) => http.get(`/kubernetes/${clusterCode}/deployments`),
getStatefulSets: async (clusterCode: string, namespace: string) =>
http.get(`/kubernetes/${clusterCode}/namespace/${namespace}/statefulsets`),
getDaemonSets: async (clusterCode: string, namespace: string) =>
http.get(`/kubernetes/${clusterCode}/namespace/${namespace}/daemonsets`),
getStatefulSetDetail: async (clusterCode: string, namespace: string, name: string) =>
http.get(`/kubernetes/${clusterCode}/namespace/${namespace}/statefulsets/${name}`),
getDaemonSetDetail: async (clusterCode: string, namespace: string, name: string) =>
http.get(`/kubernetes/${clusterCode}/namespace/${namespace}/daemonsets/${name}`),
scaleStatefulSet: async (clusterCode: string, namespace: string, name: string, replicas: number) =>
http.post(`/kubernetes/${clusterCode}/namespace/${namespace}/statefulsets/${name}/scale`, { replicas }),
restartStatefulSet: async (clusterCode: string, namespace: string, name: string) =>
http.post(`/kubernetes/${clusterCode}/namespace/${namespace}/statefulsets/${name}/restart`, {}),
restartDaemonSet: async (clusterCode: string, namespace: string, name: string) =>
http.post(`/kubernetes/${clusterCode}/namespace/${namespace}/daemonsets/${name}/restart`, {}),
getReplicaSets: async (clusterCode: string, namespace: string) =>
http.get(`/kubernetes/${clusterCode}/namespace/${namespace}/replicasets`),
getDeploymentRevisions: async (clusterCode: string, namespace: string, name: string) =>
http.get(`/kubernetes/${clusterCode}/namespace/${namespace}/deployments/${name}/revisions`),
rollbackDeployment: async (clusterCode: string, namespace: string, name: string, revision: number) =>
http.post(`/kubernetes/${clusterCode}/namespace/${namespace}/deployments/${name}/rollback`, { revision }),
getDeployment: async (clusterCode: string, namespace: string, name: string) => {
try {
return await http.get(`/kubernetes/${clusterCode}/namespace/${namespace}/deployments/${name}`);
} catch {
const res: Record<string, unknown> = await http.get(
`/kubernetes/${clusterCode}/namespace/${namespace}/deployments`,
);
const list = Array.isArray(res) ? res : (res?.list || res?.items || res?.data || []);
return (list as { name: string }[]).find((d) => d.name === name) || null;
}
},
};
+222
View File
@@ -0,0 +1,222 @@
// 监控告警 (规则/通知/大屏/Prometheus/Zabbix)
// 从 services/api.ts 拆分 — Q3 api.ts 模块化
import { http, type ListResponse } from '@/utils/request';
export const alertApi = {
getAlerts: async (params?: { page?: number; page_size?: number; status?: string; severity?: string }) => {
return http.get<ListResponse>('/alerts', params);
},
getRules: async () => {
return http.get('/alerts/rules');
},
createRule: async ( data: any) => {
return http.post('/alerts/rules', data);
},
updateRule: async (id: number | string, data: any) => {
return http.put(`/alerts/rules/${id}`, data);
},
deleteRule: async (id: number | string) => {
return http.delete(`/alerts/rules/${id}`);
},
batchDeleteRules: async (ids: number[]) => {
return http.delete('/alerts/rules/batch-delete', { ids });
},
toggleRule: async (id: number | string) => {
return http.post(`/alerts/rules/${id}/toggle`);
},
acknowledge: async (id: number | string) => {
return http.post(`/alerts/${id}/ack`);
},
// 通知渠道管理
getNotifyChannels: async () => {
return http.get('/alerts/notify-channels');
},
createNotifyChannel: async ( data: any) => {
return http.post('/alerts/notify-channels', data);
},
updateNotifyChannel: async (id: number | string, data: any) => {
return http.put(`/alerts/notify-channels/${id}`, data);
},
deleteNotifyChannel: async (id: number | string) => {
return http.delete(`/alerts/notify-channels/${id}`);
},
testNotifyChannel: async (id: number | string) => {
return http.post(`/alerts/notify-channels/${id}/test`);
},
// 报警联系人
getContacts: async () => {
return http.get('/alerts/contacts');
},
createContact: async ( data: any) => {
return http.post('/alerts/contacts', data);
},
updateContact: async (id: number | string, data: any) => {
return http.put(`/alerts/contacts/${id}`, data);
},
deleteContact: async (id: number | string) => {
return http.delete(`/alerts/contacts/${id}`);
},
// 报警联系组
getContactGroups: async () => {
return http.get('/alerts/contact-groups');
},
createContactGroup: async ( data: any) => {
return http.post('/alerts/contact-groups', data);
},
updateContactGroup: async (id: number | string, data: any) => {
return http.put(`/alerts/contact-groups/${id}`, data);
},
deleteContactGroup: async (id: number | string) => {
return http.delete(`/alerts/contact-groups/${id}`);
},
};
// ==================== 流水线 API ====================
export const alertCenterApi = {
getAlerts: async (params?: { page?: number; page_size?: number; status?: string; severity?: string }) => {
return http.get<ListResponse>('/alerts', params);
},
getRules: async () => {
return http.get('/alerts/rules');
},
getChannels: async () => {
return http.get('/alerts/notify-channels');
},
acknowledge: async (id: number | string) => {
return http.post(`/alerts/${id}/ack`);
},
resolve: async (id: number | string) => {
return http.post(`/alerts/${id}/ack`);
},
// 告警静默规则 CRUD
getSilences: async (params?: { status?: string }) => {
return http.get<ListResponse>('/alerts/silences', params);
},
createSilence: async (data: Record<string, unknown>) => {
return http.post('/alerts/silences', data);
},
updateSilence: async (id: number | string, data: Record<string, unknown>) => {
return http.put(`/alerts/silences/${id}`, data);
},
deleteSilence: async (id: number | string) => {
return http.delete(`/alerts/silences/${id}`);
},
toggleSilence: async (id: number | string) => {
return http.post(`/alerts/silences/${id}/toggle`);
},
toggleRule: async (id: number | string) => {
return http.post(`/alerts/rules/${id}/toggle`);
},
createRule: async ( data: any) => {
return http.post('/alerts/rules', data);
},
deleteRule: async (id: number | string) => {
return http.delete(`/alerts/rules/${id}`);
},
// 一键报警 — 后端批量创建默认规则
quickSetup: async (type: string = 'ecs') => {
return http.post('/alerts/quick-setup', { type });
},
};
// ==================== 站点拨测 API ====================
export const siteApi = {
getStats: async () => {
return http.get('/site/stats');
},
getTasks: async () => {
return http.get<{ list: any[]; total: number }>('/site/tasks');
},
createTask: async (data: { name: string; url: string; type: string; frequency_sec?: number; timeout_sec?: number; expected_status_code?: number }) => {
return http.post('/site/tasks', data);
},
deleteTask: async (id: number | string) => {
return http.delete(`/site/tasks/${id}`);
},
toggleTask: async (id: number | string, enabled: boolean) => {
return http.put(`/site/tasks/${id}`, { enabled });
},
};
// ==================== 链路追踪 API(暂无后端,返回空结果优雅降级) ====================
export const traceApi = {
getTraces: async ( _params: any): Promise<{ data: any[]; total: number }> => ({ data: [], total: 0 }),
getServices: async (_timeRange: string): Promise<{ data: any[]; total: number }> => ({ data: [], total: 0 }),
getTraceDetail: async (_traceId: string): Promise<{ data: { spans: any[] } }> => ({ data: { spans: [] } }),
};
// ==================== Grafana 仪表盘 API(暂无后端,返回空结果优雅降级) ====================
export const dashboardApi = {
getDashboards: async (): Promise<{ data: any[]; total: number }> => ({ data: [], total: 0 }),
getDatasources: async (): Promise<{ data: any[]; total: number }> => ({ data: [], total: 0 }),
createDashboard: async ( _data: any) => ({ success: false }),
updateDashboard: async (_id: number | string, _data: any) => ({ success: false }),
deleteDashboard: async (_id: number | string) => ({ success: false }),
createDatasource: async ( _data: any) => ({ success: false }),
};
// ==================== Prometheus 数据源管理 API ==================== // Logan.Li
export const promDatasourceApi = {
list: () => http.get('/prometheus-datasources'),
get: (id: number | string) => http.get(`/prometheus-datasources/${id}`),
create: ( data: any) => http.post('/prometheus-datasources', data),
update: (id: number | string, data: any) => http.put(`/prometheus-datasources/${id}`, data),
delete: (id: number | string) => http.delete(`/prometheus-datasources/${id}`),
setDefault: (id: number | string) => http.post(`/prometheus-datasources/${id}/default`),
testConnection: ( data: any) => http.post('/prometheus-datasources/test', data),
};
// ==================== Zabbix 数据源管理 API ==================== // Logan.Li
export const zabbixDatasourceApi = {
list: () => http.get('/zabbix-datasources'),
get: (id: number | string) => http.get(`/zabbix-datasources/${id}`),
create: ( data: any) => http.post('/zabbix-datasources', data),
update: (id: number | string, data: any) => http.put(`/zabbix-datasources/${id}`, data),
delete: (id: number | string) => http.delete(`/zabbix-datasources/${id}`),
setDefault: (id: number | string) => http.post(`/zabbix-datasources/${id}/default`),
testConnection: ( data: any) => http.post('/zabbix-datasources/test', data),
};
// ==================== 指标探索 / 中间件监控 API ==================== // Logan.Li
export const metricsApi = {
getTargets: (params?: Record<string, string | number | boolean | undefined>) =>
http.get('/metrics/targets', params),
getNames: () => http.get('/metrics/names'),
query: (params: {
target_id: string | number;
metric_name: string;
from: string;
to: string;
limit?: number;
}) => http.get('/metrics/query', params),
};
// ==================== SNMP 监控 API ==================== // Logan.Li
export const snmpApi = {
getStats: () => http.get('/snmp/stats'),
getDevices: () => http.get('/snmp/devices'),
createDevice: (data: Record<string, unknown>) => http.post('/snmp/devices', data),
deleteDevice: (id: number | string) => http.delete(`/snmp/devices/${id}`),
};
// ==================== Prometheus / Zabbix 大屏代理 API ==================== // Logan.Li
export const prometheusProxyApi = {
connect: (url: string) => http.post('/prometheus/connect', { url }),
dashboard: (url: string, type: string) => http.post('/prometheus/dashboard', { url, type }),
};
export const zabbixProxyApi = {
connect: (url: string, username: string, password: string) =>
http.post('/zabbix/connect', { url, username, password }),
};
+104
View File
@@ -0,0 +1,104 @@
// 服务器/资产/区域/资源型号
// 从 services/api.ts 拆分 — Q3 api.ts 模块化
import { http, type ListResponse } from '@/utils/request';
export const serverApi = {
getServers: async (params?: { page?: number; page_size?: number; keyword?: string; status?: string }) => {
return http.get<ListResponse>('/servers', params);
},
getServerDetail: async (id: number | string) => {
return http.get(`/servers/${id}`);
},
getServerStats: async () => {
return http.get('/servers/stats');
},
createServer: async ( data: any) => {
return http.post('/servers', data);
},
updateServer: async (id: number | string, data: any) => {
return http.put(`/servers/${id}`, data);
},
deleteServer: async (id: number | string) => {
return http.delete(`/servers/${id}`);
},
batchDelete: async (ids: number[]) => {
return http.post('/servers/batch-delete', { ids });
},
batchCreate: async (data: { servers: any[]; region_id?: string; auth_type?: string; credential_id?: number; default_port?: number }) => {
return http.post('/servers/batch', data);
},
getMetrics: async (_id: number | string) => {
// 后端暂无单机 metrics,用 dashboard metrics
return http.get('/dashboard/metrics');
},
// 远程安装 Agent(通过 SSH 执行安装脚本),可选传入凭据
installAgent: async (id: number | string, token: string, creds?: { username?: string; password?: string; ssh_key?: string; auth_type?: string }) => {
const body: Record<string, any> = { token };
if (creds) Object.assign(body, creds);
return http.post<{ installed: boolean; arch: string; output: string }>(`/servers/${id}/install-agent`, body);
},
// 批量远程安装 Agent
batchInstallAgent: async (ids: number[], token: string) => {
return http.post<{ total: number; success: number; results: any[] }>(`/servers/install-agent?token=${encodeURIComponent(token)}`, { server_ids: ids });
},
// SFTP 文件浏览
listFiles: async (serverId: number, path: string) => {
return http.get(`/servers/${serverId}/files?path=${encodeURIComponent(path)}`);
},
downloadFile: async (serverId: number, filePath: string) => {
return http.download(`/servers/${serverId}/files/download?path=${encodeURIComponent(filePath)}`);
},
uploadFile: async (serverId: number, dirPath: string, file: File) => {
const formData = new FormData();
formData.append('file', file);
return http.upload(`/servers/${serverId}/files/upload?path=${encodeURIComponent(dirPath)}`, formData);
},
deleteFile: async (serverId: number, filePath: string) => {
return http.delete(`/servers/${serverId}/files?path=${encodeURIComponent(filePath)}`);
},
mkdir: async (serverId: number, dirPath: string) => {
return http.post(`/servers/${serverId}/files/mkdir`, { path: dirPath });
},
};
// ==================== Kubernetes 集群 API ====================
export const regionApi = {
list: async () => {
return http.get<ListResponse>('/regions');
},
create: async ( data: any) => {
return http.post('/regions', data);
},
update: async (id: number | string, data: any) => {
return http.put(`/regions/${id}`, data);
},
delete: async (id: number | string) => {
return http.delete(`/regions/${id}`);
},
// 批量删除 // Logan.Li
batchDelete: async (ids: number[]) => {
return http.delete('/regions/batch-delete', { ids });
},
};
// ==================== 资源模型 API ====================
export const resourceModelApi = {
list: async () => {
return http.get<ListResponse>('/resource-models');
},
create: async ( data: any) => {
return http.post('/resource-models', data);
},
update: async (id: number | string, data: any) => {
return http.put(`/resource-models/${id}`, data);
},
delete: async (id: number | string) => {
return http.delete(`/resource-models/${id}`);
},
};
// ==================== 审计日志 API ====================
+10
View File
@@ -0,0 +1,10 @@
// 系统域 API — 子模块 re-export // Logan.Li
export {
auditApi,
terminalSessionApi,
sessionCommandApi,
loginLogApi,
approvalWorkflowApi,
approvalApi,
} from './system/index';
+28
View File
@@ -0,0 +1,28 @@
// 审批流程 API // Logan.Li
import { http } from '@/utils/request';
export const approvalWorkflowApi = {
list: async (params?: { category?: string }) => http.get('/approval-workflows', params),
get: async (id: number | string) => http.get(`/approval-workflows/${id}`),
create: async (data: Record<string, unknown>) => http.post('/approval-workflows', data),
update: async (id: number | string, data: Record<string, unknown>) => http.put(`/approval-workflows/${id}`, data),
delete: async (id: number | string) => http.delete(`/approval-workflows/${id}`),
setDefault: async (id: number | string) => http.put(`/approval-workflows/${id}/default`),
getSteps: async (id: number | string) => http.get(`/approval-workflows/${id}/steps`),
};
export const approvalApi = {
getTemplates: async (params?: { type?: string; category?: string }) => http.get('/approvals/templates', params),
getTemplate: async (id: number | string) => http.get(`/approvals/templates/${id}`),
createTemplate: async (data: Record<string, unknown>) => http.post('/approvals/templates', data),
updateTemplate: async (id: number | string, data: Record<string, unknown>) => http.put(`/approvals/templates/${id}`, data),
deleteTemplate: async (id: number | string) => http.delete(`/approvals/templates/${id}`),
getProcesses: async (params?: { page?: number; page_size?: number; status?: string; category?: string }) =>
http.get('/approvals/processes', params),
createProcess: async (data: Record<string, unknown>) => http.post('/approvals/processes', data),
approveProcess: async (id: number | string, comment?: string) =>
http.post(`/approvals/processes/${id}/approve`, { comment }),
rejectProcess: async (id: number | string, comment?: string) =>
http.post(`/approvals/processes/${id}/reject`, { comment }),
};
+30
View File
@@ -0,0 +1,30 @@
// 审计日志 API // Logan.Li
import { http, type ListResponse } from '@/utils/request';
export const auditApi = {
getLogs: async (params?: {
page?: number;
page_size?: number;
module?: string;
action?: string;
username?: string;
start_time?: string;
end_time?: string;
}) => http.get<ListResponse>('/audit/logs', params as Record<string, string | number | boolean | undefined>),
getLogDetail: async (id: number | string) => http.get(`/audit/logs/${id}`),
getModules: async () => http.get('/audit/modules'),
getActions: async () => http.get('/audit/actions'),
getStatistics: async () => http.get('/audit/statistics'),
exportLogs: async (params?: Record<string, string | number | boolean | undefined>) => {
const qs = new URLSearchParams();
qs.set('format', 'csv');
if (params) {
Object.entries(params).forEach(([k, v]) => {
if (v !== undefined && v !== null && v !== '') qs.set(k, String(v));
});
}
return http.download(`/audit/logs/export?${qs.toString()}`);
},
clearLogs: async () => http.post('/audit/logs/clear'),
};
+5
View File
@@ -0,0 +1,5 @@
// 系统域 API 聚合出口 // Logan.Li
export { auditApi } from './audit';
export { terminalSessionApi, sessionCommandApi, loginLogApi } from './terminal';
export { approvalWorkflowApi, approvalApi } from './approval';
+37
View File
@@ -0,0 +1,37 @@
// 终端会话 / 命令 / 登录日志 API // Logan.Li
import { http, type ListResponse } from '@/utils/request';
export const terminalSessionApi = {
list: async (params?: {
page?: number;
page_size?: number;
server_id?: number;
username?: string;
status?: string;
}) => http.get<ListResponse>('/terminal-sessions', params as Record<string, string | number | boolean | undefined>),
get: async (id: number) => http.get(`/terminal-sessions/${id}`),
getRecord: async (id: number) => http.get<string>(`/terminal-sessions/${id}/record`),
kill: async (id: number) => http.post(`/terminal-sessions/${id}/kill`),
download: async (id: number) => http.download(`/terminal-sessions/${id}/download`, `session-${id}.cast`),
delete: async (id: number) => http.delete(`/terminal-sessions/${id}`),
batchDelete: async (ids: number[]) => http.post('/terminal-sessions/batch-delete', { ids }),
};
export const sessionCommandApi = {
list: async (params?: {
page?: number;
page_size?: number;
session_id?: number;
username?: string;
}) => http.get<ListResponse>('/session-commands', params as Record<string, string | number | boolean | undefined>),
};
export const loginLogApi = {
list: async (params?: {
page?: number;
page_size?: number;
username?: string;
status?: string;
}) => http.get<ListResponse>('/login-logs', params as Record<string, string | number | boolean | undefined>),
};