refactor: 全局代码模块化重构 — 所有文件<700行

后端 handler 拆分:
- automation.go(1067→4文件), server.go(1011→5文件), ldap.go(815→3文件), user.go(704→2文件)

前端组件拆分:
- SystemManager(1782→569), AlertManager(1133→220), K8sClusters(1062→4文件)
- Dashboard(941→4文件), ServerManager(905→640), ApprovalFlow(830→548)
- AlertCenter(775→693), AIPredictiveAnalytics(760→670)
- CloudBilling(728→663), GrafanaDashboard(717→643), sidebar(726→689)

Mock 数据模块化:
- mocks/data.ts(2552行→barrel+11个domain模块)

新增 CLAUDE.md 项目全局开发规范

修复: AlertCenter/LogManager ListResponse.data→.list 类型不匹配
验证: go build ✅ + tsc --noEmit ✅ + npm run build ✅
This commit is contained in:
attacker committed 2026-06-15 01:32:15 +08:00
1 parent e8dbe65955
commit 73b5a48df9
37 files changed
+5148 -5237

No files matched your search

@@ -24,8 +24,9 @@ import { ScrollArea } from '@/components/ui/scroll-area';
import { toast } from 'sonner';
import { useConfirm } from '@/components/ui/confirm-dialog';
import { alertCenterApi, alertApi } from '@/services/api';
import { AlertDetailDialog, AlertSilenceDialog } from './AlertCenterDetail';
interface Alert {
export interface Alert {
id: string;
title: string;
description: string;
@@ -102,7 +103,7 @@ const AlertCenter: React.FC = () => {
setLoading(true);
try {
const res = await alertCenterApi.getAlerts();
const data = res.data || [];
const data = res.list || [];
setAlerts(data);
setStats({
firing: data.filter((a: Alert) => a.status === 'firing').length,
@@ -169,7 +170,7 @@ const AlertCenter: React.FC = () => {
const toggleRule = async (ruleId: string, enabled: boolean) => {
try {
await alertCenterApi.toggleRule(ruleId, enabled);
await alertCenterApi.toggleRule(ruleId);
setRules(rules.map(r => r.id === ruleId ? { ...r, enabled } : r));
toast.success('规则状态已更新');
} catch (error) {
@@ -616,101 +617,18 @@ const AlertCenter: React.FC = () => {
</TabsContent>
</Tabs>
{/* 告警详情对话框 */}
<Dialog open={detailOpen} onOpenChange={setDetailOpen}>
<DialogContent className="max-w-3xl">
<DialogHeader>
<DialogTitle className="flex items-center gap-2">
{selectedAlert?.title}
{selectedAlert && getSeverityBadge(selectedAlert.severity)}
</DialogTitle>
</DialogHeader>
{selectedAlert && (
<div className="space-y-4">
<div>
<Label className="text-muted-foreground">描述</Label>
<p className="mt-1">{selectedAlert.description}</p>
</div>
<div className="grid grid-cols-2 gap-4">
<div>
<Label className="text-muted-foreground">来源</Label>
<p className="font-medium">{selectedAlert.source}</p>
</div>
<div>
<Label className="text-muted-foreground">服务</Label>
<p className="font-medium">{selectedAlert.service}</p>
</div>
<div>
<Label className="text-muted-foreground">指标</Label>
<p className="font-medium">{selectedAlert.metric}</p>
</div>
<div>
<Label className="text-muted-foreground">当前值 / 阈值</Label>
<p className="font-medium">{selectedAlert.value} / {selectedAlert.threshold}</p>
</div>
<div>
<Label className="text-muted-foreground">开始时间</Label>
<p className="font-medium">{selectedAlert.startedAt}</p>
</div>
{selectedAlert.resolvedAt && (
<div>
<Label className="text-muted-foreground">解决时间</Label>
<p className="font-medium">{selectedAlert.resolvedAt}</p>
</div>
)}
</div>
<div>
<Label className="text-muted-foreground">标签</Label>
<div className="flex flex-wrap gap-2 mt-1">
{Object.entries(selectedAlert.labels).map(([k, v]) => (
<Badge key={k} variant="outline">{k}={v}</Badge>
))}
</div>
</div>
{selectedAlert.runbookUrl && (
<div>
<Label className="text-muted-foreground">处理手册</Label>
<a href={selectedAlert.runbookUrl} target="_blank" rel="noopener noreferrer" className="text-blue-500 hover:underline block mt-1">
查看处理手册 →
</a>
</div>
)}
</div>
)}
<DialogFooter>
<Button variant="outline" onClick={() => setDetailOpen(false)}>关闭</Button>
{selectedAlert?.status === 'firing' && (
<Button onClick={() => { handleAcknowledge(selectedAlert.id); setDetailOpen(false); }}>
<Check className="w-4 h-4 mr-2" />
确认告警
</Button>
)}
</DialogFooter>
</DialogContent>
</Dialog>
{/* 静默对话框 */}
<Dialog open={silenceOpen} onOpenChange={setSilenceOpen}>
<DialogContent>
<DialogHeader>
<DialogTitle>静默告警</DialogTitle>
<DialogDescription>选择静默持续时间</DialogDescription>
</DialogHeader>
<div className="space-y-2">
{['1h', '4h', '8h', '24h', '7d'].map((duration) => (
<Button
key={duration}
variant="outline"
className="w-full justify-between"
onClick={() => selectedAlert && handleSilence(selectedAlert.id, duration)}
>
<span>静默 {duration}</span>
<ChevronRight className="w-4 h-4" />
</Button>
))}
</div>
</DialogContent>
</Dialog>
<AlertDetailDialog
alert={selectedAlert}
open={detailOpen}
onOpenChange={setDetailOpen}
onAcknowledge={handleAcknowledge}
/>
<AlertSilenceDialog
alert={selectedAlert}
open={silenceOpen}
onOpenChange={setSilenceOpen}
onSilence={handleSilence}
/>
{/* 通知渠道创建/编辑对话框 */}
<Dialog open={channelDialogOpen} onOpenChange={setChannelDialogOpen}>