import { useState } from 'react' import { usePageSize } from '../hooks/usePageSize' import { toast } from 'sonner' import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query' import { useConfirm } from '../hooks/useConfirm' import { CalendarClock, Check, X, Trash2, Clock, CheckCircle2, XCircle, RotateCcw, FileText, Smartphone } from 'lucide-react' import { leaveApi } from '../lib/api-services' import Card from '../components/ui/Card' import Button from '../components/ui/Button' import { Input, Label, Select } from '../components/ui/Input' import EmptyState from '../components/ui/EmptyState' import Pagination from '../components/ui/Pagination' const LEAVE_TYPE_MAP: Record = { SICK: '病假', PERSONAL: '事假', ANNUAL: '年假', MATERNITY: '产假', OTHER: '其他', } const STATUS_MAP: Record = { PENDING: { label: '待审批', color: 'bg-amber-50 text-warning', icon: }, APPROVED: { label: '已批准', color: 'bg-green-50 text-safe', icon: }, REJECTED: { label: '已驳回', color: 'bg-red-50 text-danger', icon: }, CANCELLED: { label: '已撤回', color: 'bg-gray-100 text-gray-500', icon: }, } const fmtDate = (d: string) => new Date(d).toLocaleDateString('zh-CN') export default function LeaveApproval() { const queryClient = useQueryClient() const confirm = useConfirm() const pageSize = usePageSize() const [page, setPage] = useState(1) const [filterStatus, setFilterStatus] = useState('') const [filterType, setFilterType] = useState('') const [approveModal, setApproveModal] = useState<{ id: string; action: string; name: string } | null>(null) const [approveRemark, setApproveRemark] = useState('') const { data: stats } = useQuery({ queryKey: ['leave-stats'], queryFn: () => leaveApi.stats(), }) const { data: result, isLoading } = useQuery({ queryKey: ['leave-requests', filterStatus, filterType, page, pageSize], queryFn: () => leaveApi.list({ status: filterStatus || undefined, leaveType: filterType || undefined, page, pageSize }), }) const list = result?.list || [] const total = result?.total || 0 const approveMutation = useMutation({ mutationFn: ({ id, action, remark }: { id: string; action: string; remark?: string }) => leaveApi.approve(id, action, remark), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['leave-requests'] }) queryClient.invalidateQueries({ queryKey: ['leave-stats'] }) toast.success('审批完成') setApproveModal(null) setApproveRemark('') }, onError: (err: any) => toast.error(err?.response?.data?.error?.message || '审批失败'), }) const deleteMutation = useMutation({ mutationFn: (id: string) => leaveApi.remove(id), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['leave-requests'] }) queryClient.invalidateQueries({ queryKey: ['leave-stats'] }) toast.success('已删除') }, }) return (

休假审批

员工端申请 → 管理端审批 → 自动归档

{/* 流程说明 */}
休假审批流程
① 员工在手机端「员工自助」发起休假申请(选择类型、日期、事由)
② 管理端在此页面审批:批准或驳回(可填写审批意见)
③ 批准后自动生成休假记录,归档至考勤系统
{/* 统计卡片 */}
{stats?.total || 0}
总计
{stats?.pending || 0}
待审批
{stats?.approved || 0}
已批准
{stats?.rejected || 0}
已驳回
{stats?.cancelled || 0}
已撤回
{/* 筛选 + 操作 */}
{total > 0 && {total} 条记录}
{/* 列表 */} {isLoading ? (
加载中...
) : list.length === 0 ? ( ) : ( <>
{list.map((item: any) => { const st = STATUS_MAP[item.status] || STATUS_MAP.PENDING return ( ) })}
员工 类型 起止日期 天数 事由 状态 审批意见 操作
{item.employee?.name}
{item.employee?.department}
{LEAVE_TYPE_MAP[item.leaveType] || item.leaveType} {fmtDate(item.startDate)} ~ {fmtDate(item.endDate)} {item.days} {item.reason || '—'} {st.icon}{st.label} {item.approveRemark || '—'}
{item.status === 'PENDING' && ( <> )}
setPage(1)} /> )} {/* 审批弹窗 */} {approveModal && (
setApproveModal(null)}>
e.stopPropagation()}>

{approveModal.action === 'APPROVED' ? '批准休假申请' : '驳回休假申请'} — {approveModal.name}

setApproveRemark(e.target.value)} placeholder="请输入审批意见(可选)" />
)}
) }