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:
@@ -2,6 +2,7 @@
|
||||
|
||||
|
||||
import { executeServerAction } from '@/lib/api/execute-server-action';
|
||||
import { buildApiUrl } from '@/lib/api/query-params';
|
||||
import type { PaginatedApiResponse } from '@/lib/api/types';
|
||||
import type { Process, ProcessFormData, ClassificationRule, IndividualItem, ProcessStep } from '@/types/process';
|
||||
|
||||
@@ -222,8 +223,6 @@ function transformFrontendToApi(data: ProcessFormData): Record<string, unknown>
|
||||
// API 함수
|
||||
// ============================================================================
|
||||
|
||||
const API_URL = process.env.NEXT_PUBLIC_API_URL;
|
||||
|
||||
/**
|
||||
* 공정 목록 조회
|
||||
*/
|
||||
@@ -234,15 +233,14 @@ export async function getProcessList(params?: {
|
||||
status?: string;
|
||||
process_type?: string;
|
||||
}): Promise<{ success: boolean; data?: { items: Process[]; total: number; page: number; totalPages: number }; error?: string; __authError?: boolean }> {
|
||||
const searchParams = new URLSearchParams();
|
||||
if (params?.page) searchParams.set('page', String(params.page));
|
||||
if (params?.size) searchParams.set('size', String(params.size));
|
||||
if (params?.q) searchParams.set('q', params.q);
|
||||
if (params?.status) searchParams.set('status', params.status);
|
||||
if (params?.process_type) searchParams.set('process_type', params.process_type);
|
||||
|
||||
const result = await executeServerAction<PaginatedApiResponse<ApiProcess>>({
|
||||
url: `${API_URL}/api/v1/processes?${searchParams.toString()}`,
|
||||
url: buildApiUrl('/api/v1/processes', {
|
||||
page: params?.page,
|
||||
size: params?.size,
|
||||
q: params?.q,
|
||||
status: params?.status,
|
||||
process_type: params?.process_type,
|
||||
}),
|
||||
errorMessage: '공정 목록 조회에 실패했습니다.',
|
||||
});
|
||||
if (result.__authError) return { success: false, __authError: true };
|
||||
@@ -263,7 +261,7 @@ export async function getProcessList(params?: {
|
||||
*/
|
||||
export async function getProcessById(id: string): Promise<{ success: boolean; data?: Process; error?: string; __authError?: boolean }> {
|
||||
const result = await executeServerAction({
|
||||
url: `${API_URL}/api/v1/processes/${id}`,
|
||||
url: buildApiUrl(`/api/v1/processes/${id}`),
|
||||
transform: (data: ApiProcess) => transformApiToFrontend(data),
|
||||
errorMessage: '공정 조회에 실패했습니다.',
|
||||
});
|
||||
@@ -276,7 +274,7 @@ export async function getProcessById(id: string): Promise<{ success: boolean; da
|
||||
*/
|
||||
export async function createProcess(data: ProcessFormData): Promise<{ success: boolean; data?: Process; error?: string; __authError?: boolean }> {
|
||||
const result = await executeServerAction({
|
||||
url: `${API_URL}/api/v1/processes`,
|
||||
url: buildApiUrl('/api/v1/processes'),
|
||||
method: 'POST',
|
||||
body: transformFrontendToApi(data),
|
||||
transform: (d: ApiProcess) => transformApiToFrontend(d),
|
||||
@@ -291,7 +289,7 @@ export async function createProcess(data: ProcessFormData): Promise<{ success: b
|
||||
*/
|
||||
export async function updateProcess(id: string, data: ProcessFormData): Promise<{ success: boolean; data?: Process; error?: string; __authError?: boolean }> {
|
||||
const result = await executeServerAction({
|
||||
url: `${API_URL}/api/v1/processes/${id}`,
|
||||
url: buildApiUrl(`/api/v1/processes/${id}`),
|
||||
method: 'PUT',
|
||||
body: transformFrontendToApi(data),
|
||||
transform: (d: ApiProcess) => transformApiToFrontend(d),
|
||||
@@ -306,7 +304,7 @@ export async function updateProcess(id: string, data: ProcessFormData): Promise<
|
||||
*/
|
||||
export async function removeProcessItem(processId: string, remainingItemIds: number[]): Promise<{ success: boolean; data?: Process; error?: string; __authError?: boolean }> {
|
||||
const result = await executeServerAction({
|
||||
url: `${API_URL}/api/v1/processes/${processId}`,
|
||||
url: buildApiUrl(`/api/v1/processes/${processId}`),
|
||||
method: 'PUT',
|
||||
body: { item_ids: remainingItemIds },
|
||||
transform: (d: ApiProcess) => transformApiToFrontend(d),
|
||||
@@ -321,7 +319,7 @@ export async function removeProcessItem(processId: string, remainingItemIds: num
|
||||
*/
|
||||
export async function deleteProcess(id: string): Promise<{ success: boolean; error?: string; __authError?: boolean }> {
|
||||
const result = await executeServerAction({
|
||||
url: `${API_URL}/api/v1/processes/${id}`,
|
||||
url: buildApiUrl(`/api/v1/processes/${id}`),
|
||||
method: 'DELETE',
|
||||
errorMessage: '공정 삭제에 실패했습니다.',
|
||||
});
|
||||
@@ -334,7 +332,7 @@ export async function deleteProcess(id: string): Promise<{ success: boolean; err
|
||||
*/
|
||||
export async function deleteProcesses(ids: string[]): Promise<{ success: boolean; deletedCount?: number; error?: string; __authError?: boolean }> {
|
||||
const result = await executeServerAction<{ deleted_count: number }>({
|
||||
url: `${API_URL}/api/v1/processes`,
|
||||
url: buildApiUrl('/api/v1/processes'),
|
||||
method: 'DELETE',
|
||||
body: { ids: ids.map((id) => parseInt(id, 10)) },
|
||||
errorMessage: '공정 일괄 삭제에 실패했습니다.',
|
||||
@@ -349,7 +347,7 @@ export async function deleteProcesses(ids: string[]): Promise<{ success: boolean
|
||||
*/
|
||||
export async function toggleProcessActive(id: string): Promise<{ success: boolean; data?: Process; error?: string; __authError?: boolean }> {
|
||||
const result = await executeServerAction({
|
||||
url: `${API_URL}/api/v1/processes/${id}/toggle`,
|
||||
url: buildApiUrl(`/api/v1/processes/${id}/toggle`),
|
||||
method: 'PATCH',
|
||||
transform: (d: ApiProcess) => transformApiToFrontend(d),
|
||||
errorMessage: '공정 상태 변경에 실패했습니다.',
|
||||
@@ -365,7 +363,7 @@ export async function reorderProcesses(
|
||||
processes: { id: string; order: number }[]
|
||||
): Promise<{ success: boolean; error?: string; __authError?: boolean }> {
|
||||
const result = await executeServerAction({
|
||||
url: `${API_URL}/api/v1/processes/reorder`,
|
||||
url: buildApiUrl('/api/v1/processes/reorder'),
|
||||
method: 'PATCH',
|
||||
body: {
|
||||
items: processes.map((p) => ({
|
||||
@@ -390,7 +388,7 @@ export async function getProcessOptions(): Promise<{
|
||||
}> {
|
||||
interface ApiOptionItem { id: number; process_code: string; process_name: string; process_type: string; department: string }
|
||||
const result = await executeServerAction<ApiOptionItem[]>({
|
||||
url: `${API_URL}/api/v1/processes/options`,
|
||||
url: buildApiUrl('/api/v1/processes/options'),
|
||||
errorMessage: '공정 옵션 조회에 실패했습니다.',
|
||||
});
|
||||
if (result.__authError) return { success: false, __authError: true };
|
||||
@@ -418,7 +416,7 @@ export async function getProcessStats(): Promise<{
|
||||
}> {
|
||||
interface ApiStats { total: number; active: number; inactive: number; by_type: Record<string, number> }
|
||||
const result = await executeServerAction<ApiStats>({
|
||||
url: `${API_URL}/api/v1/processes/stats`,
|
||||
url: buildApiUrl('/api/v1/processes/stats'),
|
||||
errorMessage: '공정 통계 조회에 실패했습니다.',
|
||||
});
|
||||
if (result.__authError) return { success: false, __authError: true };
|
||||
@@ -456,7 +454,7 @@ export async function getDepartmentOptions(): Promise<DepartmentOption[]> {
|
||||
];
|
||||
interface DeptResponse { data: Array<{ id: number; name: string }> }
|
||||
const result = await executeServerAction<DeptResponse>({
|
||||
url: `${API_URL}/api/v1/departments`,
|
||||
url: buildApiUrl('/api/v1/departments'),
|
||||
errorMessage: '부서 목록 조회에 실패했습니다.',
|
||||
});
|
||||
if (!result.success || !result.data?.data) return defaultOptions;
|
||||
@@ -507,15 +505,14 @@ interface GetItemListParams {
|
||||
* - 파라미터에 processName, processCategory 필터 추가 필요 (공정/구분 필터링용)
|
||||
*/
|
||||
export async function getItemList(params?: GetItemListParams): Promise<ItemOption[]> {
|
||||
const searchParams = new URLSearchParams();
|
||||
searchParams.set('size', String(params?.size || 1000));
|
||||
if (params?.q) searchParams.set('q', params.q);
|
||||
if (params?.itemType) searchParams.set('item_type', params.itemType);
|
||||
if (params?.excludeProcessId) searchParams.set('exclude_process_id', params.excludeProcessId);
|
||||
|
||||
interface ItemListResponse { data: Array<{ id: number; name: string; item_code?: string; item_type?: string; item_type_name?: string }> }
|
||||
const result = await executeServerAction<ItemListResponse>({
|
||||
url: `${API_URL}/api/v1/items?${searchParams.toString()}`,
|
||||
url: buildApiUrl('/api/v1/items', {
|
||||
size: params?.size || 1000,
|
||||
q: params?.q,
|
||||
item_type: params?.itemType,
|
||||
exclude_process_id: params?.excludeProcessId,
|
||||
}),
|
||||
errorMessage: '품목 목록 조회에 실패했습니다.',
|
||||
});
|
||||
if (!result.success || !result.data?.data) return [];
|
||||
@@ -534,7 +531,7 @@ export async function getItemList(params?: GetItemListParams): Promise<ItemOptio
|
||||
*/
|
||||
export async function getItemTypeOptions(): Promise<Array<{ value: string; label: string }>> {
|
||||
const result = await executeServerAction<Array<{ code: string; name: string }>>({
|
||||
url: `${API_URL}/api/v1/settings/common/item_type`,
|
||||
url: buildApiUrl('/api/v1/settings/common/item_type'),
|
||||
errorMessage: '품목 유형 옵션 조회에 실패했습니다.',
|
||||
});
|
||||
if (!result.success || !result.data) return [];
|
||||
@@ -561,7 +558,7 @@ export async function getDocumentTemplates(): Promise<{
|
||||
}> {
|
||||
interface ApiTemplateItem { id: number; name: string; category: string }
|
||||
const result = await executeServerAction<{ data: ApiTemplateItem[] }>({
|
||||
url: `${API_URL}/api/v1/document-templates?is_active=1&per_page=100`,
|
||||
url: buildApiUrl('/api/v1/document-templates', { is_active: 1, per_page: 100 }),
|
||||
errorMessage: '문서 양식 목록 조회에 실패했습니다.',
|
||||
});
|
||||
if (!result.success || !result.data?.data) return { success: false, error: result.error };
|
||||
@@ -621,7 +618,7 @@ export async function getProcessSteps(processId: string): Promise<{
|
||||
error?: string;
|
||||
}> {
|
||||
const result = await executeServerAction<ApiProcessStep[]>({
|
||||
url: `${API_URL}/api/v1/processes/${processId}/steps`,
|
||||
url: buildApiUrl(`/api/v1/processes/${processId}/steps`),
|
||||
errorMessage: '공정 단계 목록 조회에 실패했습니다.',
|
||||
});
|
||||
if (!result.success || !result.data) return { success: false, error: result.error };
|
||||
@@ -637,7 +634,7 @@ export async function getProcessStepById(processId: string, stepId: string): Pro
|
||||
error?: string;
|
||||
}> {
|
||||
const result = await executeServerAction({
|
||||
url: `${API_URL}/api/v1/processes/${processId}/steps/${stepId}`,
|
||||
url: buildApiUrl(`/api/v1/processes/${processId}/steps/${stepId}`),
|
||||
transform: (d: ApiProcessStep) => transformStepApiToFrontend(d),
|
||||
errorMessage: '공정 단계 조회에 실패했습니다.',
|
||||
});
|
||||
@@ -652,7 +649,7 @@ export async function createProcessStep(
|
||||
data: Omit<ProcessStep, 'id'>
|
||||
): Promise<{ success: boolean; data?: ProcessStep; error?: string }> {
|
||||
const result = await executeServerAction({
|
||||
url: `${API_URL}/api/v1/processes/${processId}/steps`,
|
||||
url: buildApiUrl(`/api/v1/processes/${processId}/steps`),
|
||||
method: 'POST',
|
||||
body: {
|
||||
step_name: data.stepName,
|
||||
@@ -689,7 +686,7 @@ export async function updateProcessStep(
|
||||
if (data.completionType !== undefined) apiData.completion_type = data.completionType || null;
|
||||
|
||||
const result = await executeServerAction({
|
||||
url: `${API_URL}/api/v1/processes/${processId}/steps/${stepId}`,
|
||||
url: buildApiUrl(`/api/v1/processes/${processId}/steps/${stepId}`),
|
||||
method: 'PUT',
|
||||
body: apiData,
|
||||
transform: (d: ApiProcessStep) => transformStepApiToFrontend(d),
|
||||
@@ -706,7 +703,7 @@ export async function deleteProcessStep(
|
||||
stepId: string
|
||||
): Promise<{ success: boolean; error?: string }> {
|
||||
const result = await executeServerAction({
|
||||
url: `${API_URL}/api/v1/processes/${processId}/steps/${stepId}`,
|
||||
url: buildApiUrl(`/api/v1/processes/${processId}/steps/${stepId}`),
|
||||
method: 'DELETE',
|
||||
errorMessage: '공정 단계 삭제에 실패했습니다.',
|
||||
});
|
||||
@@ -721,7 +718,7 @@ export async function reorderProcessSteps(
|
||||
steps: { id: string; order: number }[]
|
||||
): Promise<{ success: boolean; data?: ProcessStep[]; error?: string }> {
|
||||
const result = await executeServerAction<ApiProcessStep[]>({
|
||||
url: `${API_URL}/api/v1/processes/${processId}/steps/reorder`,
|
||||
url: buildApiUrl(`/api/v1/processes/${processId}/steps/reorder`),
|
||||
method: 'PATCH',
|
||||
body: {
|
||||
items: steps.map((s) => ({
|
||||
|
||||
Reference in New Issue
Block a user