'use client'; import { useState } from 'react'; import { useRouter } from 'next/navigation'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { getApvappList, multiApprove, multiReject, APRVL_STUS_LABEL, APRVL_KIND_LABEL, ApvreqListItem, } from '@/lib/api/tam'; import { localYmd, localYmdDaysAgo } from '@/lib/utils/date'; const PAGE_SIZE = 20; const TODAY = localYmd(); const MONTH_AGO = localYmdDaysAgo(30); export default function Tam0030Page() { const router = useRouter(); const qc = useQueryClient(); const [staYmd, setStaYmd] = useState(MONTH_AGO); const [endYmd, setEndYmd] = useState(TODAY); const [pageNo, setPageNo] = useState(1); const [filter, setFilter] = useState({ staYmd: MONTH_AGO, endYmd: TODAY, pageNo: 1 }); const [selected, setSelected] = useState>(new Set()); const [batchComment, setBatchComment] = useState(''); const { data, isLoading, refetch } = useQuery({ queryKey: ['apvapp', filter], queryFn: () => getApvappList({ ...filter, pageSize: PAGE_SIZE }), }); const handleSearch = () => { const f = { staYmd, endYmd, pageNo: 1 }; const same = JSON.stringify(f) === JSON.stringify(filter); setFilter(f); setPageNo(1); setSelected(new Set()); if (same) refetch(); }; const handlePageChange = (p: number) => { setPageNo(p); setFilter((prev) => ({ ...prev, pageNo: p })); setSelected(new Set()); }; // 결재중인 항목만 체크박스 대상 const appringItems = (data?.list ?? []).filter((item) => item.aprvlStusCd === '0002'); const toggleAll = () => { if (selected.size === appringItems.length) { setSelected(new Set()); } else { setSelected(new Set(appringItems.map((i) => i.aprvlDocId))); } }; const toggleOne = (id: string) => { setSelected((prev) => { const next = new Set(prev); next.has(id) ? next.delete(id) : next.add(id); return next; }); }; const getSelectedItems = () => (data?.list ?? []) .filter((i) => selected.has(i.aprvlDocId)) .map((i) => ({ aprvlDocId: i.aprvlDocId, aprvlSno: i.aprvlCmplSno + 1 })); const approveMut = useMutation({ mutationFn: () => multiApprove(getSelectedItems(), batchComment), onSuccess: () => { alert(`${selected.size}건 일괄 승인 처리되었습니다.`); setSelected(new Set()); setBatchComment(''); qc.invalidateQueries({ queryKey: ['apvapp'] }); }, onError: (e: any) => alert(e?.response?.data?.message ?? '일괄 승인 오류'), }); const rejectMut = useMutation({ mutationFn: () => multiReject(getSelectedItems(), batchComment), onSuccess: () => { alert(`${selected.size}건 일괄 반려 처리되었습니다.`); setSelected(new Set()); setBatchComment(''); qc.invalidateQueries({ queryKey: ['apvapp'] }); }, onError: (e: any) => alert(e?.response?.data?.message ?? '일괄 반려 오류'), }); const handleBatchApprove = () => { if (selected.size === 0) { alert('선택된 항목이 없습니다.'); return; } if (!confirm(`${selected.size}건을 일괄 승인하시겠습니까?`)) return; approveMut.mutate(); }; const handleBatchReject = () => { if (selected.size === 0) { alert('선택된 항목이 없습니다.'); return; } if (!batchComment.trim()) { alert('반려 사유를 입력해주세요.'); return; } if (!confirm(`${selected.size}건을 일괄 반려하시겠습니까?`)) return; rejectMut.mutate(); }; const totalPages = data ? Math.ceil(data.total / PAGE_SIZE) : 1; const isPending = approveMut.isPending || rejectMut.isPending; const statusBadge = (cd: string) => { const colors: Record = { '0001': 'bg-gray-100 text-gray-600', '0002': 'bg-blue-100 text-blue-700', '0003': 'bg-green-100 text-green-700', '0004': 'bg-red-100 text-red-700', }; return ( {APRVL_STUS_LABEL[cd] ?? cd} ); }; return (

결재 처리

{/* 검색 */}
setStaYmd(e.target.value.replace(/-/g, ''))} className="border rounded px-2 py-1.5 text-sm" /> ~ setEndYmd(e.target.value.replace(/-/g, ''))} className="border rounded px-2 py-1.5 text-sm" />
{/* 일괄처리 바 */} {selected.size > 0 && (
{selected.size}건 선택됨 setBatchComment(e.target.value)} placeholder="의견 (반려 시 필수)" className="flex-1 border rounded px-2 py-1 text-sm" />
)} {/* 테이블 */} {isLoading ? ( ) : !data?.list?.length ? ( ) : ( data.list.map((item: ApvreqListItem) => { const isAppring = item.aprvlStusCd === '0002'; const isChecked = selected.has(item.aprvlDocId); return ( ); }) )}
0 && selected.size === appringItems.length} onChange={toggleAll} /> 신청자 종류 상태 신청일 완료일 진행 처리
불러오는 중...
처리할 문서가 없습니다.
{isAppring && ( toggleOne(item.aprvlDocId)} /> )} {item.aplntId} {APRVL_KIND_LABEL[item.aprvlKindCd] ?? item.aprvlKindCd} {statusBadge(item.aprvlStusCd)} {item.offerDt} {item.cmplDt || '-'} {item.aprvlCmplSno} / {item.finalAprvlSno}
{/* 페이지네이션 */} {totalPages > 1 && (
{Array.from({ length: totalPages }, (_, i) => i + 1).map((p) => ( ))}
)}
전체 {data?.total ?? 0}건
); }