'use client' import { useEffect, useState } from 'react' import { useSession } from 'next-auth/react' import { useRouter } from 'next/navigation' interface Employee { id: number employee_id: string username_base: string legal_name: string english_name: string | null phone: string | null mobile: string | null hire_date: string termination_date: string | null status: string identities_count?: number has_network_drive?: boolean // Phase 2.3: 主要身份資訊 primary_business_unit?: string | null primary_department?: string | null primary_job_title?: string | null } interface EmployeeListResponse { total: number page: number page_size: number total_pages: number items: Employee[] } export default function EmployeesPage() { const { data: session, status } = useSession() const router = useRouter() const [employees, setEmployees] = useState([]) const [loading, setLoading] = useState(true) const [error, setError] = useState(null) const [pagination, setPagination] = useState({ total: 0, page: 1, page_size: 20, total_pages: 0, }) const [search, setSearch] = useState('') const [statusFilter, setStatusFilter] = useState('') useEffect(() => { if (status === 'unauthenticated') { router.push('/auth/signin') } }, [status, router]) useEffect(() => { if (status === 'authenticated') { fetchEmployees() } }, [status, pagination.page, search, statusFilter]) const fetchEmployees = async () => { try { setLoading(true) setError(null) const params = new URLSearchParams({ page: pagination.page.toString(), page_size: pagination.page_size.toString(), }) if (search) params.append('search', search) if (statusFilter) params.append('status_filter', statusFilter) const response = await fetch( `${process.env.NEXT_PUBLIC_API_BASE_URL}/employees/?${params.toString()}` ) if (!response.ok) { throw new Error('無法載入員工列表') } const data: EmployeeListResponse = await response.json() setEmployees(data.items) setPagination({ total: data.total, page: data.page, page_size: data.page_size, total_pages: data.total_pages, }) } catch (err) { setError(err instanceof Error ? err.message : '載入失敗') } finally { setLoading(false) } } const handleSearch = (value: string) => { setSearch(value) setPagination({ ...pagination, page: 1 }) } const handleStatusFilter = (value: string) => { setStatusFilter(value) setPagination({ ...pagination, page: 1 }) } const handlePageChange = (newPage: number) => { setPagination({ ...pagination, page: newPage }) } if (status === 'loading' || loading) { return (
載入中...
) } if (!session) { return null } return (

員工管理

管理公司員工資料

{/* 搜尋與篩選 */}
handleSearch(e.target.value)} className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent" />
{/* 錯誤訊息 */} {error && (
{error}
)} {/* 員工列表 */}
{employees.length === 0 ? ( ) : ( employees.map((employee) => ( )) )}
工號 姓名 事業部/部門 職稱 到職日 狀態 操作
暫無員工資料
{employee.employee_id}
{employee.legal_name}
{employee.english_name && (
{employee.english_name}
)}
{employee.primary_business_unit || '-'}
{employee.primary_department && (
{employee.primary_department}
)}
{employee.primary_job_title || '-'} {new Date(employee.hire_date).toLocaleDateString('zh-TW')} {employee.status === 'active' ? '在職' : employee.status === 'on_leave' ? '留停' : '離職'}
{/* 分頁 */} {pagination.total_pages > 1 && (
顯示第 {(pagination.page - 1) * pagination.page_size + 1} -{' '} {Math.min(pagination.page * pagination.page_size, pagination.total)} 筆, 共 {pagination.total} 筆
第 {pagination.page} / {pagination.total_pages} 頁
)}
) }