refactor(WEB): 전체 actions.ts에 공통 API 유틸 적용

- buildApiUrl / executePaginatedAction 패턴으로 전환 (40+ actions 파일)
- 직접 URLSearchParams 조립 → buildApiUrl 유틸 사용
- 수동 페이지네이션 메타 변환 → executePaginatedAction 자동 처리
- HandoverReportDocumentModal, OrderDocumentModal 개선
- 급여관리 SalaryManagement 코드 개선
- CLAUDE.md Server Action 공통 유틸 규칙 정리

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
유병철
2026-02-12 20:59:59 +09:00
parent 31be9d4a25
commit cbb38d48b9
51 changed files with 1050 additions and 1405 deletions

View File

@@ -16,6 +16,7 @@
*/
import { executeServerAction } from '@/lib/api/execute-server-action';
import { buildApiUrl } from '@/lib/api/query-params';
import type {
ProductInspection,
InspectionStats,
@@ -286,8 +287,6 @@ function transformFormToApi(data: InspectionFormData): Record<string, unknown> {
};
}
const API_BASE = `${process.env.NEXT_PUBLIC_API_URL}/api/v1/inspections`;
// ===== 제품검사 목록 조회 =====
export async function getInspections(params?: {
@@ -306,19 +305,15 @@ export async function getInspections(params?: {
}> {
const defaultPagination = { currentPage: 1, lastPage: 1, perPage: 20, total: 0 };
const searchParams = new URLSearchParams();
if (params?.page) searchParams.set('page', String(params.page));
if (params?.size) searchParams.set('per_page', String(params.size));
if (params?.q) searchParams.set('q', params.q);
if (params?.status && params.status !== '전체') {
searchParams.set('status', mapFrontendStatus(params.status));
}
if (params?.dateFrom) searchParams.set('date_from', params.dateFrom);
if (params?.dateTo) searchParams.set('date_to', params.dateTo);
const queryString = searchParams.toString();
const result = await executeServerAction<PaginatedResponse>({
url: `${API_BASE}${queryString ? `?${queryString}` : ''}`,
url: buildApiUrl('/api/v1/inspections', {
page: params?.page,
per_page: params?.size,
q: params?.q,
status: params?.status && params.status !== '전체' ? mapFrontendStatus(params.status) : undefined,
date_from: params?.dateFrom,
date_to: params?.dateTo,
}),
errorMessage: '제품검사 목록 조회에 실패했습니다.',
});
@@ -373,13 +368,11 @@ export async function getInspectionStats(params?: {
error?: string;
__authError?: boolean;
}> {
const searchParams = new URLSearchParams();
if (params?.dateFrom) searchParams.set('date_from', params.dateFrom);
if (params?.dateTo) searchParams.set('date_to', params.dateTo);
const queryString = searchParams.toString();
const result = await executeServerAction<InspectionStatsApi>({
url: `${API_BASE}/stats${queryString ? `?${queryString}` : ''}`,
url: buildApiUrl('/api/v1/inspections/stats', {
date_from: params?.dateFrom,
date_to: params?.dateTo,
}),
errorMessage: '제품검사 통계 조회에 실패했습니다.',
});
@@ -412,17 +405,13 @@ export async function getInspectionCalendar(params?: {
error?: string;
__authError?: boolean;
}> {
const searchParams = new URLSearchParams();
if (params?.year) searchParams.set('year', String(params.year));
if (params?.month) searchParams.set('month', String(params.month));
if (params?.inspector) searchParams.set('inspector', params.inspector);
if (params?.status && params.status !== '전체') {
searchParams.set('status', mapFrontendStatus(params.status));
}
const queryString = searchParams.toString();
const result = await executeServerAction<CalendarItemApi[]>({
url: `${API_BASE}/calendar${queryString ? `?${queryString}` : ''}`,
url: buildApiUrl('/api/v1/inspections/calendar', {
year: params?.year,
month: params?.month,
inspector: params?.inspector,
status: params?.status && params.status !== '전체' ? mapFrontendStatus(params.status) : undefined,
}),
errorMessage: '캘린더 스케줄 조회에 실패했습니다.',
});
@@ -454,7 +443,7 @@ export async function getInspectionById(id: string): Promise<{
__authError?: boolean;
}> {
const result = await executeServerAction<ProductInspectionApi>({
url: `${API_BASE}/${id}`,
url: buildApiUrl(`/api/v1/inspections/${id}`),
errorMessage: '제품검사 상세 조회에 실패했습니다.',
});
@@ -482,7 +471,7 @@ export async function createInspection(data: InspectionFormData): Promise<{
}> {
const apiData = transformFormToApi(data);
const result = await executeServerAction<ProductInspectionApi>({
url: API_BASE,
url: buildApiUrl('/api/v1/inspections'),
method: 'POST',
body: apiData,
errorMessage: '제품검사 등록에 실패했습니다.',
@@ -569,7 +558,7 @@ export async function updateInspection(
}
const result = await executeServerAction<ProductInspectionApi>({
url: `${API_BASE}/${id}`,
url: buildApiUrl(`/api/v1/inspections/${id}`),
method: 'PUT',
body: apiData,
errorMessage: '제품검사 수정에 실패했습니다.',
@@ -589,7 +578,7 @@ export async function deleteInspection(id: string): Promise<{
__authError?: boolean;
}> {
const result = await executeServerAction({
url: `${API_BASE}/${id}`,
url: buildApiUrl(`/api/v1/inspections/${id}`),
method: 'DELETE',
errorMessage: '제품검사 삭제에 실패했습니다.',
});
@@ -614,7 +603,7 @@ export async function completeInspection(
}
const result = await executeServerAction<ProductInspectionApi>({
url: `${API_BASE}/${id}/complete`,
url: buildApiUrl(`/api/v1/inspections/${id}/complete`),
method: 'PATCH',
body: apiData,
errorMessage: '검사 완료 처리에 실패했습니다.',
@@ -636,12 +625,8 @@ export async function getOrderSelectList(params?: {
error?: string;
__authError?: boolean;
}> {
const searchParams = new URLSearchParams();
if (params?.q) searchParams.set('q', params.q);
const queryString = searchParams.toString();
const result = await executeServerAction<OrderSelectItemApi[]>({
url: `${process.env.NEXT_PUBLIC_API_URL}/api/v1/orders/select${queryString ? `?${queryString}` : ''}`,
url: buildApiUrl('/api/v1/orders/select', { q: params?.q }),
errorMessage: '수주 선택 목록 조회에 실패했습니다.',
});

View File

@@ -14,6 +14,7 @@
*/
import { executeServerAction } from '@/lib/api/execute-server-action';
import { buildApiUrl } from '@/lib/api/query-params';
import type {
PerformanceReport,
PerformanceReportStats,
@@ -38,8 +39,6 @@ interface PaginationMeta {
total: number;
}
const API_BASE = `${process.env.NEXT_PUBLIC_API_URL}/api/v1/performance-reports`;
// ===== 분기별 실적신고 목록 조회 =====
export async function getPerformanceReports(params?: {
@@ -57,19 +56,15 @@ export async function getPerformanceReports(params?: {
}> {
const defaultPagination = { currentPage: 1, lastPage: 1, perPage: 20, total: 0 };
const searchParams = new URLSearchParams();
if (params?.page) searchParams.set('page', String(params.page));
if (params?.size) searchParams.set('per_page', String(params.size));
if (params?.q) searchParams.set('q', params.q);
if (params?.year) searchParams.set('year', String(params.year));
if (params?.quarter && params.quarter !== '전체') {
searchParams.set('quarter', params.quarter);
}
const queryString = searchParams.toString();
interface ApiListData { items?: PerformanceReport[]; current_page?: number; last_page?: number; per_page?: number; total?: number }
const result = await executeServerAction<ApiListData>({
url: `${API_BASE}${queryString ? `?${queryString}` : ''}`,
url: buildApiUrl('/api/v1/performance-reports', {
page: params?.page,
per_page: params?.size,
q: params?.q,
year: params?.year,
quarter: params?.quarter && params.quarter !== '전체' ? params.quarter : undefined,
}),
errorMessage: '실적신고 목록 조회에 실패했습니다.',
});
@@ -120,15 +115,11 @@ export async function getPerformanceReportStats(params?: {
error?: string;
__authError?: boolean;
}> {
const searchParams = new URLSearchParams();
if (params?.year) searchParams.set('year', String(params.year));
if (params?.quarter && params.quarter !== '전체') {
searchParams.set('quarter', params.quarter);
}
const queryString = searchParams.toString();
const result = await executeServerAction<PerformanceReportStats>({
url: `${API_BASE}/stats${queryString ? `?${queryString}` : ''}`,
url: buildApiUrl('/api/v1/performance-reports/stats', {
year: params?.year,
quarter: params?.quarter && params.quarter !== '전체' ? params.quarter : undefined,
}),
errorMessage: '실적신고 통계 조회에 실패했습니다.',
});
@@ -154,15 +145,13 @@ export async function getMissedReports(params?: {
}> {
const defaultPagination = { currentPage: 1, lastPage: 1, perPage: 20, total: 0 };
const searchParams = new URLSearchParams();
if (params?.page) searchParams.set('page', String(params.page));
if (params?.size) searchParams.set('per_page', String(params.size));
if (params?.q) searchParams.set('q', params.q);
const queryString = searchParams.toString();
interface ApiMissedData { items?: MissedReport[]; current_page?: number; last_page?: number; per_page?: number; total?: number }
const result = await executeServerAction<ApiMissedData>({
url: `${API_BASE}/missed${queryString ? `?${queryString}` : ''}`,
url: buildApiUrl('/api/v1/performance-reports/missed', {
page: params?.page,
per_page: params?.size,
q: params?.q,
}),
errorMessage: '누락체크 목록 조회에 실패했습니다.',
});
@@ -208,7 +197,7 @@ export async function confirmReports(ids: string[]): Promise<{
__authError?: boolean;
}> {
const result = await executeServerAction({
url: `${API_BASE}/confirm`,
url: buildApiUrl('/api/v1/performance-reports/confirm'),
method: 'PATCH',
body: { ids },
errorMessage: '확정 처리에 실패했습니다.',
@@ -225,7 +214,7 @@ export async function unconfirmReports(ids: string[]): Promise<{
__authError?: boolean;
}> {
const result = await executeServerAction({
url: `${API_BASE}/unconfirm`,
url: buildApiUrl('/api/v1/performance-reports/unconfirm'),
method: 'PATCH',
body: { ids },
errorMessage: '확정 해제에 실패했습니다.',
@@ -242,7 +231,7 @@ export async function distributeReports(ids: string[]): Promise<{
__authError?: boolean;
}> {
const result = await executeServerAction({
url: `${API_BASE}/distribute`,
url: buildApiUrl('/api/v1/performance-reports/distribute'),
method: 'POST',
body: { ids },
errorMessage: '배포에 실패했습니다.',
@@ -259,7 +248,7 @@ export async function updateMemo(ids: string[], memo: string): Promise<{
__authError?: boolean;
}> {
const result = await executeServerAction({
url: `${API_BASE}/memo`,
url: buildApiUrl('/api/v1/performance-reports/memo'),
method: 'PATCH',
body: { ids, memo },
errorMessage: '메모 저장에 실패했습니다.',