'use client' import { useState, useEffect } from 'react' import apiClient from '@/lib/api-client' import AlertDialog from '@/components/ui/AlertDialog' import ConfirmDialog from '@/components/ui/ConfirmDialog' import DepartmentFormModal from './DepartmentFormModal' interface Department { id: number tenant_id: number parent_id: number | null code: string name: string name_en: string | null depth: number email_domain: string | null effective_email_domain: string | null email_address: string | null email_quota_mb: number description: string | null is_active: boolean member_count: number } interface ParentDepartment { id: number name: string depth: number } export default function DepartmentsPage() { const [departments, setDepartments] = useState([]) const [parentDepartments, setParentDepartments] = useState([]) const [loading, setLoading] = useState(true) const [showModal, setShowModal] = useState(false) const [editingDepartment, setEditingDepartment] = useState(null) // 篩選條件 const [filterDepth, setFilterDepth] = useState('all') const [filterActive, setFilterActive] = useState('all') const [filterParent, setFilterParent] = useState('all') // 分頁 const [currentPage, setCurrentPage] = useState(1) const [pageSize, setPageSize] = useState(5) // 對話框 const [alertDialog, setAlertDialog] = useState<{ isOpen: boolean title: string message: string type: 'info' | 'warning' | 'error' | 'success' }>({ isOpen: false, title: '', message: '', type: 'info', }) const [confirmDialog, setConfirmDialog] = useState<{ isOpen: boolean title: string message: string onConfirm: () => void }>({ isOpen: false, title: '', message: '', onConfirm: () => {}, }) useEffect(() => { loadDepartments() loadParentDepartments() }, []) const loadDepartments = async () => { try { setLoading(true) const response: any = await apiClient.get('/departments?include_inactive=true') setDepartments(response || []) } catch (error: any) { console.error('Failed to load departments:', error) setAlertDialog({ isOpen: true, title: '載入失敗', message: error.response?.data?.detail || '無法載入部門資料', type: 'error', }) } finally { setLoading(false) } } const loadParentDepartments = async () => { try { // 載入所有部門作為上層部門選項 const response: any = await apiClient.get('/departments?include_inactive=false') setParentDepartments(response || []) } catch (error) { console.error('Failed to load parent departments:', error) } } const handleAdd = () => { setEditingDepartment(null) setShowModal(true) } const handleEdit = (department: Department) => { setEditingDepartment(department) setShowModal(true) } const handleDelete = (department: Department) => { setConfirmDialog({ isOpen: true, title: '確認刪除', message: `確定要刪除部門「${department.name}」嗎?此操作無法復原。`, onConfirm: async () => { try { await apiClient.delete(`/departments/${department.id}`) loadDepartments() setAlertDialog({ isOpen: true, title: '刪除成功', message: '部門已成功刪除', type: 'success', }) } catch (error: any) { setAlertDialog({ isOpen: true, title: '刪除失敗', message: error.response?.data?.detail || '刪除失敗,請稍後再試', type: 'error', }) } setConfirmDialog({ ...confirmDialog, isOpen: false }) }, }) } const handleToggleActive = async (department: Department) => { try { await apiClient.patch(`/departments/${department.id}`, { is_active: !department.is_active, }) loadDepartments() setAlertDialog({ isOpen: true, title: '切換成功', message: `部門已${!department.is_active ? '啟用' : '停用'}`, type: 'success', }) } catch (error: any) { setAlertDialog({ isOpen: true, title: '切換失敗', message: error.response?.data?.detail || '切換狀態失敗', type: 'error', }) } } // 篩選邏輯 const filteredDepartments = departments.filter(dept => { if (filterDepth !== 'all' && dept.depth !== parseInt(filterDepth)) return false if (filterActive === 'active' && !dept.is_active) return false if (filterActive === 'inactive' && dept.is_active) return false if (filterParent === 'top' && dept.parent_id !== null) return false if (filterParent !== 'all' && filterParent !== 'top' && dept.parent_id !== parseInt(filterParent)) return false return true }) // 分頁邏輯 const totalPages = Math.ceil(filteredDepartments.length / pageSize) const startIndex = (currentPage - 1) * pageSize const paginatedDepartments = filteredDepartments.slice(startIndex, startIndex + pageSize) const getParentName = (parentId: number | null) => { if (!parentId) return '-' const parent = departments.find(d => d.id === parentId) return parent ? parent.name : '-' } const getDepthLabel = (depth: number) => { return `第${depth + 1}層` } return (
{/* Header */}

部門資料維護

管理組織架構與部門資料

{/* Filters */}
{/* Pagination Controls */}
每頁顯示
共 {filteredDepartments.length} 筆資料
{/* DataTable */}
{loading ? ( ) : paginatedDepartments.length === 0 ? ( ) : ( paginatedDepartments.map((dept) => ( )) )}
ID 層級 部門代碼 部門名稱 上層部門 郵件網域 成員數 啟用 操作
載入中...
尚無部門資料
{dept.id} {getDepthLabel(dept.depth)} {dept.code} {dept.name} {getParentName(dept.parent_id)} {dept.effective_email_domain || '-'} {dept.member_count || 0}
{/* Pagination */} {totalPages > 1 && (
顯示第 {startIndex + 1} - {Math.min(startIndex + pageSize, filteredDepartments.length)} 筆,共 {filteredDepartments.length} 筆
{[...Array(totalPages)].map((_, i) => ( ))}
)}
{/* Modal */} {showModal && ( setShowModal(false)} onSave={(isEdit: boolean) => { setShowModal(false) loadDepartments() loadParentDepartments() setAlertDialog({ isOpen: true, title: '儲存成功', message: `部門已成功${isEdit ? '更新' : '新增'}`, type: 'success', }) }} /> )} {/* Alert Dialog */} setAlertDialog({ ...alertDialog, isOpen: false })} /> {/* Confirm Dialog */} setConfirmDialog({ ...confirmDialog, isOpen: false })} />
) }