feat(WEB): 주문/작업지시 공정 연동 개선

- process_id 필드 추가 (공정 연동)
- 공정별 다중 작업지시 생성 지원 (processIds)
- ApiProductionOrderResponse 타입 수정 (work_orders 배열 지원)
- process 정보 포함 응답 처리
This commit is contained in:
2026-01-13 19:47:39 +09:00
parent e162ad5a12
commit 81f7c5aeac
2 changed files with 42 additions and 18 deletions

View File

@@ -416,7 +416,7 @@ export function OrderRegistration({
<span>{form.selectedQuotation.siteName}</span>
<span className="text-muted-foreground mx-2">/</span>
<span className="text-green-600 font-medium">
{formatAmount(form.selectedQuotation.amount)}
{formatAmount(form.selectedQuotation.amount)}
</span>
</div>
</div>
@@ -491,6 +491,7 @@ export function OrderRegistration({
setForm((prev) => ({ ...prev, siteName: e.target.value }));
clearFieldError("siteName");
}}
disabled={!!form.selectedQuotation}
className={cn(fieldErrors.siteName && "border-red-500")}
/>
{fieldErrors.siteName && (
@@ -757,8 +758,6 @@ export function OrderRegistration({
<TableHead className="w-[60px] text-center"></TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead className="w-[80px] text-center"></TableHead>
<TableHead className="w-[60px] text-center"></TableHead>
@@ -770,7 +769,7 @@ export function OrderRegistration({
<TableBody>
{form.items.length === 0 ? (
<TableRow>
<TableCell colSpan={11} className="text-center py-8 text-muted-foreground">
<TableCell colSpan={9} className="text-center py-8 text-muted-foreground">
. .
</TableCell>
</TableRow>
@@ -784,8 +783,6 @@ export function OrderRegistration({
</code>
</TableCell>
<TableCell>{item.itemName}</TableCell>
<TableCell>{item.type || "-"}</TableCell>
<TableCell>{item.symbol || "-"}</TableCell>
<TableCell>{item.spec}</TableCell>
<TableCell className="text-center">
<Input
@@ -803,10 +800,10 @@ export function OrderRegistration({
</TableCell>
<TableCell className="text-center">{item.unit}</TableCell>
<TableCell className="text-right">
{formatAmount(item.unitPrice)}
{formatAmount(item.unitPrice)}
</TableCell>
<TableCell className="text-right font-medium">
{formatAmount(item.amount)}
{formatAmount(item.amount)}
</TableCell>
<TableCell>
<Button
@@ -838,7 +835,7 @@ export function OrderRegistration({
<div className="flex items-center gap-4 text-sm">
<span className="text-muted-foreground">:</span>
<span className="w-32 text-right">
{formatAmount(form.subtotal)}
{formatAmount(form.subtotal)}
</span>
</div>
<div className="flex items-center gap-4 text-sm">
@@ -860,7 +857,7 @@ export function OrderRegistration({
<div className="flex items-center gap-4 text-lg font-semibold">
<span>:</span>
<span className="w-32 text-right text-green-600">
{formatAmount(form.totalAmount)}
{formatAmount(form.totalAmount)}
</span>
</div>
</div>

View File

@@ -120,6 +120,7 @@ interface ApiWorkOrder {
work_order_no: string;
sales_order_id: number;
project_name: string | null;
process_id: number | null;
process_type: string;
status: string;
assignee_id: number | null;
@@ -131,10 +132,12 @@ interface ApiWorkOrder {
updated_at: string;
assignee?: { id: number; name: string } | null;
team?: { id: number; name: string } | null;
process?: { id: number; process_name: string } | null;
}
interface ApiProductionOrderResponse {
work_order: ApiWorkOrder;
work_order?: ApiWorkOrder;
work_orders?: ApiWorkOrder[];
order: ApiOrder;
}
@@ -292,7 +295,8 @@ export interface CreateFromQuoteData {
// 생산지시 생성용
export interface CreateProductionOrderData {
processType?: 'screen' | 'slat' | 'bending';
processId?: number;
processIds?: number[]; // 공정별 다중 작업지시 생성용
priority?: 'urgent' | 'high' | 'normal' | 'low';
assigneeId?: number;
teamId?: number;
@@ -306,6 +310,7 @@ export interface WorkOrder {
workOrderNo: string;
salesOrderId: number;
projectName: string | null;
processId?: number;
processType: string;
status: string;
assigneeId?: number;
@@ -317,11 +322,13 @@ export interface WorkOrder {
isActive: boolean;
createdAt: string;
updatedAt: string;
process?: { id: number; processName: string };
}
// 생산지시 생성 결과
export interface ProductionOrderResult {
workOrder: WorkOrder;
workOrder?: WorkOrder;
workOrders?: WorkOrder[];
order: Order;
}
@@ -514,6 +521,11 @@ function transformWorkOrderApiToFrontend(apiData: ApiWorkOrder): WorkOrder {
isActive: apiData.is_active,
createdAt: apiData.created_at,
updatedAt: apiData.updated_at,
processId: apiData.process_id ?? undefined,
process: apiData.process ? {
id: apiData.process.id,
processName: apiData.process.process_name,
} : undefined,
};
}
@@ -956,7 +968,12 @@ export async function createProductionOrder(
}> {
try {
const apiData: Record<string, unknown> = {};
if (data?.processType) apiData.process_type = data.processType;
// 다중 공정 ID (우선) 또는 단일 공정 ID
if (data?.processIds && data.processIds.length > 0) {
apiData.process_ids = data.processIds;
} else if (data?.processId) {
apiData.process_id = data.processId;
}
if (data?.priority) apiData.priority = data.priority;
if (data?.assigneeId) apiData.assignee_id = data.assigneeId;
if (data?.teamId) apiData.team_id = data.teamId;
@@ -982,12 +999,22 @@ export async function createProductionOrder(
return { success: false, error: result.message || '생산지시 생성에 실패했습니다.' };
}
// 다중 또는 단일 작업지시 응답 처리
const responseData: ProductionOrderResult = {
order: transformApiToFrontend(result.data.order),
};
if (result.data.work_orders && result.data.work_orders.length > 0) {
// 다중 작업지시 응답
responseData.workOrders = result.data.work_orders.map(transformWorkOrderApiToFrontend);
} else if (result.data.work_order) {
// 단일 작업지시 응답 (하위 호환성)
responseData.workOrder = transformWorkOrderApiToFrontend(result.data.work_order);
}
return {
success: true,
data: {
workOrder: transformWorkOrderApiToFrontend(result.data.work_order),
order: transformApiToFrontend(result.data.order),
},
data: responseData,
};
} catch (error) {
console.error('[createProductionOrder] Error:', error);