feat(WEB): 수주 삭제 기능 추가 및 출하목록 데이터 수정
- 수주 상세 페이지에 삭제 기능 추가 - 수주등록/취소 상태에서 삭제 버튼 표시 - 삭제 확인 다이얼로그 구현 - 삭제 후 목록 페이지로 이동 - 출하목록 데이터 누락 수정 - 발주처/현장명 order_info 참조하도록 수정 - 배송방식 라벨 API 응답값 사용 - 공통코드 API 함수 추가 - getDeliveryMethodCodes, getDeliveryMethodOptions - getCodeLabel 유틸 함수
This commit is contained in:
@@ -35,6 +35,7 @@ import {
|
||||
ChevronDown,
|
||||
ChevronRight,
|
||||
ChevronsUpDown,
|
||||
Trash2,
|
||||
} from "lucide-react";
|
||||
import { toast } from "sonner";
|
||||
import { IntegratedDetailTemplate } from "@/components/templates/IntegratedDetailTemplate";
|
||||
@@ -64,6 +65,7 @@ import {
|
||||
updateOrderStatus,
|
||||
revertProductionOrder,
|
||||
revertOrderConfirmation,
|
||||
deleteOrder,
|
||||
type Order,
|
||||
type OrderStatus,
|
||||
} from "@/components/orders";
|
||||
@@ -115,6 +117,8 @@ export default function OrderDetailPage() {
|
||||
const [isReverting, setIsReverting] = useState(false);
|
||||
const [isRevertConfirmDialogOpen, setIsRevertConfirmDialogOpen] = useState(false);
|
||||
const [isRevertingConfirm, setIsRevertingConfirm] = useState(false);
|
||||
const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false);
|
||||
const [isDeleting, setIsDeleting] = useState(false);
|
||||
|
||||
// 취소 폼 상태
|
||||
const [cancelReason, setCancelReason] = useState("");
|
||||
@@ -296,6 +300,31 @@ export default function OrderDetailPage() {
|
||||
}
|
||||
};
|
||||
|
||||
// 수주 삭제
|
||||
const handleDelete = () => {
|
||||
setIsDeleteDialogOpen(true);
|
||||
};
|
||||
|
||||
const handleDeleteSubmit = async () => {
|
||||
if (order) {
|
||||
setIsDeleting(true);
|
||||
try {
|
||||
const result = await deleteOrder(order.id);
|
||||
if (result.success) {
|
||||
toast.success("수주가 삭제되었습니다.");
|
||||
router.push("/sales/order-management-sales");
|
||||
} else {
|
||||
toast.error(result.error || "수주 삭제에 실패했습니다.");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error deleting order:", error);
|
||||
toast.error("수주 삭제 중 오류가 발생했습니다.");
|
||||
} finally {
|
||||
setIsDeleting(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 문서 모달 열기
|
||||
const openDocumentModal = (type: OrderDocumentType) => {
|
||||
setDocumentType(type);
|
||||
@@ -727,6 +756,8 @@ export default function OrderDetailPage() {
|
||||
order.status !== "shipped" &&
|
||||
order.status !== "cancelled" &&
|
||||
order.status !== "production_ordered";
|
||||
// 삭제 버튼은 수주등록 또는 취소 상태에서 표시
|
||||
const showDeleteButton = order.status === "order_registered" || order.status === "cancelled";
|
||||
|
||||
return (
|
||||
<div className="flex items-center gap-2 flex-wrap">
|
||||
@@ -772,9 +803,15 @@ export default function OrderDetailPage() {
|
||||
취소
|
||||
</Button>
|
||||
)}
|
||||
{showDeleteButton && (
|
||||
<Button variant="outline" onClick={handleDelete} className="border-red-200 text-red-600 hover:border-red-300 hover:bg-red-50">
|
||||
<Trash2 className="h-4 w-4 mr-2" />
|
||||
삭제
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}, [order, handleEdit, handleConfirmOrder, handleProductionOrder, handleViewProductionOrder, handleRevertProduction, handleRevertConfirmation, handleCancel]);
|
||||
}, [order, handleEdit, handleConfirmOrder, handleProductionOrder, handleViewProductionOrder, handleRevertProduction, handleRevertConfirmation, handleCancel, handleDelete]);
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -1116,6 +1153,80 @@ export default function OrderDetailPage() {
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
||||
{/* 수주 삭제 다이얼로그 */}
|
||||
<Dialog open={isDeleteDialogOpen} onOpenChange={setIsDeleteDialogOpen}>
|
||||
<DialogContent className="max-w-md">
|
||||
<DialogHeader>
|
||||
<DialogTitle className="flex items-center gap-2">
|
||||
<Trash2 className="h-5 w-5 text-red-600" />
|
||||
수주 삭제
|
||||
</DialogTitle>
|
||||
</DialogHeader>
|
||||
|
||||
<div className="space-y-4">
|
||||
{/* 수주 정보 박스 */}
|
||||
<div className="border rounded-lg p-4 space-y-2 text-sm">
|
||||
<div className="flex justify-between">
|
||||
<span className="text-muted-foreground">수주번호</span>
|
||||
<span className="font-medium">{order.lotNumber}</span>
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
<span className="text-muted-foreground">발주처</span>
|
||||
<span>{order.client}</span>
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
<span className="text-muted-foreground">현장명</span>
|
||||
<span>{order.siteName}</span>
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
<span className="text-muted-foreground">총금액</span>
|
||||
<span className="font-medium text-green-600">
|
||||
{formatAmount(order.totalAmount || 0)}원
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex justify-between items-center">
|
||||
<span className="text-muted-foreground">현재 상태</span>
|
||||
{getOrderStatusBadge(order.status)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 경고 메시지 */}
|
||||
<div className="bg-red-50 border border-red-200 rounded-lg p-4 text-sm space-y-1">
|
||||
<p className="font-medium mb-2 text-red-700">⚠️ 삭제 시 주의사항</p>
|
||||
<ul className="space-y-1 text-red-600">
|
||||
<li>• 삭제된 수주는 복구할 수 없습니다</li>
|
||||
<li>• 관련된 모든 품목 정보가 함께 삭제됩니다</li>
|
||||
<li>• 이 작업은 되돌릴 수 없습니다</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{/* 확인 안내 */}
|
||||
<div className="bg-gray-100 border border-gray-200 rounded-lg p-4 text-sm">
|
||||
<p className="text-gray-700 font-medium">
|
||||
정말로 이 수주를 삭제하시겠습니까?
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<DialogFooter>
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={() => setIsDeleteDialogOpen(false)}
|
||||
>
|
||||
취소
|
||||
</Button>
|
||||
<Button
|
||||
onClick={handleDeleteSubmit}
|
||||
className="bg-red-600 hover:bg-red-700"
|
||||
disabled={isDeleting}
|
||||
>
|
||||
<Trash2 className="h-4 w-4 mr-1" />
|
||||
{isDeleting ? "삭제 중..." : "삭제 확정"}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
|
||||
Reference in New Issue
Block a user