차량 관리 (신규): - VehicleList/VehicleDetail: 차량 목록/상세 - ForkliftList/ForkliftDetail: 지게차 목록/상세 - VehicleLogList/VehicleLogDetail: 운행일지 목록/상세 - 관련 페이지 라우트 추가 (/vehicle-management/*) CEO 대시보드: - Enhanced 섹션 컴포넌트 적용 (아이콘 + 컬러 테마) - EnhancedStatusBoardSection, EnhancedDailyReportSection, EnhancedMonthlyExpenseSection - TodayIssueSection 개선 IntegratedDetailTemplate: - FieldInput, FieldRenderer 기능 확장 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
235 lines
7.3 KiB
TypeScript
235 lines
7.3 KiB
TypeScript
'use server';
|
|
|
|
/**
|
|
* 지게차 관리 서버 액션
|
|
* 레거시 5130 사이트 등록 폼 기준 (2025-01-28 스크린샷 검증)
|
|
*/
|
|
|
|
import { isNextRedirectError } from '@/lib/utils/redirect-error';
|
|
import type { Forklift, ForkliftFormData, ActionResponse, ListResponse } from '../types';
|
|
|
|
// ===== Mock 데이터 (5130 레거시 기준) =====
|
|
const mockForklifts: Forklift[] = [
|
|
{
|
|
id: '1',
|
|
vehicleNumber: '경기85사1234',
|
|
vehicleType: '3톤 디젤',
|
|
purchaseType: '회사 소유',
|
|
managerMain: '김지게',
|
|
managerSub: '이지게',
|
|
purchaseCompany: '두산산업차량',
|
|
purchaseCompanyContact: '031-123-4567',
|
|
totalMileage: '15000',
|
|
mileageRecordDate: '2025-01-15',
|
|
firstRegistrationDate: '2020-06-15',
|
|
purchaseDate: '2020-06-15',
|
|
partsChangeCycle: '500',
|
|
partsChangeRecords: [
|
|
{ id: 'p1', date: '2024-12-01', mileage: '14500', cost: '150000' },
|
|
{ id: 'p2', date: '2024-06-15', mileage: '12000', cost: '120000' },
|
|
],
|
|
maintenanceRecords: [
|
|
{ id: 'm1', date: '2024-12-15', description: '정기점검', cost: '50000' },
|
|
{ id: 'm2', date: '2024-10-01', description: '유압오일 교환', cost: '80000' },
|
|
],
|
|
remarks: '',
|
|
},
|
|
{
|
|
id: '2',
|
|
vehicleNumber: '경기85사5678',
|
|
vehicleType: '2.5톤 전동',
|
|
purchaseType: '렌트',
|
|
managerMain: '박지게',
|
|
managerSub: '',
|
|
purchaseCompany: '현대건설기계',
|
|
purchaseCompanyContact: '032-456-7890',
|
|
totalMileage: '8000',
|
|
mileageRecordDate: '2025-01-10',
|
|
firstRegistrationDate: '2021-03-20',
|
|
purchaseDate: '2023-03-20',
|
|
partsChangeCycle: '400',
|
|
partsChangeRecords: [
|
|
{ id: 'p3', date: '2025-01-15', mileage: '8000', cost: '200000' },
|
|
],
|
|
maintenanceRecords: [
|
|
{ id: 'm3', date: '2025-01-10', description: '배터리 점검', cost: '30000' },
|
|
],
|
|
remarks: '2025년 6월 렌트 만료',
|
|
},
|
|
{
|
|
id: '3',
|
|
vehicleNumber: '인천12가3456',
|
|
vehicleType: '1.5톤 LPG',
|
|
purchaseType: '리스',
|
|
managerMain: '최지게',
|
|
managerSub: '강지게',
|
|
purchaseCompany: '클라크코리아',
|
|
purchaseCompanyContact: '02-789-0123',
|
|
totalMileage: '3000',
|
|
mileageRecordDate: '2025-01-20',
|
|
firstRegistrationDate: '2024-01-10',
|
|
purchaseDate: '2024-01-10',
|
|
partsChangeCycle: '500',
|
|
partsChangeRecords: [],
|
|
maintenanceRecords: [],
|
|
remarks: '신규 도입',
|
|
},
|
|
];
|
|
|
|
// ===== 지게차 목록 조회 =====
|
|
export async function getForklifts(params?: {
|
|
page?: number;
|
|
perPage?: number;
|
|
search?: string;
|
|
}): Promise<ListResponse<Forklift>> {
|
|
try {
|
|
let filteredData = [...mockForklifts];
|
|
|
|
if (params?.search) {
|
|
const search = params.search.toLowerCase();
|
|
filteredData = filteredData.filter(
|
|
(f) =>
|
|
f.vehicleNumber.toLowerCase().includes(search) ||
|
|
f.vehicleType.toLowerCase().includes(search) ||
|
|
f.managerMain.toLowerCase().includes(search) ||
|
|
f.managerSub.toLowerCase().includes(search) ||
|
|
f.purchaseCompany.toLowerCase().includes(search)
|
|
);
|
|
}
|
|
|
|
return {
|
|
success: true,
|
|
data: filteredData,
|
|
totalCount: filteredData.length,
|
|
totalPages: 1,
|
|
};
|
|
} catch (error) {
|
|
if (isNextRedirectError(error)) throw error;
|
|
console.error('[ForkliftActions] getForklifts error:', error);
|
|
return {
|
|
success: false,
|
|
data: [],
|
|
totalCount: 0,
|
|
totalPages: 0,
|
|
error: '지게차 목록 조회 중 오류가 발생했습니다.',
|
|
};
|
|
}
|
|
}
|
|
|
|
// ===== 지게차 단건 조회 =====
|
|
export async function getForkliftById(id: string): Promise<ActionResponse<Forklift>> {
|
|
try {
|
|
const forklift = mockForklifts.find((f) => f.id === id);
|
|
if (!forklift) {
|
|
return { success: false, error: '지게차를 찾을 수 없습니다.' };
|
|
}
|
|
return { success: true, data: forklift };
|
|
} catch (error) {
|
|
if (isNextRedirectError(error)) throw error;
|
|
console.error('[ForkliftActions] getForkliftById error:', error);
|
|
return {
|
|
success: false,
|
|
error: '지게차 조회 중 오류가 발생했습니다.',
|
|
};
|
|
}
|
|
}
|
|
|
|
// ===== 지게차 생성 =====
|
|
export async function createForklift(
|
|
formData: Partial<ForkliftFormData>
|
|
): Promise<ActionResponse<Forklift>> {
|
|
try {
|
|
const newForklift: Forklift = {
|
|
id: String(Date.now()),
|
|
vehicleNumber: formData.vehicleNumber || '',
|
|
vehicleType: formData.vehicleType || '',
|
|
purchaseType: formData.purchaseType || '',
|
|
managerMain: formData.managerMain || '',
|
|
managerSub: formData.managerSub || '',
|
|
purchaseCompany: formData.purchaseCompany || '',
|
|
purchaseCompanyContact: formData.purchaseCompanyContact || '',
|
|
totalMileage: formData.totalMileage || '',
|
|
mileageRecordDate: formData.mileageRecordDate || '',
|
|
firstRegistrationDate: formData.firstRegistrationDate || '',
|
|
purchaseDate: formData.purchaseDate || '',
|
|
partsChangeCycle: formData.partsChangeCycle || '',
|
|
partsChangeRecords: formData.partsChangeRecords || [],
|
|
maintenanceRecords: formData.maintenanceRecords || [],
|
|
remarks: formData.remarks || '',
|
|
};
|
|
mockForklifts.push(newForklift);
|
|
return { success: true, data: newForklift };
|
|
} catch (error) {
|
|
if (isNextRedirectError(error)) throw error;
|
|
console.error('[ForkliftActions] createForklift error:', error);
|
|
return {
|
|
success: false,
|
|
error: '지게차 등록 중 오류가 발생했습니다.',
|
|
};
|
|
}
|
|
}
|
|
|
|
// ===== 지게차 수정 =====
|
|
export async function updateForklift(
|
|
id: string,
|
|
formData: Partial<ForkliftFormData>
|
|
): Promise<ActionResponse<Forklift>> {
|
|
try {
|
|
const index = mockForklifts.findIndex((f) => f.id === id);
|
|
if (index === -1) {
|
|
return { success: false, error: '지게차를 찾을 수 없습니다.' };
|
|
}
|
|
mockForklifts[index] = {
|
|
...mockForklifts[index],
|
|
...formData,
|
|
};
|
|
return { success: true, data: mockForklifts[index] };
|
|
} catch (error) {
|
|
if (isNextRedirectError(error)) throw error;
|
|
console.error('[ForkliftActions] updateForklift error:', error);
|
|
return {
|
|
success: false,
|
|
error: '지게차 수정 중 오류가 발생했습니다.',
|
|
};
|
|
}
|
|
}
|
|
|
|
// ===== 지게차 삭제 =====
|
|
export async function deleteForklift(id: string): Promise<ActionResponse> {
|
|
try {
|
|
const index = mockForklifts.findIndex((f) => f.id === id);
|
|
if (index === -1) {
|
|
return { success: false, error: '지게차를 찾을 수 없습니다.' };
|
|
}
|
|
mockForklifts.splice(index, 1);
|
|
return { success: true };
|
|
} catch (error) {
|
|
if (isNextRedirectError(error)) throw error;
|
|
console.error('[ForkliftActions] deleteForklift error:', error);
|
|
return {
|
|
success: false,
|
|
error: '지게차 삭제 중 오류가 발생했습니다.',
|
|
};
|
|
}
|
|
}
|
|
|
|
// ===== 지게차 일괄 삭제 =====
|
|
export async function bulkDeleteForklifts(ids: string[]): Promise<ActionResponse> {
|
|
try {
|
|
ids.forEach((id) => {
|
|
const index = mockForklifts.findIndex((f) => f.id === id);
|
|
if (index !== -1) {
|
|
mockForklifts.splice(index, 1);
|
|
}
|
|
});
|
|
return { success: true };
|
|
} catch (error) {
|
|
if (isNextRedirectError(error)) throw error;
|
|
console.error('[ForkliftActions] bulkDeleteForklifts error:', error);
|
|
return {
|
|
success: false,
|
|
error: '지게차 일괄 삭제 중 오류가 발생했습니다.',
|
|
};
|
|
}
|
|
}
|