feat(WEB): 수주 Bulk Delete + Revert Force 프론트엔드 연동

- deleteOrders: for 루프 단건 삭제 → DELETE /api/v1/orders/bulk 단일 호출로 전환
- deleteOrders: force 옵션 추가 (개발환경 물리 삭제용)
- revertProductionOrder: force/reason 파라미터 추가
- 수주 상세: 되돌리기 다이얼로그에 사유 Textarea 추가
- 수주 상세: 개발환경 전용 "완전삭제 (DEV)" 버튼 추가
- 수주 목록: 개발환경 전용 selectionActions "완전삭제 (DEV)" 버튼 추가
This commit is contained in:
2026-02-21 08:56:44 +09:00
parent bb4acac3c1
commit 7d7d5356ff
3 changed files with 158 additions and 35 deletions

View File

@@ -959,37 +959,40 @@ export async function getOrderStats(): Promise<{
}
/**
* 수주 일괄 삭제
* 수주 일괄 삭제 (Bulk API)
*/
export async function deleteOrders(ids: string[]): Promise<{
export async function deleteOrders(
ids: string[],
options?: { force?: boolean }
): Promise<{
success: boolean;
deletedCount?: number;
skippedCount?: number;
skippedIds?: number[];
error?: string;
__authError?: boolean;
}> {
try {
// 순차적으로 삭제 (API에 bulk delete가 없으므로)
let deletedCount = 0;
const errors: string[] = [];
for (const id of ids) {
const result = await deleteOrder(id);
if (result.success) {
deletedCount++;
} else {
errors.push(result.error || `ID ${id} 삭제 실패`);
}
}
if (deletedCount === 0 && errors.length > 0) {
return { success: false, error: errors[0] };
}
return { success: true, deletedCount };
} catch (error) {
console.error('[deleteOrders] Error:', error);
return { success: false, error: '서버 오류가 발생했습니다.' };
interface BulkDeleteResponse {
deleted_count: number;
skipped_count: number;
skipped_ids: number[];
}
const body: Record<string, unknown> = { ids: ids.map(Number) };
if (options?.force) body.force = true;
const result = await executeServerAction<BulkDeleteResponse>({
url: buildApiUrl('/api/v1/orders/bulk'),
method: 'DELETE',
body,
errorMessage: '수주 일괄 삭제에 실패했습니다.',
});
if (result.__authError) return { success: false, __authError: true };
if (!result.success || !result.data) return { success: false, error: result.error };
return {
success: true,
deletedCount: result.data.deleted_count,
skippedCount: result.data.skipped_count,
skippedIds: result.data.skipped_ids,
};
}
/**
@@ -1071,7 +1074,10 @@ export async function createProductionOrder(
/**
* 생산지시 되돌리기 (작업지시 및 관련 데이터 삭제)
*/
export async function revertProductionOrder(orderId: string): Promise<{
export async function revertProductionOrder(
orderId: string,
options?: { force?: boolean; reason?: string }
): Promise<{
success: boolean;
data?: {
order: Order;
@@ -1084,11 +1090,16 @@ export async function revertProductionOrder(orderId: string): Promise<{
interface RevertResponse {
order: ApiOrder;
deleted_counts: { work_results: number; work_order_items: number; work_orders: number };
cancelled_counts?: { work_orders: number; work_order_items: number };
previous_status: string;
}
const body: Record<string, unknown> = {};
if (options?.force !== undefined) body.force = options.force;
if (options?.reason) body.reason = options.reason;
const result = await executeServerAction<RevertResponse>({
url: buildApiUrl(`/api/v1/orders/${orderId}/revert-production`),
method: 'POST',
body: Object.keys(body).length > 0 ? body : undefined,
errorMessage: '생산지시 되돌리기에 실패했습니다.',
});
if (result.__authError) return { success: false, __authError: true };