import { useState, useEffect } from "react"; import { useSearchParams } from "react-router-dom"; 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 { PageTabs } from "@/components/layout/PageTabs"; import { LdapManagementSection } from "./LdapManagementSection"; import type { JsonData } from "@/types/common"; import { useTranslation } from "react-i18next"; import i18n from "@/i18n"; import { useUserStore } from "@/store"; // 系统设置子 Tab:通用 / 安全 / LDAP // Logan.Li const SETTINGS_TABS = [ { id: "general", label: i18n.t("system.settingsGeneral") }, { id: "security", label: i18n.t("system.settingsSecurity") }, { id: "ldap", label: "LDAP" }, ] as const; type SettingsSubTab = (typeof SETTINGS_TABS)[number]["id"]; export interface LdapFormData { ldap_host: string; ldap_port: number; use_ldaps: boolean; admin_dn: string; admin_password: string; base_dn: string; search_filter: string; } export interface SystemSettingsTabProps { // 审计策略 // Logan.Li auditRetentionDays: string; setAuditRetentionDays: (v: string) => void; auditRecordAll: boolean; setAuditRecordAll: (v: boolean) => void; sessionWatermarkEnabled: boolean; setSessionWatermarkEnabled: (v: boolean) => void; sessionRecordEnabled: boolean; setSessionRecordEnabled: (v: boolean) => void; clipboardEnabled: boolean; setClipboardEnabled: (v: boolean) => void; fileUploadEnabled: boolean; setFileUploadEnabled: (v: boolean) => void; fileDownloadEnabled: boolean; setFileDownloadEnabled: (v: boolean) => void; commandPolicyEnabled: boolean; setCommandPolicyEnabled: (v: boolean) => void; approvalRequired: boolean; setApprovalRequired: (v: boolean) => void; auditLoading: boolean; auditApplying: boolean; handleAuditApply: () => void; auditLastCleanupText: string | null; auditRetentionOptions: number[]; // LDAP config ldapConfig: unknown; ldapForm: LdapFormData; setLdapForm: React.Dispatch>; ldapSaving: boolean; ldapTesting: boolean; ldapTestResult: string | null; handleLdapSave: () => void; handleLdapTest: () => void; // LDAP management - pass-through to LdapManagementSection ldapMgmtOpen: boolean; setLdapMgmtOpen: (v: boolean) => void; ldapOUs: unknown[]; selectedOUDN: string; setSelectedOUDN: (v: string) => void; ldapUsers: unknown[]; selectedLDAPUsers: string[]; setSelectedLDAPUsers: (v: string[]) => void; loadLdapOUs: () => void; loadLdapOUUsers: (ouDn?: string) => void; handleLdapImport: (opts?: { importAll?: boolean }) => void | Promise; 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: unknown; handleLdapUserTest: () => void; editLdapUser: JsonData | null; setEditLdapUser: (u: JsonData | 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: JsonData) => void; } export function SystemSettingsTab(props: SystemSettingsTabProps) { const { t } = useTranslation(); const currentUsername = useUserStore( (state) => state.user?.username || "admin", ); const { auditRetentionDays, setAuditRetentionDays, auditRecordAll, setAuditRecordAll, sessionWatermarkEnabled, setSessionWatermarkEnabled, sessionRecordEnabled, setSessionRecordEnabled, clipboardEnabled, setClipboardEnabled, fileUploadEnabled, setFileUploadEnabled, fileDownloadEnabled, setFileDownloadEnabled, commandPolicyEnabled, setCommandPolicyEnabled, approvalRequired, setApprovalRequired, auditLoading, auditApplying, handleAuditApply, auditLastCleanupText, auditRetentionOptions, ldapConfig, ldapForm, setLdapForm, ldapSaving, ldapTesting, ldapTestResult, handleLdapSave, handleLdapTest, } = props; const [searchParams, setSearchParams] = useSearchParams(); const tabFromUrl = searchParams.get("tab") as SettingsSubTab | null; const [subTab, setSubTab] = useState( SETTINGS_TABS.some((t) => t.id === tabFromUrl) ? tabFromUrl! : "general", ); useEffect(() => { if ( tabFromUrl && SETTINGS_TABS.some((t) => t.id === tabFromUrl) && tabFromUrl !== subTab ) { setSubTab(tabFromUrl); } }, [tabFromUrl, subTab]); const changeSubTab = (id: string) => { const next = id as SettingsSubTab; setSubTab(next); const params = new URLSearchParams(searchParams); if (next === "general") params.delete("tab"); else params.set("tab", next); setSearchParams(params, { replace: true }); }; return (
{subTab === "general" && (
{t("system.audit")} {t("system.auditSettingsDesc")}

{t("system.recordAllOps")}

{t("system.recordAllOpsDesc")}

{t("system.logRetention")}

{t("system.logRetentionHint")}

{auditLastCleanupText && (

{auditLastCleanupText}

)}
{t("system.systemInfo")} {t("system.systemInfoDesc")}
{t("system.systemVersion")} v2.5.1
{t("system.uptime")} {t("system.uptimeValue")}
)} {subTab === "security" && (
{t("system.security")} {t("system.securityDesc")}

{t("system.forcePasswordComplexity")}

{t("system.forcePasswordComplexityDesc")}

{t("system.loginLockout")}

{t("system.loginLockoutDesc")}

{t("system.twoFactor")}

{t("system.twoFactorDesc")}

{t("system.sessionSettings")} {t("system.sessionSettingsDesc")}

{t("system.sessionWatermark")}

{t("system.sessionWatermarkDesc", { user: currentUsername, })}

{currentUsername} {currentUsername} {currentUsername} {currentUsername}

{t("system.sessionRecordEnabled")}

{t("system.sessionRecordEnabledDesc")}

{t("system.clipboardEnabled")}

{t("system.clipboardEnabledDesc")}

{t("system.fileUploadEnabled")}

{t("system.fileUploadEnabledDesc")}

{t("system.fileDownloadEnabled")}

{t("system.fileDownloadEnabledDesc")}

{t("system.commandPolicyEnabled")}

{t("system.commandPolicyEnabledDesc")}

{t("system.approvalRequired")}

{t("system.approvalRequiredDesc")}

{t("system.sessionTimeoutTime")}

{t("system.sessionTimeoutDesc")}

{t("system.sso")}

{t("system.singleSignOnDesc")}

)} {subTab === "ldap" && ( <>
LDAP / Active Directory {t("system.ldapConfigHint")}
setLdapForm({ ...ldapForm, ldap_host: e.target.value }) } className="dg-input" placeholder="ldap.example.com" />
setLdapForm({ ...ldapForm, ldap_port: Number(e.target.value), }) } className="dg-input" placeholder="389" />
setLdapForm({ ...ldapForm, base_dn: e.target.value }) } className="dg-input" placeholder="ou=users,dc=example,dc=com" />
setLdapForm({ ...ldapForm, admin_dn: e.target.value }) } className="dg-input" placeholder="cn=admin,dc=example,dc=com" />
setLdapForm({ ...ldapForm, admin_password: e.target.value, }) } className="dg-input" placeholder="******" />
setLdapForm({ ...ldapForm, search_filter: e.target.value, }) } className="dg-input" placeholder="(uid=%s)" />
setLdapForm({ ...ldapForm, use_ldaps: v }) } className="data-[state=checked]:bg-blue-600" /> {t("system.enableLdaps")}
{/* 测试/保存按钮 */}
{ldapTestResult && ( {ldapTestResult} )}
{ldapConfig && } )}
); }