refactor(q1): src/api 全量清零 any + types/monitor 扩展输入 DTO

ROADMAP Q1 推进(前端类型安全治理 in_progress):

- src/api/ 整个目录 any 清零(含 monitor/ deploy/ 子目录 12+ 文件)
  create/update 入参 any -> Record<string, unknown> / object
  mock 桩 trace/grafana 对接 types/ 标准类型(Trace/GrafanaDashboard)
  典型接口 LdapFormData/ProbeForm 等强类型表单用 object 接收
- types/monitor.ts 扩展 ~150 行接口:
  ZabbixDatasource / AlertSilence / 7 个输入 DTO
  Trace / TraceSpan / TraceServiceMetrics / GrafanaDashboard / DashboardPanel
  HealthProbeInput

验证:
- 整个 src/api/ 目录 any=0
- ESLint no-explicit-any: 995 -> 937 (本项目此轮贡献 -58)
- tsc -b 零错误, npm run build ✓ (17.06s)
- API 回归 8/8 核心端点通过, Docker 部署 healthy
This commit is contained in:
attacker committed 2026-06-26 03:37:56 +08:00
1 parent 480e677042
commit b553c7956d
436 files changed
+410 -1198

No files matched your search

+4 -4
View File
@@ -15,8 +15,8 @@ export const agentApi = {
// 触发聚合
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),
createRule: ( data: Record<string, unknown>) => http.post('/agent/rules', data),
updateRule: (id: number, data: Record<string, unknown>) => 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 安装/卸载
@@ -27,8 +27,8 @@ export const agentApi = {
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),
createHealthProbe: ( data: object) => http.post('/agent/health-probes', data),
updateHealthProbe: (id: number, data: object) => 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}`),
+6 -6
View File
@@ -20,7 +20,7 @@ export const userApi = {
getProfile: async () => {
return http.get('/user/profile');
},
updateProfile: async ( data: any) => {
updateProfile: async ( data: Record<string, unknown>) => {
return http.put('/user/profile', data);
},
changePassword: async (data: { old_password: string; new_password: string }) => {
@@ -29,16 +29,16 @@ export const userApi = {
getUsers: async (params?: { page?: number; page_size?: number; keyword?: string }) => {
return http.get<ListResponse>('/admin/users', params);
},
createUser: async ( data: any) => {
createUser: async ( data: Record<string, unknown>) => {
return http.post('/admin/users', data);
},
updateUser: async (id: number | string, data: any) => {
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: any[]; skip_existing?: boolean }) => {
batchImport: async (data: { users: Record<string, unknown>[]; skip_existing?: boolean }) => {
return http.post('/admin/users/batch-import', data);
},
downloadTemplate: () => {
@@ -71,7 +71,7 @@ export const ldapApi = {
getConfig: async () => {
return http.get('/admin/ldap-config');
},
updateConfig: async ( data: any) => {
updateConfig: async ( data: object) => {
return http.put('/admin/ldap-config', data);
},
testConnection: async (data?: { test_user?: string; test_password?: string }) => {
@@ -80,7 +80,7 @@ export const ldapApi = {
listUsers: async (ouDn?: string) => {
return http.post('/admin/ldap-config/users', { ou_dn: ouDn || '' });
},
batchImport: async ( users: any[]) => {
batchImport: async ( users: Record<string, unknown>[]) => {
return http.post('/admin/ldap-config/import', { users });
},
listOUs: async () => {
+8 -8
View File
@@ -10,10 +10,10 @@ export const cronJobApi = {
getJob: async (id: number | string) => {
return http.get(`/cron-jobs/${id}`);
},
createJob: async ( data: any) => {
createJob: async ( data: Record<string, unknown>) => {
return http.post('/cron-jobs', data);
},
updateJob: async (id: number | string, data: any) => {
updateJob: async (id: number | string, data: Record<string, unknown>) => {
return http.put(`/cron-jobs/${id}`, data);
},
deleteJob: async (id: number | string) => {
@@ -39,10 +39,10 @@ export const scriptApi = {
getScript: async (id: number | string) => {
return http.get(`/scripts/${id}`);
},
createScript: async ( data: any) => {
createScript: async ( data: Record<string, unknown>) => {
return http.post('/scripts', data);
},
updateScript: async (id: number | string, data: any) => {
updateScript: async (id: number | string, data: Record<string, unknown>) => {
return http.put(`/scripts/${id}`, data);
},
deleteScript: async (id: number | string) => {
@@ -74,10 +74,10 @@ export const ansibleApi = {
getPlaybook: async (id: number | string) => {
return http.get(`/ansible/playbooks/${id}`);
},
createPlaybook: async ( data: any) => {
createPlaybook: async ( data: Record<string, unknown>) => {
return http.post('/ansible/playbooks', data);
},
updatePlaybook: async (id: number | string, data: any) => {
updatePlaybook: async (id: number | string, data: Record<string, unknown>) => {
return http.put(`/ansible/playbooks/${id}`, data);
},
deletePlaybook: async (id: number | string) => {
@@ -109,10 +109,10 @@ export const ansibleApi = {
getInventories: async (params?: { page?: number; page_size?: number; keyword?: string }) => {
return http.get<ListResponse>('/ansible/inventories', params);
},
createInventory: async ( data: any) => {
createInventory: async ( data: Record<string, unknown>) => {
return http.post('/ansible/inventories', data);
},
updateInventory: async (id: number | string, data: any) => {
updateInventory: async (id: number | string, data: Record<string, unknown>) => {
return http.put(`/ansible/inventories/${id}`, data);
},
deleteInventory: async (id: number | string) => {
+11 -11
View File
@@ -6,32 +6,32 @@ 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),
createRepo: ( data: Record<string, unknown>) => http.post('/deploy/repos', data),
updateRepo: (id: number | string, data: Record<string, unknown>) => 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),
createRegistry: ( data: Record<string, unknown>) => http.post('/deploy/registries', data),
updateRegistry: (id: number | string, data: Record<string, unknown>) => 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),
createEnvironment: ( data: Record<string, unknown>) => http.post('/deploy/environments', data),
updateEnvironment: (id: number | string, data: Record<string, unknown>) => 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),
createItemRole: ( data: Record<string, unknown>) => http.post('/admin/item-roles', data),
updateItemRole: (id: number | string, data: Record<string, unknown>) => 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),
createGroup: ( data: Record<string, unknown>) => http.post('/deploy/groups', data),
updateGroup: (id: number | string, data: Record<string, unknown>) => 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),
@@ -39,7 +39,7 @@ export const deployApi = {
// 工具配置
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),
updateTool: (id: number | string, data: Record<string, unknown>) => 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`),
+1 -1
View File
@@ -4,7 +4,7 @@ import { http } from '@/utils/request';
export const credentialApi = {
list: (params?: { page?: number; page_size?: number; secret_type?: string; search?: string }) =>
http.get<{ list: any[]; total: number }>('/credentials', params),
http.get<{ list: unknown[]; 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),
+2 -2
View File
@@ -9,10 +9,10 @@ export const pipelineApi = {
getPipelineDetail: async (id: number | string) => {
return http.get(`/pipelines/${id}`);
},
createPipeline: async ( data: any) => {
createPipeline: async ( data: Record<string, unknown>) => {
return http.post('/pipelines', data);
},
updatePipeline: async (id: number | string, data: any) => {
updatePipeline: async (id: number | string, data: Record<string, unknown>) => {
return http.put(`/pipelines/${id}`, data);
},
deletePipeline: async (id: number | string) => {
+1 -1
View File
@@ -6,7 +6,7 @@ export const releaseApi = {
getReleases: async (params?: { page?: number; page_size?: number }) => {
return http.get<ListResponse>('/releases', params);
},
createRelease: async ( data: any) => {
createRelease: async ( data: Record<string, unknown>) => {
return http.post('/releases', data);
},
approveRelease: async (id: number | string) => {
+1 -1
View File
@@ -37,7 +37,7 @@ export const alertCenterApi = {
toggleRule: async (id: number | string) => {
return http.post(`/alerts/rules/${id}/toggle`);
},
createRule: async ( data: any) => {
createRule: async ( data: Record<string, unknown>) => {
return http.post('/alerts/rules', data);
},
deleteRule: async (id: number | string) => {
+8 -8
View File
@@ -9,10 +9,10 @@ export const alertApi = {
getRules: async () => {
return http.get('/alerts/rules');
},
createRule: async ( data: any) => {
createRule: async ( data: Record<string, unknown>) => {
return http.post('/alerts/rules', data);
},
updateRule: async (id: number | string, data: any) => {
updateRule: async (id: number | string, data: Record<string, unknown>) => {
return http.put(`/alerts/rules/${id}`, data);
},
deleteRule: async (id: number | string) => {
@@ -31,10 +31,10 @@ export const alertApi = {
getNotifyChannels: async () => {
return http.get('/alerts/notify-channels');
},
createNotifyChannel: async ( data: any) => {
createNotifyChannel: async ( data: Record<string, unknown>) => {
return http.post('/alerts/notify-channels', data);
},
updateNotifyChannel: async (id: number | string, data: any) => {
updateNotifyChannel: async (id: number | string, data: Record<string, unknown>) => {
return http.put(`/alerts/notify-channels/${id}`, data);
},
deleteNotifyChannel: async (id: number | string) => {
@@ -47,10 +47,10 @@ export const alertApi = {
getContacts: async () => {
return http.get('/alerts/contacts');
},
createContact: async ( data: any) => {
createContact: async ( data: Record<string, unknown>) => {
return http.post('/alerts/contacts', data);
},
updateContact: async (id: number | string, data: any) => {
updateContact: async (id: number | string, data: Record<string, unknown>) => {
return http.put(`/alerts/contacts/${id}`, data);
},
deleteContact: async (id: number | string) => {
@@ -60,10 +60,10 @@ export const alertApi = {
getContactGroups: async () => {
return http.get('/alerts/contact-groups');
},
createContactGroup: async ( data: any) => {
createContactGroup: async ( data: Record<string, unknown>) => {
return http.post('/alerts/contact-groups', data);
},
updateContactGroup: async (id: number | string, data: any) => {
updateContactGroup: async (id: number | string, data: Record<string, unknown>) => {
return http.put(`/alerts/contact-groups/${id}`, data);
},
deleteContactGroup: async (id: number | string) => {
+6 -6
View File
@@ -5,19 +5,19 @@ import { http } from '@/utils/request';
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),
create: ( data: Record<string, unknown>) => http.post('/prometheus-datasources', data),
update: (id: number | string, data: Record<string, unknown>) => 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),
testConnection: ( data: Record<string, unknown>) => http.post('/prometheus-datasources/test', data),
};
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),
create: ( data: Record<string, unknown>) => http.post('/zabbix-datasources', data),
update: (id: number | string, data: Record<string, unknown>) => 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),
testConnection: ( data: Record<string, unknown>) => http.post('/zabbix-datasources/test', data),
};
+10 -7
View File
@@ -1,10 +1,13 @@
// Grafana 仪表盘 API(暂无后端,返回空结果优雅降级) // Logan.Li
// Q1 类型安全: 对接 types/monitor.ts(GrafanaDashboard)
import type { GrafanaDashboard } from '@/types/monitor';
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 }),
};
getDashboards: async (): Promise<{ data: GrafanaDashboard[]; total: number }> => ({ data: [], total: 0 }),
getDatasources: async (): Promise<{ data: Record<string, unknown>[]; total: number }> => ({ data: [], total: 0 }),
createDashboard: async (_data: Partial<GrafanaDashboard>): Promise<{ success: boolean }> => ({ success: false }),
updateDashboard: async (_id: number | string, _data: Partial<GrafanaDashboard>): Promise<{ success: boolean }> => ({ success: false }),
deleteDashboard: async (_id: number | string): Promise<{ success: boolean }> => ({ success: false }),
createDatasource: async (_data: Record<string, unknown>): Promise<{ success: boolean }> => ({ success: false }),
};
+1 -1
View File
@@ -7,7 +7,7 @@ export const siteApi = {
return http.get('/site/stats');
},
getTasks: async () => {
return http.get<{ list: any[]; total: number }>('/site/tasks');
return http.get<{ list: unknown[]; 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);
+7 -4
View File
@@ -1,7 +1,10 @@
// 链路追踪 API(暂无后端,返回空结果优雅降级) // Logan.Li
// Q1 类型安全: 对接 types/monitor.ts(Trace / TraceSpan / TraceServiceMetrics)
import type { Trace, TraceSpan, TraceServiceMetrics } from '@/types/monitor';
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: [] } }),
};
getTraces: async (_params: Record<string, unknown>): Promise<{ data: Trace[]; total: number }> => ({ data: [], total: 0 }),
getServices: async (_timeRange: string): Promise<{ data: TraceServiceMetrics[]; total: number }> => ({ data: [], total: 0 }),
getTraceDetail: async (_traceId: string): Promise<{ data: { spans: TraceSpan[] } }> => ({ data: { spans: [] } }),
};
+155
View File
@@ -215,3 +215,158 @@ export interface PrometheusDatasource {
description: string;
created_at: string;
}
// ===== Zabbix 数据源 =====
export interface ZabbixDatasource {
id: number;
name: string;
url: string;
username: string;
password: string;
enabled: boolean;
is_default: boolean;
description: string;
created_at: string;
}
// ===== 告警静默规则 =====
export interface AlertSilence {
id: number;
name: string;
matchers: { key: string; value: string; is_regex?: boolean }[];
starts_at: string;
ends_at: string;
repeat_mode: 'onetime' | 'daily' | 'weekly';
enabled: boolean;
created_by: string;
created_at: string;
}
// ===== 输入 DTO(创建/更新用,枚举字段放宽为 string 以兼容表单)=====
export interface AlertRuleInput {
name?: string;
server_id?: number;
server_hostname?: string;
metric?: string;
operator?: string;
threshold?: number;
duration_sec?: number;
severity?: string;
enabled?: boolean;
notify_channels?: (number | string)[];
description?: string;
type?: string;
source?: string;
expression?: string;
duration?: number;
}
export interface AlertContactInput {
name?: string;
channel_type?: string;
webhook_url?: string;
phone?: string;
email?: string;
enabled?: boolean;
description?: string;
}
export interface AlertContactGroupInput {
name?: string;
description?: string;
contact_ids?: number[];
}
export interface AlertChannelInput {
name?: string;
type?: string;
config?: string;
enabled?: boolean;
description?: string;
}
export type PrometheusDatasourceInput = Record<string, unknown>;
export type ZabbixDatasourceInput = Record<string, unknown>;
export interface AlertSilenceInput {
name?: string;
description?: string;
matchers?: { key: string; value: string; is_regex?: boolean }[];
starts_at?: string;
ends_at?: string;
silence_type?: string;
start_time?: string;
end_time?: string;
repeat_mode?: string;
enabled?: boolean;
}
// ===== 健康探针输入 =====
export type HealthProbeInput = Partial<Omit<HealthProbe, 'id' | 'last_status' | 'last_checked_at'>>;
// ===== 链路追踪(mock 桩,与 TraceManager 消费者形状对齐)=====
export interface TraceSpan {
id: string;
spanId: string;
parentSpanId?: string;
serviceName: string;
operationName: string;
startTime: string;
duration: number;
status: 'success' | 'error' | 'pending';
kind: 'client' | 'server' | 'producer' | 'consumer' | 'internal';
tags: Record<string, string>;
logs: { timestamp: string; fields: Record<string, string> }[];
children: TraceSpan[];
}
export interface Trace {
id: string;
traceId: string;
serviceName: string;
operationName: string;
startTime: string;
duration: number;
status: 'success' | 'error' | 'pending';
spanCount: number;
tags: Record<string, string>;
spans?: TraceSpan[];
}
export interface TraceServiceMetrics {
serviceName: string;
requestCount: number;
errorRate: number;
avgDuration: number;
p95Duration: number;
p99Duration: number;
}
// ===== Grafana 仪表盘(mock 桩,与消费者形状对齐)=====
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export interface DashboardPanel {
id: string;
title: string;
type: string;
query: string;
datasource: string;
width: number;
height: number;
x: number;
y: number;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
options: any;
}
export interface GrafanaDashboard {
id: string;
name: string;
description: string;
datasource: string;
datasourceUrl: string;
panels: DashboardPanel[];
createdAt: string;
updatedAt: string;
createdBy: string;
isDefault: boolean;
}