Files
sam-react-prod/src/components/process-management/actions.ts

452 lines
14 KiB
TypeScript

'use server';
import { serverFetch } from '@/lib/api/fetch-wrapper';
import type { Process, ProcessFormData, ClassificationRule } from '@/types/process';
// ============================================================================
// API 타입 정의
// ============================================================================
interface ApiProcess {
id: number;
tenant_id: number;
process_code: string;
process_name: string;
description: string | null;
process_type: string;
department: string | null;
work_log_template: string | null;
required_workers: number;
equipment_info: string | null;
work_steps: string[] | null;
note: string | null;
is_active: boolean;
created_at: string;
updated_at: string;
classification_rules?: ApiClassificationRule[];
}
interface ApiClassificationRule {
id: number;
process_id: number;
registration_type: string;
rule_type: string;
matching_type: string;
condition_value: string;
priority: number;
description: string | null;
is_active: boolean;
created_at: string;
updated_at: string;
}
interface ApiResponse<T> {
success: boolean;
message: string;
data: T;
}
interface PaginatedResponse<T> {
current_page: number;
data: T[];
last_page: number;
per_page: number;
total: number;
}
// ============================================================================
// 데이터 변환 함수
// ============================================================================
function transformApiToFrontend(apiData: ApiProcess): Process {
return {
id: String(apiData.id),
processCode: apiData.process_code,
processName: apiData.process_name,
description: apiData.description ?? undefined,
processType: apiData.process_type as Process['processType'],
department: apiData.department ?? '',
workLogTemplate: apiData.work_log_template ?? undefined,
classificationRules: (apiData.classification_rules ?? []).map(transformRuleApiToFrontend),
requiredWorkers: apiData.required_workers,
equipmentInfo: apiData.equipment_info ?? undefined,
workSteps: apiData.work_steps ?? [],
note: apiData.note ?? undefined,
status: apiData.is_active ? '사용중' : '미사용',
createdAt: apiData.created_at,
updatedAt: apiData.updated_at,
};
}
function transformRuleApiToFrontend(apiRule: ApiClassificationRule): ClassificationRule {
return {
id: String(apiRule.id),
registrationType: apiRule.registration_type as ClassificationRule['registrationType'],
ruleType: apiRule.rule_type as ClassificationRule['ruleType'],
matchingType: apiRule.matching_type as ClassificationRule['matchingType'],
conditionValue: apiRule.condition_value,
priority: apiRule.priority,
description: apiRule.description ?? undefined,
isActive: apiRule.is_active,
createdAt: apiRule.created_at,
};
}
function transformFrontendToApi(data: ProcessFormData): Record<string, unknown> {
return {
process_name: data.processName,
process_type: data.processType,
department: data.department || null,
work_log_template: data.workLogTemplate || null,
required_workers: data.requiredWorkers,
equipment_info: data.equipmentInfo || null,
work_steps: data.workSteps ? data.workSteps.split(',').map((s) => s.trim()).filter(Boolean) : [],
note: data.note || null,
is_active: data.isActive,
classification_rules: data.classificationRules.map((rule) => ({
registration_type: rule.registrationType,
rule_type: rule.ruleType,
matching_type: rule.matchingType,
condition_value: rule.conditionValue,
priority: rule.priority,
description: rule.description || null,
is_active: rule.isActive,
})),
};
}
// ============================================================================
// API 함수
// ============================================================================
/**
* 공정 목록 조회
*/
export async function getProcessList(params?: {
page?: number;
size?: number;
q?: string;
status?: string;
process_type?: string;
}): Promise<{ success: boolean; data?: { items: Process[]; total: number; page: number; totalPages: number }; error?: string; __authError?: boolean }> {
try {
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 { response, error } = await serverFetch(
`${process.env.NEXT_PUBLIC_API_URL}/v1/processes?${searchParams.toString()}`,
{ method: 'GET', cache: 'no-store' }
);
if (error) {
return { success: false, error: error.message, __authError: error.code === 'UNAUTHORIZED' };
}
if (!response) {
return { success: false, error: '목록 조회에 실패했습니다.' };
}
const result: ApiResponse<PaginatedResponse<ApiProcess>> = await response.json();
if (!response.ok || !result.success) {
return { success: false, error: result.message || '목록 조회에 실패했습니다.' };
}
return {
success: true,
data: {
items: result.data.data.map(transformApiToFrontend),
total: result.data.total,
page: result.data.current_page,
totalPages: result.data.last_page,
},
};
} catch (error) {
console.error('[getProcessList] Error:', error);
return { success: false, error: '서버 오류가 발생했습니다.' };
}
}
/**
* 공정 상세 조회
*/
export async function getProcessById(id: string): Promise<{ success: boolean; data?: Process; error?: string; __authError?: boolean }> {
try {
const { response, error } = await serverFetch(`${process.env.NEXT_PUBLIC_API_URL}/v1/processes/${id}`, {
method: 'GET',
cache: 'no-store',
});
if (error) {
return { success: false, error: error.message, __authError: error.code === 'UNAUTHORIZED' };
}
if (!response) {
return { success: false, error: '조회에 실패했습니다.' };
}
const result: ApiResponse<ApiProcess> = await response.json();
if (!response.ok || !result.success) {
return { success: false, error: result.message || '조회에 실패했습니다.' };
}
return { success: true, data: transformApiToFrontend(result.data) };
} catch (error) {
console.error('[getProcessById] Error:', error);
return { success: false, error: '서버 오류가 발생했습니다.' };
}
}
/**
* 공정 생성
*/
export async function createProcess(data: ProcessFormData): Promise<{ success: boolean; data?: Process; error?: string; __authError?: boolean }> {
try {
const apiData = transformFrontendToApi(data);
const { response, error } = await serverFetch(`${process.env.NEXT_PUBLIC_API_URL}/v1/processes`, {
method: 'POST',
body: JSON.stringify(apiData),
});
if (error) {
return { success: false, error: error.message, __authError: error.code === 'UNAUTHORIZED' };
}
if (!response) {
return { success: false, error: '등록에 실패했습니다.' };
}
const result: ApiResponse<ApiProcess> = await response.json();
if (!response.ok || !result.success) {
return { success: false, error: result.message || '등록에 실패했습니다.' };
}
return { success: true, data: transformApiToFrontend(result.data) };
} catch (error) {
console.error('[createProcess] Error:', error);
return { success: false, error: '서버 오류가 발생했습니다.' };
}
}
/**
* 공정 수정
*/
export async function updateProcess(id: string, data: ProcessFormData): Promise<{ success: boolean; data?: Process; error?: string; __authError?: boolean }> {
try {
const apiData = transformFrontendToApi(data);
const { response, error } = await serverFetch(`${process.env.NEXT_PUBLIC_API_URL}/v1/processes/${id}`, {
method: 'PUT',
body: JSON.stringify(apiData),
});
if (error) {
return { success: false, error: error.message, __authError: error.code === 'UNAUTHORIZED' };
}
if (!response) {
return { success: false, error: '수정에 실패했습니다.' };
}
const result: ApiResponse<ApiProcess> = await response.json();
if (!response.ok || !result.success) {
return { success: false, error: result.message || '수정에 실패했습니다.' };
}
return { success: true, data: transformApiToFrontend(result.data) };
} catch (error) {
console.error('[updateProcess] Error:', error);
return { success: false, error: '서버 오류가 발생했습니다.' };
}
}
/**
* 공정 삭제
*/
export async function deleteProcess(id: string): Promise<{ success: boolean; error?: string; __authError?: boolean }> {
try {
const { response, error } = await serverFetch(`${process.env.NEXT_PUBLIC_API_URL}/v1/processes/${id}`, {
method: 'DELETE',
});
if (error) {
return { success: false, error: error.message, __authError: error.code === 'UNAUTHORIZED' };
}
if (!response) {
return { success: false, error: '삭제에 실패했습니다.' };
}
const result: ApiResponse<null> = await response.json();
if (!response.ok || !result.success) {
return { success: false, error: result.message || '삭제에 실패했습니다.' };
}
return { success: true };
} catch (error) {
console.error('[deleteProcess] Error:', error);
return { success: false, error: '서버 오류가 발생했습니다.' };
}
}
/**
* 공정 일괄 삭제
*/
export async function deleteProcesses(ids: string[]): Promise<{ success: boolean; deletedCount?: number; error?: string; __authError?: boolean }> {
try {
const { response, error } = await serverFetch(`${process.env.NEXT_PUBLIC_API_URL}/v1/processes`, {
method: 'DELETE',
body: JSON.stringify({ ids: ids.map((id) => parseInt(id, 10)) }),
});
if (error) {
return { success: false, error: error.message, __authError: error.code === 'UNAUTHORIZED' };
}
if (!response) {
return { success: false, error: '일괄 삭제에 실패했습니다.' };
}
const result: ApiResponse<{ deleted_count: number }> = await response.json();
if (!response.ok || !result.success) {
return { success: false, error: result.message || '일괄 삭제에 실패했습니다.' };
}
return { success: true, deletedCount: result.data.deleted_count };
} catch (error) {
console.error('[deleteProcesses] Error:', error);
return { success: false, error: '서버 오류가 발생했습니다.' };
}
}
/**
* 공정 상태 토글
*/
export async function toggleProcessActive(id: string): Promise<{ success: boolean; data?: Process; error?: string; __authError?: boolean }> {
try {
const { response, error } = await serverFetch(`${process.env.NEXT_PUBLIC_API_URL}/v1/processes/${id}/toggle`, {
method: 'PATCH',
});
if (error) {
return { success: false, error: error.message, __authError: error.code === 'UNAUTHORIZED' };
}
if (!response) {
return { success: false, error: '상태 변경에 실패했습니다.' };
}
const result: ApiResponse<ApiProcess> = await response.json();
if (!response.ok || !result.success) {
return { success: false, error: result.message || '상태 변경에 실패했습니다.' };
}
return { success: true, data: transformApiToFrontend(result.data) };
} catch (error) {
console.error('[toggleProcessActive] Error:', error);
return { success: false, error: '서버 오류가 발생했습니다.' };
}
}
/**
* 공정 옵션 목록 (드롭다운용)
*/
export async function getProcessOptions(): Promise<{
success: boolean;
data?: Array<{ id: string; processCode: string; processName: string; processType: string; department: string }>;
error?: string;
__authError?: boolean;
}> {
try {
const { response, error } = await serverFetch(`${process.env.NEXT_PUBLIC_API_URL}/v1/processes/options`, {
method: 'GET',
cache: 'no-store',
});
if (error) {
return { success: false, error: error.message, __authError: error.code === 'UNAUTHORIZED' };
}
if (!response) {
return { success: false, error: '옵션 조회에 실패했습니다.' };
}
const result: ApiResponse<Array<{ id: number; process_code: string; process_name: string; process_type: string; department: string }>> =
await response.json();
if (!response.ok || !result.success) {
return { success: false, error: result.message || '옵션 조회에 실패했습니다.' };
}
return {
success: true,
data: result.data.map((item) => ({
id: String(item.id),
processCode: item.process_code,
processName: item.process_name,
processType: item.process_type,
department: item.department ?? '',
})),
};
} catch (error) {
console.error('[getProcessOptions] Error:', error);
return { success: false, error: '서버 오류가 발생했습니다.' };
}
}
/**
* 공정 통계
*/
export async function getProcessStats(): Promise<{
success: boolean;
data?: { total: number; active: number; inactive: number; byType: Record<string, number> };
error?: string;
__authError?: boolean;
}> {
try {
const { response, error } = await serverFetch(`${process.env.NEXT_PUBLIC_API_URL}/v1/processes/stats`, {
method: 'GET',
cache: 'no-store',
});
if (error) {
return { success: false, error: error.message, __authError: error.code === 'UNAUTHORIZED' };
}
if (!response) {
return { success: false, error: '통계 조회에 실패했습니다.' };
}
const result: ApiResponse<{ total: number; active: number; inactive: number; by_type: Record<string, number> }> = await response.json();
if (!response.ok || !result.success) {
return { success: false, error: result.message || '통계 조회에 실패했습니다.' };
}
return {
success: true,
data: {
total: result.data.total,
active: result.data.active,
inactive: result.data.inactive,
byType: result.data.by_type,
},
};
} catch (error) {
console.error('[getProcessStats] Error:', error);
return { success: false, error: '서버 오류가 발생했습니다.' };
}
}