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

@@ -0,0 +1,340 @@
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Switch } from '@/components/ui/switch';
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from '@/components/ui/select';
import { Lock, History, Key, Settings, Network, RefreshCw, Loader2 } from 'lucide-react';
import { LdapManagementSection } from './LdapManagementSection';
export interface LdapFormData {
ldap_host: string;
ldap_port: number;
use_ldaps: boolean;
admin_dn: string;
admin_password: string;
base_dn: string;
search_filter: string;
}
interface SystemSettingsTabProps {
// LDAP config
ldapConfig: any;
ldapForm: LdapFormData;
setLdapForm: React.Dispatch<React.SetStateAction<LdapFormData>>;
ldapSaving: boolean;
ldapTesting: boolean;
ldapTestResult: string | null;
handleLdapSave: () => void;
handleLdapTest: () => void;
// LDAP management - pass-through to LdapManagementSection
ldapMgmtOpen: boolean;
setLdapMgmtOpen: (v: boolean) => void;
ldapOUs: any[];
selectedOUDN: string;
setSelectedOUDN: (v: string) => void;
ldapUsers: any[];
selectedLDAPUsers: string[];
setSelectedLDAPUsers: (v: string[]) => void;
loadLdapOUs: () => void;
loadLdapOUUsers: (ouDn?: string) => void;
handleLdapImport: () => void;
importing: boolean;
importFeedback: string | null;
importResultOpen: boolean;
setImportResultOpen: (v: boolean) => void;
createOUOpen: boolean;
setCreateOUOpen: (v: boolean) => void;
ouForm: { ou_name: string; parent_dn: string; description: string };
setOuForm: React.Dispatch<React.SetStateAction<{ ou_name: string; parent_dn: string; description: string }>>;
handleCreateOU: () => void;
createUserOpen: boolean;
setCreateUserOpen: (v: boolean) => void;
newUser: { username: string; password: string; display_name: string; email: string; ou_dn: string };
setNewUser: React.Dispatch<React.SetStateAction<{ username: string; password: string; display_name: string; email: string; ou_dn: string }>>;
handleCreateLDAPUser: () => void;
ldapUserTestOpen: boolean;
setLdapUserTestOpen: (v: boolean) => void;
ldapTestUser: string;
setLdapTestUser: (v: string) => void;
ldapTestPass: string;
setLdapTestPass: (v: string) => void;
ldapUserTesting: boolean;
ldapUserTestResult: any;
handleLdapUserTest: () => void;
editLdapUser: any | null;
setEditLdapUser: (u: any | null) => void;
editLdapForm: { cn: string; mail: string; phone: string; title: string };
setEditLdapForm: React.Dispatch<React.SetStateAction<{ cn: string; mail: string; phone: string; title: string }>>;
handleUpdateLdapUser: () => void;
handleDeleteLDAPEntry: (dn: string, silent?: boolean) => void;
openEditLdapUser: (user: any) => void;
}
export function SystemSettingsTab(props: SystemSettingsTabProps) {
const {
ldapConfig,
ldapForm,
setLdapForm,
ldapSaving,
ldapTesting,
ldapTestResult,
handleLdapSave,
handleLdapTest,
} = props;
return (
<>
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
<Card className="bg-slate-900 border-slate-800">
<CardHeader>
<CardTitle className="text-slate-100 flex items-center gap-2">
<Lock className="h-5 w-5 text-blue-400" />
安全设置
</CardTitle>
<CardDescription className="text-slate-500">密码策略与登录安全</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<div className="flex items-center justify-between">
<div>
<p className="text-sm font-medium text-slate-200">强制密码复杂度</p>
<p className="text-xs text-slate-500">要求密码包含大小写字母、数字和特殊字符</p>
</div>
<Switch defaultChecked className="data-[state=checked]:bg-blue-600" />
</div>
<div className="flex items-center justify-between">
<div>
<p className="text-sm font-medium text-slate-200">登录失败锁定</p>
<p className="text-xs text-slate-500">连续5次登录失败锁定账户30分钟</p>
</div>
<Switch defaultChecked className="data-[state=checked]:bg-blue-600" />
</div>
<div className="flex items-center justify-between">
<div>
<p className="text-sm font-medium text-slate-200">双因素认证</p>
<p className="text-xs text-slate-500">启用后需要手机验证码登录</p>
</div>
<Switch className="data-[state=checked]:bg-blue-600" />
</div>
</CardContent>
</Card>
<Card className="bg-slate-900 border-slate-800">
<CardHeader>
<CardTitle className="text-slate-100 flex items-center gap-2">
<History className="h-5 w-5 text-emerald-400" />
审计设置
</CardTitle>
<CardDescription className="text-slate-500">操作日志与审计策略</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<div className="flex items-center justify-between">
<div>
<p className="text-sm font-medium text-slate-200">记录所有操作</p>
<p className="text-xs text-slate-500">记录用户的所有操作行为</p>
</div>
<Switch defaultChecked className="data-[state=checked]:bg-blue-600" />
</div>
<div className="flex items-center justify-between">
<div>
<p className="text-sm font-medium text-slate-200">日志保留时间</p>
<p className="text-xs text-slate-500">操作日志保留180天</p>
</div>
<Select defaultValue="180">
<SelectTrigger className="w-32 h-8 bg-slate-800 border-slate-700 text-slate-200">
<SelectValue />
</SelectTrigger>
<SelectContent className="bg-slate-800 border-slate-700">
<SelectItem value="30">30天</SelectItem>
<SelectItem value="90">90天</SelectItem>
<SelectItem value="180">180天</SelectItem>
<SelectItem value="365">1年</SelectItem>
</SelectContent>
</Select>
</div>
</CardContent>
</Card>
<Card className="bg-slate-900 border-slate-800">
<CardHeader>
<CardTitle className="text-slate-100 flex items-center gap-2">
<Key className="h-5 w-5 text-amber-400" />
会话设置
</CardTitle>
<CardDescription className="text-slate-500">会话超时与Token配置</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<div className="flex items-center justify-between">
<div>
<p className="text-sm font-medium text-slate-200">会话超时时间</p>
<p className="text-xs text-slate-500">用户无操作30分钟后自动登出</p>
</div>
<Select defaultValue="30">
<SelectTrigger className="w-32 h-8 bg-slate-800 border-slate-700 text-slate-200">
<SelectValue />
</SelectTrigger>
<SelectContent className="bg-slate-800 border-slate-700">
<SelectItem value="15">15分钟</SelectItem>
<SelectItem value="30">30分钟</SelectItem>
<SelectItem value="60">1小时</SelectItem>
<SelectItem value="120">2小时</SelectItem>
</SelectContent>
</Select>
</div>
<div className="flex items-center justify-between">
<div>
<p className="text-sm font-medium text-slate-200">单点登录</p>
<p className="text-xs text-slate-500">同一账号只能在一个设备登录</p>
</div>
<Switch className="data-[state=checked]:bg-blue-600" />
</div>
</CardContent>
</Card>
<Card className="bg-slate-900 border-slate-800">
<CardHeader>
<CardTitle className="text-slate-100 flex items-center gap-2">
<Settings className="h-5 w-5 text-purple-400" />
系统信息
</CardTitle>
<CardDescription className="text-slate-500">版本与系统状态</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<div className="flex items-center justify-between">
<span className="text-sm text-slate-400">系统版本</span>
<span className="text-sm text-slate-200">v2.5.1</span>
</div>
<div className="flex items-center justify-between">
<span className="text-sm text-slate-400">运行时间</span>
<span className="text-sm text-slate-200">30天 12小时</span>
</div>
</CardContent>
</Card>
</div>
{/* LDAP 配置 */}
<Card className="bg-slate-900 border-slate-800 mt-4">
<CardHeader>
<div className="flex items-center justify-between">
<div>
<CardTitle className="text-slate-100 flex items-center gap-2">
<Network className="h-5 w-5 text-cyan-400" />
LDAP / Active Directory
</CardTitle>
<CardDescription className="text-slate-500 mt-1">配置 LDAP 服务器,实现统一身份认证</CardDescription>
</div>
</div>
</CardHeader>
<CardContent>
<div className="grid grid-cols-2 gap-4">
<div className="space-y-1.5">
<label className="text-xs text-slate-500">LDAP 服务器地址</label>
<Input
value={ldapForm.ldap_host}
onChange={(e) => setLdapForm({ ...ldapForm, ldap_host: e.target.value })}
className="bg-slate-800/50 border-slate-700 text-slate-200 placeholder:text-slate-600"
placeholder="ldap.example.com"
/>
</div>
<div className="space-y-1.5">
<label className="text-xs text-slate-500">端口</label>
<Input
type="number"
value={ldapForm.ldap_port}
onChange={(e) => setLdapForm({ ...ldapForm, ldap_port: Number(e.target.value) })}
className="bg-slate-800/50 border-slate-700 text-slate-200"
placeholder="389"
/>
</div>
<div className="space-y-1.5 col-span-2">
<label className="text-xs text-slate-500">Base DN(用户搜索基础)</label>
<Input
value={ldapForm.base_dn}
onChange={(e) => setLdapForm({ ...ldapForm, base_dn: e.target.value })}
className="bg-slate-800/50 border-slate-700 text-slate-200 placeholder:text-slate-600"
placeholder="ou=users,dc=example,dc=com"
/>
</div>
<div className="space-y-1.5">
<label className="text-xs text-slate-500">管理员 Bind DN</label>
<Input
value={ldapForm.admin_dn}
onChange={(e) => setLdapForm({ ...ldapForm, admin_dn: e.target.value })}
className="bg-slate-800/50 border-slate-700 text-slate-200 placeholder:text-slate-600"
placeholder="cn=admin,dc=example,dc=com"
/>
</div>
<div className="space-y-1.5">
<label className="text-xs text-slate-500">管理员密码 {ldapConfig && '(留空不修改)'}</label>
<Input
type="password"
value={ldapForm.admin_password}
onChange={(e) => setLdapForm({ ...ldapForm, admin_password: e.target.value })}
className="bg-slate-800/50 border-slate-700 text-slate-200 placeholder:text-slate-600"
placeholder="******"
/>
</div>
<div className="space-y-1.5 col-span-2">
<label className="text-xs text-slate-500">搜索过滤器(可选,用 %s 代表用户名)</label>
<Input
value={ldapForm.search_filter}
onChange={(e) => setLdapForm({ ...ldapForm, search_filter: e.target.value })}
className="bg-slate-800/50 border-slate-700 text-slate-200 placeholder:text-slate-600"
placeholder="(uid=%s)"
/>
</div>
<div className="flex items-center gap-2 col-span-2">
<Switch
checked={ldapForm.use_ldaps}
onCheckedChange={(v) => setLdapForm({ ...ldapForm, use_ldaps: v })}
className="data-[state=checked]:bg-blue-600"
/>
<span className="text-sm text-slate-300">启用 LDAPS(SSL 加密)</span>
</div>
</div>
{/* 测试/保存按钮 */}
<div className="flex items-center gap-3 mt-4 pt-4 border-t border-slate-800">
{ldapTestResult && (
<span className={`text-xs ${ldapTestResult.includes('成功') ? 'text-emerald-400' : 'text-red-400'}`}>
{ldapTestResult}
</span>
)}
<div className="flex items-center gap-2 ml-auto">
<Button
variant="outline"
size="sm"
className="border-slate-700 text-slate-300"
onClick={handleLdapTest}
disabled={ldapTesting}
>
{ldapTesting ? <Loader2 className="h-3.5 w-3.5 mr-1 animate-spin" /> : <RefreshCw className="h-3.5 w-3.5 mr-1" />}
测试连接
</Button>
<Button
size="sm"
className="bg-blue-600 hover:bg-blue-700 text-white"
onClick={handleLdapSave}
disabled={ldapSaving}
>
{ldapSaving ? '保存中...' : '保存配置'}
</Button>
</div>
</div>
</CardContent>
</Card>
{/* LDAP 账号管理 - 可折叠 */}
{ldapConfig && (
<div className="mt-4">
<LdapManagementSection {...props} />
</div>
)}
</>
);
}