Implement production plan listing feature with API and frontend integration

This commit is contained in:
kjs
2026-03-23 11:11:44 +09:00
parent ca2af56aad
commit aa48d40048
6 changed files with 1753 additions and 18 deletions

View File

@@ -2,7 +2,7 @@
* 생산계획 API 클라이언트
*/
import apiClient from "./client";
import { apiClient } from "./client";
// ─── 타입 정의 ───
@@ -94,10 +94,51 @@ export interface GenerateScheduleResponse {
deleted_count: number;
};
schedules: ProductionPlan[];
deletedSchedules?: ProductionPlan[];
keptSchedules?: ProductionPlan[];
}
// ─── API 함수 ───
/** 생산계획 목록 조회 */
export async function getPlans(params?: {
productType?: string;
status?: string;
startDate?: string;
endDate?: string;
itemCode?: string;
}) {
const queryParams = new URLSearchParams();
if (params?.productType) queryParams.set("productType", params.productType);
if (params?.status) queryParams.set("status", params.status);
if (params?.startDate) queryParams.set("startDate", params.startDate);
if (params?.endDate) queryParams.set("endDate", params.endDate);
if (params?.itemCode) queryParams.set("itemCode", params.itemCode);
const qs = queryParams.toString();
const url = `/production/plans${qs ? `?${qs}` : ""}`;
const response = await apiClient.get(url);
return response.data as { success: boolean; data: ProductionPlan[] };
}
/** 자동 스케줄 미리보기 (DB 변경 없이 예상 결과) */
export async function previewSchedule(request: GenerateScheduleRequest) {
const response = await apiClient.post("/production/generate-schedule/preview", request);
return response.data as { success: boolean; data: GenerateScheduleResponse };
}
/** 반제품 계획 미리보기 */
export async function previewSemiSchedule(
planIds: number[],
options?: { considerStock?: boolean; excludeUsed?: boolean }
) {
const response = await apiClient.post("/production/generate-semi-schedule/preview", {
plan_ids: planIds,
options: options || {},
});
return response.data as { success: boolean; data: { count: number; schedules: ProductionPlan[] } };
}
/** 수주 데이터 조회 (품목별 그룹핑) */
export async function getOrderSummary(params?: {
excludePlanned?: boolean;
@@ -110,44 +151,44 @@ export async function getOrderSummary(params?: {
if (params?.itemName) queryParams.set("itemName", params.itemName);
const qs = queryParams.toString();
const url = `/api/production/order-summary${qs ? `?${qs}` : ""}`;
const url = `/production/order-summary${qs ? `?${qs}` : ""}`;
const response = await apiClient.get(url);
return response.data as { success: boolean; data: OrderSummaryItem[] };
}
/** 안전재고 부족분 조회 */
export async function getStockShortage() {
const response = await apiClient.get("/api/production/stock-shortage");
const response = await apiClient.get("/production/stock-shortage");
return response.data as { success: boolean; data: StockShortageItem[] };
}
/** 생산계획 상세 조회 */
export async function getPlanById(planId: number) {
const response = await apiClient.get(`/api/production/plan/${planId}`);
const response = await apiClient.get(`/production/plan/${planId}`);
return response.data as { success: boolean; data: ProductionPlan };
}
/** 생산계획 수정 */
export async function updatePlan(planId: number, data: Partial<ProductionPlan>) {
const response = await apiClient.put(`/api/production/plan/${planId}`, data);
const response = await apiClient.put(`/production/plan/${planId}`, data);
return response.data as { success: boolean; data: ProductionPlan };
}
/** 생산계획 삭제 */
export async function deletePlan(planId: number) {
const response = await apiClient.delete(`/api/production/plan/${planId}`);
const response = await apiClient.delete(`/production/plan/${planId}`);
return response.data as { success: boolean; message: string };
}
/** 자동 스케줄 생성 */
export async function generateSchedule(request: GenerateScheduleRequest) {
const response = await apiClient.post("/api/production/generate-schedule", request);
const response = await apiClient.post("/production/generate-schedule", request);
return response.data as { success: boolean; data: GenerateScheduleResponse };
}
/** 스케줄 병합 */
export async function mergeSchedules(scheduleIds: number[], productType?: string) {
const response = await apiClient.post("/api/production/merge-schedules", {
const response = await apiClient.post("/production/merge-schedules", {
schedule_ids: scheduleIds,
product_type: productType || "완제품",
});
@@ -159,7 +200,7 @@ export async function generateSemiSchedule(
planIds: number[],
options?: { considerStock?: boolean; excludeUsed?: boolean }
) {
const response = await apiClient.post("/api/production/generate-semi-schedule", {
const response = await apiClient.post("/production/generate-semi-schedule", {
plan_ids: planIds,
options: options || {},
});
@@ -168,7 +209,7 @@ export async function generateSemiSchedule(
/** 스케줄 분할 */
export async function splitSchedule(planId: number, splitQty: number) {
const response = await apiClient.post(`/api/production/plan/${planId}/split`, {
const response = await apiClient.post(`/production/plan/${planId}/split`, {
split_qty: splitQty,
});
return response.data as {