From 019a9d13f3b48dd6b5227b6f50b3be795b3bbd76 Mon Sep 17 00:00:00 2001 From: attacker Date: Wed, 17 Jun 2026 07:08:01 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E6=8B=86=E5=88=86SystemManager.tsx?= =?UTF-8?q?(569=E2=86=92308=E8=A1=8C)=E6=8F=90=E5=8F=96useLdapManagement?= =?UTF-8?q?=E8=87=AA=E5=AE=9A=E4=B9=89Hook=E5=B0=81=E8=A3=85=E5=85=A8?= =?UTF-8?q?=E9=83=A8LDAP=E7=8A=B6=E6=80=81=E4=B8=8E=E4=B8=9A=E5=8A=A1?= =?UTF-8?q?=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/system/SystemManager.tsx | 307 ++-------------- .../components/system/useLdapManagement.ts | 336 ++++++++++++++++++ 2 files changed, 359 insertions(+), 284 deletions(-) create mode 100644 frontend/src/components/system/useLdapManagement.ts diff --git a/frontend/src/components/system/SystemManager.tsx b/frontend/src/components/system/SystemManager.tsx index a2520d9..59517db 100644 --- a/frontend/src/components/system/SystemManager.tsx +++ b/frontend/src/components/system/SystemManager.tsx @@ -1,15 +1,15 @@ import { useState, useEffect } from 'react'; -import { toast } from 'sonner'; import { useConfirm } from '@/components/ui/confirm-dialog'; import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; import { Badge } from '@/components/ui/badge'; import { CheckCircle, XCircle, Users, Shield, FileCode, Settings } from 'lucide-react'; -import { userApi, ldapApi } from '@/services/api'; +import { userApi } from '@/services/api'; import type { Role } from '@/types'; import { SystemUserTab } from './SystemUserTab'; import { SystemRolesTab } from './SystemRolesTab'; import { SystemLogsTab } from './SystemLogsTab'; -import { SystemSettingsTab, type LdapFormData } from './SystemSettingsTab'; +import { SystemSettingsTab } from './SystemSettingsTab'; +import { useLdapManagement } from './useLdapManagement'; import type { UserFormData } from './UserFormDialog'; // 后端用户数据转换为前端兼容格式 @@ -49,48 +49,11 @@ export function SystemManager() { const [saving, setSaving] = useState(false); const [form, setForm] = useState({ ...emptyForm }); - // 批量导入弹窗 + // CSV 批量导入弹窗 const [importDialogOpen, setImportDialogOpen] = useState<'csv' | 'ldap' | null>(null); const [importPreview, setImportPreview] = useState([]); - const [importing, setImporting] = useState(false); const [importResult, setImportResult] = useState(null); - // LDAP 用户列表 - const [ldapUsers, setLdapUsers] = useState([]); - const [ldapSelected, setLdapSelected] = useState>(new Set()); - const [ldapLoading, setLdapLoading] = useState(false); - const [ldapImportOUs, setLdapImportOUs] = useState([]); - const [ldapImportOUDN, setLdapImportOUDN] = useState(''); - - // LDAP 配置 - const [ldapConfig, setLdapConfig] = useState(null); - const [ldapForm, setLdapForm] = useState({ - ldap_host: '', ldap_port: 389, use_ldaps: false, - admin_dn: '', admin_password: '', base_dn: '', search_filter: '', - }); - const [ldapSaving, setLdapSaving] = useState(false); - const [ldapTesting, setLdapTesting] = useState(false); - const [ldapTestResult, setLdapTestResult] = useState(null); - const [ldapMgmtOpen, setLdapMgmtOpen] = useState(false); - const [importFeedback, setImportFeedback] = useState(null); - const [importResultOpen, setImportResultOpen] = useState(false); - - // LDAP 账号管理 - const [ldapOUs, setLdapOUs] = useState([]); - const [selectedOUDN, setSelectedOUDN] = useState(''); - const [selectedLDAPUsers, setSelectedLDAPUsers] = useState([]); - const [createOUOpen, setCreateOUOpen] = useState(false); - const [createUserOpen, setCreateUserOpen] = useState(false); - const [ouForm, setOuForm] = useState({ ou_name: '', parent_dn: '', description: '' }); - const [newUser, setNewUser] = useState({ username: '', password: '', display_name: '', email: '', ou_dn: '' }); - const [ldapUserTestOpen, setLdapUserTestOpen] = useState(false); - const [ldapTestUser, setLdapTestUser] = useState(''); - const [ldapTestPass, setLdapTestPass] = useState(''); - const [ldapUserTesting, setLdapUserTesting] = useState(false); - const [ldapUserTestResult, setLdapUserTestResult] = useState(null); - const [editLdapUser, setEditLdapUser] = useState(null); - const [editLdapForm, setEditLdapForm] = useState({ cn: '', mail: '', phone: '', title: '' }); - const loadUsers = async () => { setLoading(true); try { @@ -105,16 +68,18 @@ export function SystemManager() { } }; + // LDAP 状态全部由 hook 管理(在 loadUsers 之后调用避免 TDZ) // Logan.Li + const ldap = useLdapManagement(loadUsers); + useEffect(() => { loadUsers(); - loadLdapConfig(); + ldap.loadLdapConfig(); }, []); // LDAP 导入 Dialog 打开时加载 OU 和用户 useEffect(() => { if (importDialogOpen === 'ldap') { - ldapApi.listOUs().then(ous => setLdapImportOUs(Array.isArray(ous) ? ous : [])).catch(() => {}); - loadLdapUsers(''); + ldap.loadImportDialogData(); } }, [importDialogOpen]); @@ -236,7 +201,7 @@ export function SystemManager() { // 执行 CSV 批量导入 const handleBatchImport = async () => { - setImporting(true); + ldap.setImporting(true); try { const res = await userApi.batchImport({ users: importPreview, skip_existing: true }); setImportResult(res); @@ -244,236 +209,10 @@ export function SystemManager() { } catch (error: any) { setImportResult({ code: 500, message: error?.message || '导入失败' }); } finally { - setImporting(false); + ldap.setImporting(false); } }; - // 加载 LDAP 用户列表 - const loadLdapUsers = async (ouDn?: string) => { - setLdapLoading(true); - try { - const res = await ldapApi.listUsers(ouDn); - setLdapUsers(Array.isArray(res) ? res : []); - setLdapSelected(new Set()); - } catch { - setLdapUsers([]); - } finally { - setLdapLoading(false); - } - }; - - // 执行 LDAP 导入 - const handleLdapImport = async () => { - let selected: any[] = []; - if (selectedLDAPUsers.length > 0) { - selected = ldapUsers.filter((u) => selectedLDAPUsers.includes(u.dn)); - } else { - selected = ldapUsers; // 没有选择则导入全部 - } - if (selected.length === 0) return; - setImporting(true); - try { - const mapped = selected.map((u) => ({ - username: u.uid || '', - nickname: u.cn || '', - email: u.mail || '', - })); - const res = await ldapApi.batchImport(mapped); - setImportFeedback(res?.message || `成功导入 ${selected.length} 个用户`); - setImportResultOpen(true); - setSelectedLDAPUsers([]); - await loadUsers(); - } catch (error: any) { - setImportFeedback('导入失败: ' + (error?.message || '未知错误')); - setImportResultOpen(true); - } finally { - setImporting(false); - } - }; - - // 加载 LDAP 配置 - const loadLdapConfig = async () => { - try { - const res = await ldapApi.getConfig(); - if (res && res.ldap_host) { - setLdapConfig(res); - setLdapForm({ - ldap_host: res.ldap_host || '', - ldap_port: res.ldap_port || 389, - use_ldaps: res.use_ldaps || false, - admin_dn: res.admin_dn || '', - admin_password: '', - base_dn: res.base_dn || '', - search_filter: res.search_filter || '', - }); - } - } catch { - // No config yet - } - }; - - // 保存 LDAP 配置 - const handleLdapSave = async () => { - setLdapSaving(true); - try { - await ldapApi.updateConfig(ldapForm); - await loadLdapConfig(); - } catch (error) { - console.error('Failed to save LDAP config:', error); - } finally { - setLdapSaving(false); - } - }; - - // 测试 LDAP 连接 - const handleLdapTest = async () => { - setLdapTesting(true); - setLdapTestResult(null); - try { - await ldapApi.updateConfig(ldapForm); - const res = await ldapApi.testConnection(); - setLdapTestResult(res?.message || (res?.success ? '连接成功' : '连接失败')); - } catch (error: any) { - setLdapTestResult(error?.message || '连接失败'); - } finally { - setLdapTesting(false); - } - }; - - // LDAP 账号管理函数 - const loadLdapOUs = async () => { - try { - const ous = await ldapApi.listOUs(); - setLdapOUs(ous || []); - // 同时加载根 DN 下的用户 - if (!selectedOUDN && ldapConfig?.base_dn) { - setSelectedOUDN(ldapConfig.base_dn); - await loadLdapOUUsers(ldapConfig.base_dn); - } - } catch (e) { console.error('loadOUs', e); } - }; - - const loadLdapOUUsers = async (ouDn?: string) => { - try { - const users = await ldapApi.listUsers(ouDn); - setLdapUsers(users || []); - } catch (e) { console.error('loadOUUsers', e); } - }; - - const handleCreateOU = async () => { - setLdapSaving(true); - try { - await ldapApi.createOU(ouForm); - setCreateOUOpen(false); - setOuForm({ ou_name: '', parent_dn: '', description: '' }); - await loadLdapOUs(); - } catch (e: any) { - const msg = e?.message || ''; - if (msg.includes('Already Exists') || msg.includes('68')) { - toast.error(`OU "${ouForm.ou_name}" 已存在,请使用其他名称`); - } else { - toast.error('创建失败: ' + msg); - } - } finally { setLdapSaving(false); } - }; - - const handleCreateLDAPUser = async () => { - setLdapSaving(true); - try { - await ldapApi.createUser({ ...newUser, ou_dn: newUser.ou_dn || selectedOUDN || ldapConfig?.base_dn }); - setCreateUserOpen(false); - setNewUser({ username: '', password: '', display_name: '', email: '', ou_dn: '' }); - await loadLdapOUUsers(selectedOUDN); - } catch (e: any) { toast.error(e?.message || '创建失败'); } - finally { setLdapSaving(false); } - }; - - const handleDeleteLDAPEntry = async (dn: string, silent = false) => { - if (!silent) { const ok = await confirm({ title: '删除 LDAP 条目', description: `确定删除 ${dn}?`, confirmText: '删除', variant: 'destructive' }); if (!ok) return; } - try { - await ldapApi.deleteUser(dn); - if (!silent) await loadLdapOUUsers(selectedOUDN); - } catch (e: any) { if (!silent) toast.error(e?.message || '删除失败'); } - }; - - const openEditLdapUser = (user: any) => { - setEditLdapUser(user); - setEditLdapForm({ cn: user.cn || '', mail: user.mail || '', phone: user.phone || '', title: user.title || '' }); - }; - - const handleUpdateLdapUser = async () => { - if (!editLdapUser) return; - try { - await ldapApi.updateUser({ dn: editLdapUser.dn, ...editLdapForm }); - setEditLdapUser(null); - await loadLdapOUUsers(selectedOUDN); - } catch (e: any) { toast.error(e?.message || '修改失败'); } - }; - - const handleLdapUserTest = async () => { - setLdapUserTesting(true); - setLdapUserTestResult(null); - try { - const res = await ldapApi.testConnection({ test_user: ldapTestUser, test_password: ldapTestPass }); - setLdapUserTestResult(res); - } catch (e: any) { - setLdapUserTestResult({ success: false, message: e?.message || '验证失败' }); - } finally { setLdapUserTesting(false); } - }; - - // Settings tab props (LDAP management pass-through) - const settingsTabProps = { - ldapConfig, - ldapForm, - setLdapForm, - ldapSaving, - ldapTesting, - ldapTestResult, - handleLdapSave, - handleLdapTest, - ldapMgmtOpen, - setLdapMgmtOpen, - ldapOUs, - selectedOUDN, - setSelectedOUDN, - ldapUsers, - selectedLDAPUsers, - setSelectedLDAPUsers, - loadLdapOUs, - loadLdapOUUsers, - handleLdapImport, - importing, - importFeedback, - importResultOpen, - setImportResultOpen, - createOUOpen, - setCreateOUOpen, - ouForm, - setOuForm, - handleCreateOU, - createUserOpen, - setCreateUserOpen, - newUser, - setNewUser, - handleCreateLDAPUser, - ldapUserTestOpen, - setLdapUserTestOpen, - ldapTestUser, - setLdapTestUser, - ldapTestPass, - setLdapTestPass, - ldapUserTesting, - ldapUserTestResult, - handleLdapUserTest, - editLdapUser, - setEditLdapUser, - editLdapForm, - setEditLdapForm, - handleUpdateLdapUser, - handleDeleteLDAPEntry, - openEditLdapUser, - }; - return (
{/* Page Header */} @@ -528,21 +267,21 @@ export function SystemManager() { setImportDialogOpen={setImportDialogOpen} importPreview={importPreview} setImportPreview={setImportPreview} - importing={importing} + importing={ldap.importing} importResult={importResult} setImportResult={setImportResult} handleCsvUpload={handleCsvUpload} handleBatchImport={handleBatchImport} - ldapUsers={ldapUsers} - ldapSelected={ldapSelected} - setLdapSelected={setLdapSelected} - ldapLoading={ldapLoading} - ldapImportOUs={ldapImportOUs} - ldapImportOUDN={ldapImportOUDN} - setLdapImportOUDN={setLdapImportOUDN} - loadLdapUsers={loadLdapUsers} - handleLdapImport={handleLdapImport} - setLdapUsers={setLdapUsers} + ldapUsers={ldap.ldapUsers} + ldapSelected={ldap.ldapSelected} + setLdapSelected={ldap.setLdapSelected} + ldapLoading={ldap.ldapLoading} + ldapImportOUs={ldap.ldapImportOUs} + ldapImportOUDN={ldap.ldapImportOUDN} + setLdapImportOUDN={ldap.setLdapImportOUDN} + loadLdapUsers={ldap.loadLdapUsers} + handleLdapImport={ldap.handleLdapImport} + setLdapUsers={ldap.setLdapUsers} /> @@ -561,7 +300,7 @@ export function SystemManager() { - +
diff --git a/frontend/src/components/system/useLdapManagement.ts b/frontend/src/components/system/useLdapManagement.ts new file mode 100644 index 0000000..c83aa03 --- /dev/null +++ b/frontend/src/components/system/useLdapManagement.ts @@ -0,0 +1,336 @@ +import { useState } from 'react'; +import { toast } from 'sonner'; +import { useConfirm } from '@/components/ui/confirm-dialog'; +import { ldapApi } from '@/services/api'; +import type { LdapFormData } from './SystemSettingsTab'; + +/** + * useLdapManagement — 封装 SystemManager 中所有 LDAP 相关状态与业务逻辑 + * + * 包含三大块: + * 1. LDAP 配置管理(连接信息读写 + 测试连接) + * 2. LDAP 账号管理(OU/用户 CRUD + 属性编辑 + 认证测试) + * 3. LDAP 用户导入(导入弹窗用:OU 下拉 + 用户列表 + 批量导入) + * + * 另外持有 `importing` 状态,供 CSV 批量导入与 LDAP 导入共用。 + * + * @param onUsersChanged 导入用户后回调(刷新本地用户列表) + * // Logan.Li + */ +export function useLdapManagement(onUsersChanged: () => Promise | void) { + const confirm = useConfirm(); + + // ===== LDAP 用户导入(用户管理 Tab 的导入弹窗用) ===== + const [ldapUsers, setLdapUsers] = useState([]); + const [ldapSelected, setLdapSelected] = useState>(new Set()); + const [ldapLoading, setLdapLoading] = useState(false); + const [ldapImportOUs, setLdapImportOUs] = useState([]); + const [ldapImportOUDN, setLdapImportOUDN] = useState(''); + + // ===== LDAP 配置 ===== + const [ldapConfig, setLdapConfig] = useState(null); + const [ldapForm, setLdapForm] = useState({ + ldap_host: '', ldap_port: 389, use_ldaps: false, + admin_dn: '', admin_password: '', base_dn: '', search_filter: '', + }); + const [ldapSaving, setLdapSaving] = useState(false); + const [ldapTesting, setLdapTesting] = useState(false); + const [ldapTestResult, setLdapTestResult] = useState(null); + const [ldapMgmtOpen, setLdapMgmtOpen] = useState(false); + const [importFeedback, setImportFeedback] = useState(null); + const [importResultOpen, setImportResultOpen] = useState(false); + + // ===== LDAP 账号管理 ===== + const [ldapOUs, setLdapOUs] = useState([]); + const [selectedOUDN, setSelectedOUDN] = useState(''); + const [selectedLDAPUsers, setSelectedLDAPUsers] = useState([]); + const [createOUOpen, setCreateOUOpen] = useState(false); + const [createUserOpen, setCreateUserOpen] = useState(false); + const [ouForm, setOuForm] = useState({ ou_name: '', parent_dn: '', description: '' }); + const [newUser, setNewUser] = useState({ username: '', password: '', display_name: '', email: '', ou_dn: '' }); + const [ldapUserTestOpen, setLdapUserTestOpen] = useState(false); + const [ldapTestUser, setLdapTestUser] = useState(''); + const [ldapTestPass, setLdapTestPass] = useState(''); + const [ldapUserTesting, setLdapUserTesting] = useState(false); + const [ldapUserTestResult, setLdapUserTestResult] = useState(null); + const [editLdapUser, setEditLdapUser] = useState(null); + const [editLdapForm, setEditLdapForm] = useState({ cn: '', mail: '', phone: '', title: '' }); + + // 导入进行中状态(CSV 与 LDAP 导入共用) + const [importing, setImporting] = useState(false); + + // ===== LDAP 配置相关 handler ===== + + /** 加载 LDAP 配置 // Logan.Li */ + const loadLdapConfig = async () => { + try { + const res = await ldapApi.getConfig(); + if (res && res.ldap_host) { + setLdapConfig(res); + setLdapForm({ + ldap_host: res.ldap_host || '', + ldap_port: res.ldap_port || 389, + use_ldaps: res.use_ldaps || false, + admin_dn: res.admin_dn || '', + admin_password: '', + base_dn: res.base_dn || '', + search_filter: res.search_filter || '', + }); + } + } catch { + // 暂无配置 + } + }; + + /** 保存 LDAP 配置 // Logan.Li */ + const handleLdapSave = async () => { + setLdapSaving(true); + try { + await ldapApi.updateConfig(ldapForm); + await loadLdapConfig(); + } catch (error) { + console.error('Failed to save LDAP config:', error); + } finally { + setLdapSaving(false); + } + }; + + /** 测试 LDAP 连接 // Logan.Li */ + const handleLdapTest = async () => { + setLdapTesting(true); + setLdapTestResult(null); + try { + await ldapApi.updateConfig(ldapForm); + const res = await ldapApi.testConnection(); + setLdapTestResult(res?.message || (res?.success ? '连接成功' : '连接失败')); + } catch (error: any) { + setLdapTestResult(error?.message || '连接失败'); + } finally { + setLdapTesting(false); + } + }; + + // ===== LDAP 账号管理相关 handler ===== + + /** 加载指定 OU 下的用户 // Logan.Li */ + const loadLdapOUUsers = async (ouDn?: string) => { + try { + const users = await ldapApi.listUsers(ouDn); + setLdapUsers(users || []); + } catch (e) { console.error('loadOUUsers', e); } + }; + + /** 加载 OU 列表(含根 DN 用户) // Logan.Li */ + const loadLdapOUs = async () => { + try { + const ous = await ldapApi.listOUs(); + setLdapOUs(ous || []); + // 同时加载根 DN 下的用户 + if (!selectedOUDN && ldapConfig?.base_dn) { + setSelectedOUDN(ldapConfig.base_dn); + await loadLdapOUUsers(ldapConfig.base_dn); + } + } catch (e) { console.error('loadOUs', e); } + }; + + /** 创建 OU // Logan.Li */ + const handleCreateOU = async () => { + setLdapSaving(true); + try { + await ldapApi.createOU(ouForm); + setCreateOUOpen(false); + setOuForm({ ou_name: '', parent_dn: '', description: '' }); + await loadLdapOUs(); + } catch (e: any) { + const msg = e?.message || ''; + if (msg.includes('Already Exists') || msg.includes('68')) { + toast.error(`OU "${ouForm.ou_name}" 已存在,请使用其他名称`); + } else { + toast.error('创建失败: ' + msg); + } + } finally { setLdapSaving(false); } + }; + + /** 创建 LDAP 用户 // Logan.Li */ + const handleCreateLDAPUser = async () => { + setLdapSaving(true); + try { + await ldapApi.createUser({ ...newUser, ou_dn: newUser.ou_dn || selectedOUDN || ldapConfig?.base_dn }); + setCreateUserOpen(false); + setNewUser({ username: '', password: '', display_name: '', email: '', ou_dn: '' }); + await loadLdapOUUsers(selectedOUDN); + } catch (e: any) { toast.error(e?.message || '创建失败'); } + finally { setLdapSaving(false); } + }; + + /** 删除 LDAP 条目 // Logan.Li */ + const handleDeleteLDAPEntry = async (dn: string, silent = false) => { + if (!silent) { + const ok = await confirm({ title: '删除 LDAP 条目', description: `确定删除 ${dn}?`, confirmText: '删除', variant: 'destructive' }); + if (!ok) return; + } + try { + await ldapApi.deleteUser(dn); + if (!silent) await loadLdapOUUsers(selectedOUDN); + } catch (e: any) { if (!silent) toast.error(e?.message || '删除失败'); } + }; + + /** 打开 LDAP 用户编辑 // Logan.Li */ + const openEditLdapUser = (user: any) => { + setEditLdapUser(user); + setEditLdapForm({ cn: user.cn || '', mail: user.mail || '', phone: user.phone || '', title: user.title || '' }); + }; + + /** 更新 LDAP 用户属性 // Logan.Li */ + const handleUpdateLdapUser = async () => { + if (!editLdapUser) return; + try { + await ldapApi.updateUser({ dn: editLdapUser.dn, ...editLdapForm }); + setEditLdapUser(null); + await loadLdapOUUsers(selectedOUDN); + } catch (e: any) { toast.error(e?.message || '修改失败'); } + }; + + /** LDAP 账号验证测试 // Logan.Li */ + const handleLdapUserTest = async () => { + setLdapUserTesting(true); + setLdapUserTestResult(null); + try { + const res = await ldapApi.testConnection({ test_user: ldapTestUser, test_password: ldapTestPass }); + setLdapUserTestResult(res); + } catch (e: any) { + setLdapUserTestResult({ success: false, message: e?.message || '验证失败' }); + } finally { setLdapUserTesting(false); } + }; + + // ===== LDAP 用户导入相关 handler ===== + + /** 加载 LDAP 用户列表(导入弹窗用) // Logan.Li */ + const loadLdapUsers = async (ouDn?: string) => { + setLdapLoading(true); + try { + const res = await ldapApi.listUsers(ouDn); + setLdapUsers(Array.isArray(res) ? res : []); + setLdapSelected(new Set()); + } catch { + setLdapUsers([]); + } finally { + setLdapLoading(false); + } + }; + + /** 执行 LDAP 批量导入 // Logan.Li */ + const handleLdapImport = async () => { + let selected: any[] = []; + if (selectedLDAPUsers.length > 0) { + selected = ldapUsers.filter((u) => selectedLDAPUsers.includes(u.dn)); + } else { + selected = ldapUsers; // 没有选择则导入全部 + } + if (selected.length === 0) return; + setImporting(true); + try { + const mapped = selected.map((u) => ({ + username: u.uid || '', + nickname: u.cn || '', + email: u.mail || '', + })); + const res = await ldapApi.batchImport(mapped); + setImportFeedback(res?.message || `成功导入 ${selected.length} 个用户`); + setImportResultOpen(true); + setSelectedLDAPUsers([]); + await onUsersChanged(); + } catch (error: any) { + setImportFeedback('导入失败: ' + (error?.message || '未知错误')); + setImportResultOpen(true); + } finally { + setImporting(false); + } + }; + + /** LDAP 导入弹窗打开时加载 OU 和用户列表 // Logan.Li */ + const loadImportDialogData = () => { + ldapApi.listOUs() + .then((ous) => setLdapImportOUs(Array.isArray(ous) ? ous : [])) + .catch(() => {}); + loadLdapUsers(''); + }; + + // ===== 构造传递给 SystemSettingsTab 的 props 对象 ===== + const settingsTabProps = { + ldapConfig, + ldapForm, + setLdapForm, + ldapSaving, + ldapTesting, + ldapTestResult, + handleLdapSave, + handleLdapTest, + ldapMgmtOpen, + setLdapMgmtOpen, + ldapOUs, + selectedOUDN, + setSelectedOUDN, + ldapUsers, + selectedLDAPUsers, + setSelectedLDAPUsers, + loadLdapOUs, + loadLdapOUUsers, + handleLdapImport, + importing, + importFeedback, + importResultOpen, + setImportResultOpen, + createOUOpen, + setCreateOUOpen, + ouForm, + setOuForm, + handleCreateOU, + createUserOpen, + setCreateUserOpen, + newUser, + setNewUser, + handleCreateLDAPUser, + ldapUserTestOpen, + setLdapUserTestOpen, + ldapTestUser, + setLdapTestUser, + ldapTestPass, + setLdapTestPass, + ldapUserTesting, + ldapUserTestResult, + handleLdapUserTest, + editLdapUser, + setEditLdapUser, + editLdapForm, + setEditLdapForm, + handleUpdateLdapUser, + handleDeleteLDAPEntry, + openEditLdapUser, + }; + + return { + // LDAP 用户导入(用户管理 Tab) + ldapUsers, + setLdapUsers, + ldapSelected, + setLdapSelected, + ldapLoading, + ldapImportOUs, + ldapImportOUDN, + setLdapImportOUDN, + loadLdapUsers, + handleLdapImport, + loadImportDialogData, + // 导入状态(CSV + LDAP 共用) + importing, + setImporting, + importFeedback, + importResultOpen, + setImportResultOpen, + // 初始化 + loadLdapConfig, + // 系统设置 Tab + settingsTabProps, + }; +}