feat: [quality] 실적신고 확정건 엑셀 다운로드 프론트엔드 연동
- exportConfirmedExcel() 서버 액션 추가 (Blob 다운로드 패턴) - handleExcelDownload 함수를 실제 API 호출로 변경 - 연도/분기 필터 파라미터 전달
This commit is contained in:
@@ -48,6 +48,7 @@ import {
|
||||
unconfirmReports,
|
||||
distributeReports,
|
||||
updateMemo,
|
||||
exportConfirmedExcel,
|
||||
} from './actions';
|
||||
import { confirmStatusColorMap } from './mockData';
|
||||
import { isNextRedirectError } from '@/lib/utils/redirect-error';
|
||||
@@ -209,9 +210,28 @@ export function PerformanceReportList() {
|
||||
}
|
||||
}, [memoSelectedIds]);
|
||||
|
||||
const handleExcelDownload = useCallback(() => {
|
||||
toast.info('확정건 엑셀 다운로드 기능은 API 연동 후 활성화됩니다.');
|
||||
}, []);
|
||||
const handleExcelDownload = useCallback(async () => {
|
||||
const quarterNum = quarter === '전체' ? Math.ceil(new Date().getMonth() / 3) || 1 : Number(quarter);
|
||||
try {
|
||||
const result = await exportConfirmedExcel({ year, quarter: quarterNum });
|
||||
if (result.success && result.data) {
|
||||
const url = URL.createObjectURL(result.data);
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = result.filename || `판매실적대장_${year}년_${quarterNum}분기.xlsx`;
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
document.body.removeChild(a);
|
||||
URL.revokeObjectURL(url);
|
||||
toast.success('엑셀 다운로드 완료');
|
||||
} else {
|
||||
toast.error(result.error || '엑셀 다운로드에 실패했습니다.');
|
||||
}
|
||||
} catch (error) {
|
||||
if (isNextRedirectError(error)) throw error;
|
||||
toast.error('엑셀 다운로드에 실패했습니다.');
|
||||
}
|
||||
}, [year, quarter]);
|
||||
|
||||
// ===== 통계 카드 =====
|
||||
const stats: StatCard[] = useMemo(
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
* - GET /api/v1/quality/performance-reports - 분기별 실적신고 목록
|
||||
* - GET /api/v1/quality/performance-reports/stats - 통계
|
||||
* - GET /api/v1/quality/performance-reports/missing - 누락체크 목록
|
||||
* - GET /api/v1/quality/performance-reports/export-excel - 확정건 엑셀 다운로드
|
||||
* - PATCH /api/v1/quality/performance-reports/confirm - 선택 확정
|
||||
* - PATCH /api/v1/quality/performance-reports/unconfirm - 확정 해제
|
||||
* - PATCH /api/v1/quality/performance-reports/memo - 메모 일괄 적용
|
||||
@@ -14,6 +15,7 @@
|
||||
|
||||
import { executeServerAction } from '@/lib/api/execute-server-action';
|
||||
import { buildApiUrl } from '@/lib/api/query-params';
|
||||
import { cookies } from 'next/headers';
|
||||
import type {
|
||||
PerformanceReport,
|
||||
PerformanceReportStats,
|
||||
@@ -301,3 +303,49 @@ export async function updateMemo(ids: string[], memo: string): Promise<{
|
||||
if (!result.success && USE_MOCK_FALLBACK) return { success: true };
|
||||
return { success: result.success, error: result.error, __authError: result.__authError };
|
||||
}
|
||||
|
||||
// ===== 확정건 엑셀 다운로드 =====
|
||||
|
||||
export async function exportConfirmedExcel(params: {
|
||||
year: number;
|
||||
quarter: number;
|
||||
}): Promise<{
|
||||
success: boolean;
|
||||
data?: Blob;
|
||||
filename?: string;
|
||||
error?: string;
|
||||
}> {
|
||||
try {
|
||||
const cookieStore = await cookies();
|
||||
const token = cookieStore.get('access_token')?.value;
|
||||
|
||||
const headers: HeadersInit = {
|
||||
'Accept': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||
'Authorization': token ? `Bearer ${token}` : '',
|
||||
'X-API-KEY': process.env.API_KEY || '',
|
||||
};
|
||||
|
||||
const url = buildApiUrl('/api/v1/quality/performance-reports/export-excel', {
|
||||
year: params.year,
|
||||
quarter: params.quarter,
|
||||
});
|
||||
|
||||
const response = await fetch(url, { method: 'GET', headers });
|
||||
|
||||
if (!response.ok) {
|
||||
return { success: false, error: `API 오류: ${response.status}` };
|
||||
}
|
||||
|
||||
const blob = await response.blob();
|
||||
const contentDisposition = response.headers.get('Content-Disposition');
|
||||
const filenameMatch = contentDisposition?.match(/filename\*?=(?:UTF-8'')?(.+)/);
|
||||
const filename = filenameMatch?.[1]
|
||||
? decodeURIComponent(filenameMatch[1])
|
||||
: `판매실적대장_${params.year}년_${params.quarter}분기.xlsx`;
|
||||
|
||||
return { success: true, data: blob, filename };
|
||||
} catch (error) {
|
||||
if (error instanceof Error && error.message?.includes('NEXT_REDIRECT')) throw error;
|
||||
return { success: false, error: '서버 오류가 발생했습니다.' };
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user