2026-01-20 09:00:27 +09:00
|
|
|
"use client";
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 수주 상세 보기 컴포넌트 (View Mode)
|
feat(WEB): Phase 6 IntegratedDetailTemplate 마이그레이션 완료
Phase 6 마이그레이션 (41개 컴포넌트 완료):
- 건설/시공: 협력업체, 시공관리, 기성관리, 발주관리, 계약관리 등
- 영업: 견적관리(V2), 고객관리(V2), 수주관리
- 회계: 청구관리, 매입관리, 매출관리, 거래처관리, 악성채권 등
- 생산: 작업지시, 검수관리
- 출고: 출하관리
- 자재: 입고관리, 재고현황
- 고객센터: 문의관리, 이벤트관리, 공지관리
- 인사: 직원관리
- 설정: 권한관리
주요 변경사항:
- 34개 xxxConfig.ts 파일 생성 (설정 기반 페이지 구성)
- PageLayout/PageHeader → IntegratedDetailTemplate 통합
- 일관된 타이틀/버튼 영역 (목록, 상세, 수정, 삭제)
- 1112줄 코드 감소 (중복 제거)
프로젝트 공통화 현황 분석 문서 추가:
- 상세 페이지 62%, 목록 페이지 82% 공통화 달성
- 추가 공통화 기회 및 로드맵 정리
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-20 15:51:02 +09:00
|
|
|
* IntegratedDetailTemplate 마이그레이션 완료 (2026-01-20)
|
2026-01-20 09:00:27 +09:00
|
|
|
*
|
|
|
|
|
* - 문서 모달: 계약서, 거래명세서, 발주서
|
|
|
|
|
* - 기본 정보, 수주/배송 정보, 비고
|
|
|
|
|
* - 제품 내역 테이블
|
|
|
|
|
* - 상태별 버튼 차이
|
|
|
|
|
*/
|
|
|
|
|
|
feat(WEB): Phase 6 IntegratedDetailTemplate 마이그레이션 완료
Phase 6 마이그레이션 (41개 컴포넌트 완료):
- 건설/시공: 협력업체, 시공관리, 기성관리, 발주관리, 계약관리 등
- 영업: 견적관리(V2), 고객관리(V2), 수주관리
- 회계: 청구관리, 매입관리, 매출관리, 거래처관리, 악성채권 등
- 생산: 작업지시, 검수관리
- 출고: 출하관리
- 자재: 입고관리, 재고현황
- 고객센터: 문의관리, 이벤트관리, 공지관리
- 인사: 직원관리
- 설정: 권한관리
주요 변경사항:
- 34개 xxxConfig.ts 파일 생성 (설정 기반 페이지 구성)
- PageLayout/PageHeader → IntegratedDetailTemplate 통합
- 일관된 타이틀/버튼 영역 (목록, 상세, 수정, 삭제)
- 1112줄 코드 감소 (중복 제거)
프로젝트 공통화 현황 분석 문서 추가:
- 상세 페이지 62%, 목록 페이지 82% 공통화 달성
- 추가 공통화 기회 및 로드맵 정리
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-20 15:51:02 +09:00
|
|
|
import { useState, useEffect, useMemo, useCallback } from "react";
|
2026-01-20 09:00:27 +09:00
|
|
|
import { useRouter } from "next/navigation";
|
|
|
|
|
import { Button } from "@/components/ui/button";
|
|
|
|
|
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
|
|
|
|
import {
|
|
|
|
|
Table,
|
|
|
|
|
TableBody,
|
|
|
|
|
TableCell,
|
|
|
|
|
TableHead,
|
|
|
|
|
TableHeader,
|
|
|
|
|
TableRow,
|
|
|
|
|
} from "@/components/ui/table";
|
|
|
|
|
import {
|
|
|
|
|
FileText,
|
|
|
|
|
Factory,
|
|
|
|
|
XCircle,
|
|
|
|
|
FileSpreadsheet,
|
|
|
|
|
FileCheck,
|
|
|
|
|
ClipboardList,
|
|
|
|
|
CheckCircle2,
|
|
|
|
|
} from "lucide-react";
|
|
|
|
|
import { toast } from "sonner";
|
feat(WEB): Phase 6 IntegratedDetailTemplate 마이그레이션 완료
Phase 6 마이그레이션 (41개 컴포넌트 완료):
- 건설/시공: 협력업체, 시공관리, 기성관리, 발주관리, 계약관리 등
- 영업: 견적관리(V2), 고객관리(V2), 수주관리
- 회계: 청구관리, 매입관리, 매출관리, 거래처관리, 악성채권 등
- 생산: 작업지시, 검수관리
- 출고: 출하관리
- 자재: 입고관리, 재고현황
- 고객센터: 문의관리, 이벤트관리, 공지관리
- 인사: 직원관리
- 설정: 권한관리
주요 변경사항:
- 34개 xxxConfig.ts 파일 생성 (설정 기반 페이지 구성)
- PageLayout/PageHeader → IntegratedDetailTemplate 통합
- 일관된 타이틀/버튼 영역 (목록, 상세, 수정, 삭제)
- 1112줄 코드 감소 (중복 제거)
프로젝트 공통화 현황 분석 문서 추가:
- 상세 페이지 62%, 목록 페이지 82% 공통화 달성
- 추가 공통화 기회 및 로드맵 정리
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-20 15:51:02 +09:00
|
|
|
import { IntegratedDetailTemplate } from "@/components/templates/IntegratedDetailTemplate";
|
|
|
|
|
import { orderSalesConfig } from "./orderSalesConfig";
|
2026-01-20 09:00:27 +09:00
|
|
|
import { BadgeSm } from "@/components/atoms/BadgeSm";
|
|
|
|
|
import { formatAmount } from "@/utils/formatAmount";
|
|
|
|
|
import {
|
|
|
|
|
Dialog,
|
|
|
|
|
DialogContent,
|
|
|
|
|
DialogHeader,
|
|
|
|
|
DialogTitle,
|
|
|
|
|
DialogFooter,
|
|
|
|
|
} from "@/components/ui/dialog";
|
|
|
|
|
import { Label } from "@/components/ui/label";
|
|
|
|
|
import {
|
|
|
|
|
Select,
|
|
|
|
|
SelectContent,
|
|
|
|
|
SelectItem,
|
|
|
|
|
SelectTrigger,
|
|
|
|
|
SelectValue,
|
|
|
|
|
} from "@/components/ui/select";
|
|
|
|
|
import { Textarea } from "@/components/ui/textarea";
|
|
|
|
|
import {
|
|
|
|
|
OrderDocumentModal,
|
|
|
|
|
type OrderDocumentType,
|
|
|
|
|
getOrderById,
|
|
|
|
|
updateOrderStatus,
|
|
|
|
|
type Order,
|
|
|
|
|
type OrderStatus,
|
|
|
|
|
} from "@/components/orders";
|
|
|
|
|
import { ServerErrorPage } from "@/components/common/ServerErrorPage";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 상태 뱃지 헬퍼
|
|
|
|
|
function getOrderStatusBadge(status: OrderStatus) {
|
|
|
|
|
const statusConfig: Record<OrderStatus, { label: string; className: string }> = {
|
|
|
|
|
order_registered: { label: "수주등록", className: "bg-gray-100 text-gray-700 border-gray-200" },
|
|
|
|
|
order_confirmed: { label: "수주확정", className: "bg-gray-100 text-gray-700 border-gray-200" },
|
|
|
|
|
production_ordered: { label: "생산지시완료", className: "bg-blue-100 text-blue-700 border-blue-200" },
|
|
|
|
|
in_production: { label: "생산중", className: "bg-green-100 text-green-700 border-green-200" },
|
|
|
|
|
rework: { label: "재작업중", className: "bg-orange-100 text-orange-700 border-orange-200" },
|
|
|
|
|
work_completed: { label: "작업완료", className: "bg-blue-600 text-white border-blue-600" },
|
|
|
|
|
shipped: { label: "출하완료", className: "bg-gray-500 text-white border-gray-500" },
|
|
|
|
|
cancelled: { label: "취소", className: "bg-red-100 text-red-700 border-red-200" },
|
|
|
|
|
};
|
|
|
|
|
const config = statusConfig[status];
|
|
|
|
|
return (
|
|
|
|
|
<BadgeSm className={config.className}>
|
|
|
|
|
{config.label}
|
|
|
|
|
</BadgeSm>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 정보 표시 컴포넌트
|
|
|
|
|
function InfoItem({ label, value }: { label: string; value: string }) {
|
|
|
|
|
return (
|
|
|
|
|
<div>
|
|
|
|
|
<p className="text-sm text-muted-foreground">{label}</p>
|
|
|
|
|
<p className="font-medium">{value || "-"}</p>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
interface OrderSalesDetailViewProps {
|
|
|
|
|
orderId: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function OrderSalesDetailView({ orderId }: OrderSalesDetailViewProps) {
|
|
|
|
|
const router = useRouter();
|
|
|
|
|
|
|
|
|
|
const [order, setOrder] = useState<Order | null>(null);
|
|
|
|
|
const [loading, setLoading] = useState(true);
|
|
|
|
|
const [isCancelDialogOpen, setIsCancelDialogOpen] = useState(false);
|
|
|
|
|
const [isCancelling, setIsCancelling] = useState(false);
|
|
|
|
|
const [isConfirmDialogOpen, setIsConfirmDialogOpen] = useState(false);
|
|
|
|
|
const [isConfirming, setIsConfirming] = useState(false);
|
|
|
|
|
|
|
|
|
|
// 취소 폼 상태
|
|
|
|
|
const [cancelReason, setCancelReason] = useState("");
|
|
|
|
|
const [cancelDetail, setCancelDetail] = useState("");
|
|
|
|
|
|
|
|
|
|
// 문서 모달 상태
|
|
|
|
|
const [documentModalOpen, setDocumentModalOpen] = useState(false);
|
|
|
|
|
const [documentType, setDocumentType] = useState<OrderDocumentType>("contract");
|
|
|
|
|
|
|
|
|
|
// 데이터 로드 (API 호출)
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
async function loadOrder() {
|
|
|
|
|
try {
|
|
|
|
|
setLoading(true);
|
|
|
|
|
const result = await getOrderById(orderId);
|
|
|
|
|
if (result.success && result.data) {
|
|
|
|
|
setOrder(result.data);
|
|
|
|
|
} else {
|
|
|
|
|
toast.error(result.error || "수주 정보를 불러오는데 실패했습니다.");
|
|
|
|
|
setOrder(null);
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error("Error loading order:", error);
|
|
|
|
|
toast.error("수주 정보를 불러오는 중 오류가 발생했습니다.");
|
|
|
|
|
setOrder(null);
|
|
|
|
|
} finally {
|
|
|
|
|
setLoading(false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
loadOrder();
|
|
|
|
|
}, [orderId]);
|
|
|
|
|
|
|
|
|
|
const handleBack = () => {
|
|
|
|
|
router.push("/sales/order-management-sales");
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleEdit = () => {
|
|
|
|
|
// V2 패턴: ?mode=edit로 이동
|
|
|
|
|
router.push(`/sales/order-management-sales/${orderId}?mode=edit`);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleProductionOrder = () => {
|
|
|
|
|
// 생산지시 생성 페이지로 이동
|
|
|
|
|
router.push(`/sales/order-management-sales/${orderId}/production-order`);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleViewProductionOrder = () => {
|
|
|
|
|
// 생산지시 목록 페이지로 이동 (수주관리 내부)
|
|
|
|
|
router.push(`/sales/order-management-sales/production-orders`);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleCancel = () => {
|
|
|
|
|
setCancelReason("");
|
|
|
|
|
setCancelDetail("");
|
|
|
|
|
setIsCancelDialogOpen(true);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleConfirmCancel = async () => {
|
|
|
|
|
if (!cancelReason) {
|
|
|
|
|
toast.error("취소 사유를 선택해주세요.");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (order) {
|
|
|
|
|
setIsCancelling(true);
|
|
|
|
|
try {
|
|
|
|
|
const result = await updateOrderStatus(order.id, "cancelled");
|
|
|
|
|
if (result.success) {
|
|
|
|
|
setOrder({ ...order, status: "cancelled" });
|
|
|
|
|
toast.success("수주가 취소되었습니다.");
|
|
|
|
|
setIsCancelDialogOpen(false);
|
|
|
|
|
setCancelReason("");
|
|
|
|
|
setCancelDetail("");
|
|
|
|
|
} else {
|
|
|
|
|
toast.error(result.error || "수주 취소에 실패했습니다.");
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error("Error cancelling order:", error);
|
|
|
|
|
toast.error("수주 취소 중 오류가 발생했습니다.");
|
|
|
|
|
} finally {
|
|
|
|
|
setIsCancelling(false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 수주 확정 처리
|
|
|
|
|
const handleConfirmOrder = () => {
|
|
|
|
|
setIsConfirmDialogOpen(true);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleConfirmOrderSubmit = async () => {
|
|
|
|
|
if (order) {
|
|
|
|
|
setIsConfirming(true);
|
|
|
|
|
try {
|
|
|
|
|
const result = await updateOrderStatus(order.id, "order_confirmed");
|
|
|
|
|
if (result.success && result.data) {
|
|
|
|
|
setOrder(result.data);
|
|
|
|
|
toast.success("수주가 확정되었습니다.");
|
|
|
|
|
setIsConfirmDialogOpen(false);
|
|
|
|
|
} else {
|
|
|
|
|
toast.error(result.error || "수주 확정에 실패했습니다.");
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error("Error confirming order:", error);
|
|
|
|
|
toast.error("수주 확정 중 오류가 발생했습니다.");
|
|
|
|
|
} finally {
|
|
|
|
|
setIsConfirming(false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 문서 모달 열기
|
feat(WEB): Phase 6 IntegratedDetailTemplate 마이그레이션 완료
Phase 6 마이그레이션 (41개 컴포넌트 완료):
- 건설/시공: 협력업체, 시공관리, 기성관리, 발주관리, 계약관리 등
- 영업: 견적관리(V2), 고객관리(V2), 수주관리
- 회계: 청구관리, 매입관리, 매출관리, 거래처관리, 악성채권 등
- 생산: 작업지시, 검수관리
- 출고: 출하관리
- 자재: 입고관리, 재고현황
- 고객센터: 문의관리, 이벤트관리, 공지관리
- 인사: 직원관리
- 설정: 권한관리
주요 변경사항:
- 34개 xxxConfig.ts 파일 생성 (설정 기반 페이지 구성)
- PageLayout/PageHeader → IntegratedDetailTemplate 통합
- 일관된 타이틀/버튼 영역 (목록, 상세, 수정, 삭제)
- 1112줄 코드 감소 (중복 제거)
프로젝트 공통화 현황 분석 문서 추가:
- 상세 페이지 62%, 목록 페이지 82% 공통화 달성
- 추가 공통화 기회 및 로드맵 정리
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-20 15:51:02 +09:00
|
|
|
const openDocumentModal = useCallback((type: OrderDocumentType) => {
|
2026-01-20 09:00:27 +09:00
|
|
|
setDocumentType(type);
|
|
|
|
|
setDocumentModalOpen(true);
|
feat(WEB): Phase 6 IntegratedDetailTemplate 마이그레이션 완료
Phase 6 마이그레이션 (41개 컴포넌트 완료):
- 건설/시공: 협력업체, 시공관리, 기성관리, 발주관리, 계약관리 등
- 영업: 견적관리(V2), 고객관리(V2), 수주관리
- 회계: 청구관리, 매입관리, 매출관리, 거래처관리, 악성채권 등
- 생산: 작업지시, 검수관리
- 출고: 출하관리
- 자재: 입고관리, 재고현황
- 고객센터: 문의관리, 이벤트관리, 공지관리
- 인사: 직원관리
- 설정: 권한관리
주요 변경사항:
- 34개 xxxConfig.ts 파일 생성 (설정 기반 페이지 구성)
- PageLayout/PageHeader → IntegratedDetailTemplate 통합
- 일관된 타이틀/버튼 영역 (목록, 상세, 수정, 삭제)
- 1112줄 코드 감소 (중복 제거)
프로젝트 공통화 현황 분석 문서 추가:
- 상세 페이지 62%, 목록 페이지 82% 공통화 달성
- 추가 공통화 기회 및 로드맵 정리
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-20 15:51:02 +09:00
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
// 동적 config (상태별 수정 버튼 표시)
|
|
|
|
|
const dynamicConfig = useMemo(() => {
|
|
|
|
|
const canEdit = order?.status !== "shipped" && order?.status !== "cancelled";
|
|
|
|
|
return {
|
|
|
|
|
...orderSalesConfig,
|
|
|
|
|
actions: {
|
|
|
|
|
...orderSalesConfig.actions,
|
|
|
|
|
showEdit: canEdit,
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
}, [order?.status]);
|
|
|
|
|
|
|
|
|
|
// 커스텀 헤더 액션 (상태별 버튼들)
|
|
|
|
|
const customHeaderActions = useMemo(() => {
|
|
|
|
|
if (!order) return null;
|
|
|
|
|
|
|
|
|
|
const showConfirmButton = order.status === "order_registered";
|
|
|
|
|
const showProductionCreateButton =
|
|
|
|
|
order.status !== "shipped" &&
|
|
|
|
|
order.status !== "cancelled" &&
|
|
|
|
|
order.status !== "production_ordered";
|
|
|
|
|
const showCancelButton =
|
|
|
|
|
order.status !== "shipped" &&
|
|
|
|
|
order.status !== "cancelled" &&
|
|
|
|
|
order.status !== "production_ordered";
|
2026-01-20 09:00:27 +09:00
|
|
|
|
|
|
|
|
return (
|
feat(WEB): Phase 6 IntegratedDetailTemplate 마이그레이션 완료
Phase 6 마이그레이션 (41개 컴포넌트 완료):
- 건설/시공: 협력업체, 시공관리, 기성관리, 발주관리, 계약관리 등
- 영업: 견적관리(V2), 고객관리(V2), 수주관리
- 회계: 청구관리, 매입관리, 매출관리, 거래처관리, 악성채권 등
- 생산: 작업지시, 검수관리
- 출고: 출하관리
- 자재: 입고관리, 재고현황
- 고객센터: 문의관리, 이벤트관리, 공지관리
- 인사: 직원관리
- 설정: 권한관리
주요 변경사항:
- 34개 xxxConfig.ts 파일 생성 (설정 기반 페이지 구성)
- PageLayout/PageHeader → IntegratedDetailTemplate 통합
- 일관된 타이틀/버튼 영역 (목록, 상세, 수정, 삭제)
- 1112줄 코드 감소 (중복 제거)
프로젝트 공통화 현황 분석 문서 추가:
- 상세 페이지 62%, 목록 페이지 82% 공통화 달성
- 추가 공통화 기회 및 로드맵 정리
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-20 15:51:02 +09:00
|
|
|
<>
|
|
|
|
|
{showConfirmButton && (
|
|
|
|
|
<Button onClick={handleConfirmOrder} className="bg-green-600 hover:bg-green-700">
|
|
|
|
|
<CheckCircle2 className="h-4 w-4 mr-2" />
|
|
|
|
|
수주 확정
|
|
|
|
|
</Button>
|
|
|
|
|
)}
|
|
|
|
|
{showProductionCreateButton && (
|
|
|
|
|
<Button onClick={handleProductionOrder}>
|
|
|
|
|
<Factory className="h-4 w-4 mr-2" />
|
|
|
|
|
생산지시 생성
|
|
|
|
|
</Button>
|
|
|
|
|
)}
|
|
|
|
|
{showCancelButton && (
|
|
|
|
|
<Button variant="outline" onClick={handleCancel} className="border-orange-200 text-orange-600 hover:border-orange-300">
|
|
|
|
|
<XCircle className="h-4 w-4 mr-2" />
|
|
|
|
|
취소
|
|
|
|
|
</Button>
|
|
|
|
|
)}
|
|
|
|
|
</>
|
2026-01-20 09:00:27 +09:00
|
|
|
);
|
feat(WEB): Phase 6 IntegratedDetailTemplate 마이그레이션 완료
Phase 6 마이그레이션 (41개 컴포넌트 완료):
- 건설/시공: 협력업체, 시공관리, 기성관리, 발주관리, 계약관리 등
- 영업: 견적관리(V2), 고객관리(V2), 수주관리
- 회계: 청구관리, 매입관리, 매출관리, 거래처관리, 악성채권 등
- 생산: 작업지시, 검수관리
- 출고: 출하관리
- 자재: 입고관리, 재고현황
- 고객센터: 문의관리, 이벤트관리, 공지관리
- 인사: 직원관리
- 설정: 권한관리
주요 변경사항:
- 34개 xxxConfig.ts 파일 생성 (설정 기반 페이지 구성)
- PageLayout/PageHeader → IntegratedDetailTemplate 통합
- 일관된 타이틀/버튼 영역 (목록, 상세, 수정, 삭제)
- 1112줄 코드 감소 (중복 제거)
프로젝트 공통화 현황 분석 문서 추가:
- 상세 페이지 62%, 목록 페이지 82% 공통화 달성
- 추가 공통화 기회 및 로드맵 정리
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-20 15:51:02 +09:00
|
|
|
}, [order, handleConfirmOrder, handleProductionOrder, handleCancel]);
|
2026-01-20 09:00:27 +09:00
|
|
|
|
feat(WEB): Phase 6 IntegratedDetailTemplate 마이그레이션 완료
Phase 6 마이그레이션 (41개 컴포넌트 완료):
- 건설/시공: 협력업체, 시공관리, 기성관리, 발주관리, 계약관리 등
- 영업: 견적관리(V2), 고객관리(V2), 수주관리
- 회계: 청구관리, 매입관리, 매출관리, 거래처관리, 악성채권 등
- 생산: 작업지시, 검수관리
- 출고: 출하관리
- 자재: 입고관리, 재고현황
- 고객센터: 문의관리, 이벤트관리, 공지관리
- 인사: 직원관리
- 설정: 권한관리
주요 변경사항:
- 34개 xxxConfig.ts 파일 생성 (설정 기반 페이지 구성)
- PageLayout/PageHeader → IntegratedDetailTemplate 통합
- 일관된 타이틀/버튼 영역 (목록, 상세, 수정, 삭제)
- 1112줄 코드 감소 (중복 제거)
프로젝트 공통화 현황 분석 문서 추가:
- 상세 페이지 62%, 목록 페이지 82% 공통화 달성
- 추가 공통화 기회 및 로드맵 정리
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-20 15:51:02 +09:00
|
|
|
// 폼 콘텐츠 렌더링
|
|
|
|
|
const renderFormContent = useCallback(() => {
|
|
|
|
|
if (!order) return null;
|
2026-01-20 09:00:27 +09:00
|
|
|
|
feat(WEB): Phase 6 IntegratedDetailTemplate 마이그레이션 완료
Phase 6 마이그레이션 (41개 컴포넌트 완료):
- 건설/시공: 협력업체, 시공관리, 기성관리, 발주관리, 계약관리 등
- 영업: 견적관리(V2), 고객관리(V2), 수주관리
- 회계: 청구관리, 매입관리, 매출관리, 거래처관리, 악성채권 등
- 생산: 작업지시, 검수관리
- 출고: 출하관리
- 자재: 입고관리, 재고현황
- 고객센터: 문의관리, 이벤트관리, 공지관리
- 인사: 직원관리
- 설정: 권한관리
주요 변경사항:
- 34개 xxxConfig.ts 파일 생성 (설정 기반 페이지 구성)
- PageLayout/PageHeader → IntegratedDetailTemplate 통합
- 일관된 타이틀/버튼 영역 (목록, 상세, 수정, 삭제)
- 1112줄 코드 감소 (중복 제거)
프로젝트 공통화 현황 분석 문서 추가:
- 상세 페이지 62%, 목록 페이지 82% 공통화 달성
- 추가 공통화 기회 및 로드맵 정리
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-20 15:51:02 +09:00
|
|
|
return (
|
2026-01-20 09:00:27 +09:00
|
|
|
<div className="space-y-6">
|
|
|
|
|
{/* 수주 정보 헤더 */}
|
|
|
|
|
<Card>
|
|
|
|
|
<CardHeader className="pb-4">
|
|
|
|
|
<div className="flex items-center justify-between flex-wrap gap-2">
|
|
|
|
|
<div className="flex items-center gap-3">
|
|
|
|
|
<code className="text-sm font-mono bg-gray-100 px-2 py-1 rounded">
|
|
|
|
|
{order.lotNumber}
|
|
|
|
|
</code>
|
|
|
|
|
{getOrderStatusBadge(order.status)}
|
|
|
|
|
</div>
|
|
|
|
|
<div className="text-sm text-muted-foreground">
|
|
|
|
|
수주일: {order.orderDate}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</CardHeader>
|
|
|
|
|
<CardContent className="pt-0">
|
|
|
|
|
{/* 문서 버튼들 */}
|
|
|
|
|
<div className="flex items-center gap-2 pt-4 border-t">
|
|
|
|
|
<span className="text-sm text-muted-foreground mr-2">문서:</span>
|
|
|
|
|
<Button
|
|
|
|
|
variant="outline"
|
|
|
|
|
size="sm"
|
|
|
|
|
onClick={() => openDocumentModal("contract")}
|
|
|
|
|
>
|
|
|
|
|
<FileCheck className="h-4 w-4 mr-1" />
|
|
|
|
|
계약서
|
|
|
|
|
</Button>
|
|
|
|
|
<Button
|
|
|
|
|
variant="outline"
|
|
|
|
|
size="sm"
|
|
|
|
|
onClick={() => openDocumentModal("transaction")}
|
|
|
|
|
>
|
|
|
|
|
<FileSpreadsheet className="h-4 w-4 mr-1" />
|
|
|
|
|
거래명세서
|
|
|
|
|
</Button>
|
|
|
|
|
<Button
|
|
|
|
|
variant="outline"
|
|
|
|
|
size="sm"
|
|
|
|
|
onClick={() => openDocumentModal("purchaseOrder")}
|
|
|
|
|
>
|
|
|
|
|
<ClipboardList className="h-4 w-4 mr-1" />
|
|
|
|
|
발주서
|
|
|
|
|
</Button>
|
|
|
|
|
</div>
|
|
|
|
|
</CardContent>
|
|
|
|
|
</Card>
|
|
|
|
|
|
|
|
|
|
{/* 기본 정보 */}
|
|
|
|
|
<Card>
|
|
|
|
|
<CardHeader>
|
|
|
|
|
<CardTitle className="text-lg">기본 정보</CardTitle>
|
|
|
|
|
</CardHeader>
|
|
|
|
|
<CardContent>
|
|
|
|
|
<div className="grid grid-cols-2 md:grid-cols-4 gap-6">
|
|
|
|
|
<InfoItem label="발주처" value={order.client} />
|
|
|
|
|
<InfoItem label="현장명" value={order.siteName} />
|
|
|
|
|
<InfoItem label="담당자" value={order.manager} />
|
|
|
|
|
<InfoItem label="연락처" value={order.contact} />
|
|
|
|
|
</div>
|
|
|
|
|
</CardContent>
|
|
|
|
|
</Card>
|
|
|
|
|
|
|
|
|
|
{/* 수주/배송 정보 */}
|
|
|
|
|
<Card>
|
|
|
|
|
<CardHeader>
|
|
|
|
|
<CardTitle className="text-lg">수주/배송 정보</CardTitle>
|
|
|
|
|
</CardHeader>
|
|
|
|
|
<CardContent>
|
|
|
|
|
<div className="grid grid-cols-2 md:grid-cols-4 gap-6">
|
|
|
|
|
<InfoItem label="수주일자" value={order.orderDate} />
|
|
|
|
|
<InfoItem label="출고예정일" value={order.expectedShipDate || "미정"} />
|
|
|
|
|
<InfoItem label="납품요청일" value={order.deliveryRequestDate} />
|
|
|
|
|
<InfoItem label="배송방식" value={order.deliveryMethod} />
|
|
|
|
|
<InfoItem label="운임비용" value={order.shippingCost} />
|
|
|
|
|
<InfoItem label="수신(반장/업체)" value={order.receiver} />
|
|
|
|
|
<InfoItem label="수신처 연락처" value={order.receiverContact} />
|
|
|
|
|
<InfoItem label="수신처 주소" value={order.address} />
|
|
|
|
|
</div>
|
|
|
|
|
</CardContent>
|
|
|
|
|
</Card>
|
|
|
|
|
|
|
|
|
|
{/* 비고 */}
|
|
|
|
|
{order.remarks && (
|
|
|
|
|
<Card>
|
|
|
|
|
<CardHeader>
|
|
|
|
|
<CardTitle className="text-lg">비고</CardTitle>
|
|
|
|
|
</CardHeader>
|
|
|
|
|
<CardContent>
|
|
|
|
|
<p className="whitespace-pre-wrap">{order.remarks}</p>
|
|
|
|
|
</CardContent>
|
|
|
|
|
</Card>
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
{/* 제품 내역 */}
|
|
|
|
|
<Card>
|
|
|
|
|
<CardHeader>
|
|
|
|
|
<CardTitle className="text-lg">제품 내역</CardTitle>
|
|
|
|
|
</CardHeader>
|
|
|
|
|
<CardContent>
|
|
|
|
|
<div className="border rounded-lg overflow-hidden">
|
|
|
|
|
<Table>
|
|
|
|
|
<TableHeader>
|
|
|
|
|
<TableRow>
|
|
|
|
|
<TableHead className="w-[60px] text-center">순번</TableHead>
|
|
|
|
|
<TableHead>품목코드</TableHead>
|
|
|
|
|
<TableHead>품명</TableHead>
|
|
|
|
|
<TableHead>층</TableHead>
|
|
|
|
|
<TableHead>부호</TableHead>
|
|
|
|
|
<TableHead>규격</TableHead>
|
|
|
|
|
<TableHead className="text-center">수량</TableHead>
|
|
|
|
|
<TableHead className="text-center">단위</TableHead>
|
|
|
|
|
<TableHead className="text-right">단가</TableHead>
|
|
|
|
|
<TableHead className="text-right">금액</TableHead>
|
|
|
|
|
</TableRow>
|
|
|
|
|
</TableHeader>
|
|
|
|
|
<TableBody>
|
|
|
|
|
{order.items.map((item, index) => (
|
|
|
|
|
<TableRow key={item.id}>
|
|
|
|
|
<TableCell className="text-center">{index + 1}</TableCell>
|
|
|
|
|
<TableCell>
|
|
|
|
|
<code className="text-xs bg-gray-100 px-1.5 py-0.5 rounded">
|
|
|
|
|
{item.itemCode}
|
|
|
|
|
</code>
|
|
|
|
|
</TableCell>
|
|
|
|
|
<TableCell>{item.itemName}</TableCell>
|
|
|
|
|
<TableCell>{item.type || "-"}</TableCell>
|
|
|
|
|
<TableCell>{item.symbol || "-"}</TableCell>
|
|
|
|
|
<TableCell>{item.spec}</TableCell>
|
|
|
|
|
<TableCell className="text-center">{item.quantity}</TableCell>
|
|
|
|
|
<TableCell className="text-center">{item.unit}</TableCell>
|
|
|
|
|
<TableCell className="text-right">
|
|
|
|
|
{formatAmount(item.unitPrice)}원
|
|
|
|
|
</TableCell>
|
|
|
|
|
<TableCell className="text-right font-medium">
|
|
|
|
|
{formatAmount(item.amount)}원
|
|
|
|
|
</TableCell>
|
|
|
|
|
</TableRow>
|
|
|
|
|
))}
|
|
|
|
|
</TableBody>
|
|
|
|
|
</Table>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{/* 합계 */}
|
|
|
|
|
<div className="flex flex-col items-end gap-2 pt-4 mt-4 border-t">
|
|
|
|
|
<div className="flex items-center gap-4 text-sm">
|
|
|
|
|
<span className="text-muted-foreground">소계:</span>
|
|
|
|
|
<span className="w-32 text-right">
|
|
|
|
|
{formatAmount(order.subtotal)}원
|
|
|
|
|
</span>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="flex items-center gap-4 text-sm">
|
|
|
|
|
<span className="text-muted-foreground">할인율:</span>
|
|
|
|
|
<span className="w-32 text-right">{order.discountRate}%</span>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="flex items-center gap-4 text-lg font-semibold">
|
|
|
|
|
<span>총금액:</span>
|
|
|
|
|
<span className="w-32 text-right text-green-600">
|
|
|
|
|
{formatAmount(order.totalAmount)}원
|
|
|
|
|
</span>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</CardContent>
|
|
|
|
|
</Card>
|
|
|
|
|
</div>
|
feat(WEB): Phase 6 IntegratedDetailTemplate 마이그레이션 완료
Phase 6 마이그레이션 (41개 컴포넌트 완료):
- 건설/시공: 협력업체, 시공관리, 기성관리, 발주관리, 계약관리 등
- 영업: 견적관리(V2), 고객관리(V2), 수주관리
- 회계: 청구관리, 매입관리, 매출관리, 거래처관리, 악성채권 등
- 생산: 작업지시, 검수관리
- 출고: 출하관리
- 자재: 입고관리, 재고현황
- 고객센터: 문의관리, 이벤트관리, 공지관리
- 인사: 직원관리
- 설정: 권한관리
주요 변경사항:
- 34개 xxxConfig.ts 파일 생성 (설정 기반 페이지 구성)
- PageLayout/PageHeader → IntegratedDetailTemplate 통합
- 일관된 타이틀/버튼 영역 (목록, 상세, 수정, 삭제)
- 1112줄 코드 감소 (중복 제거)
프로젝트 공통화 현황 분석 문서 추가:
- 상세 페이지 62%, 목록 페이지 82% 공통화 달성
- 추가 공통화 기회 및 로드맵 정리
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-20 15:51:02 +09:00
|
|
|
);
|
|
|
|
|
}, [order, openDocumentModal]);
|
|
|
|
|
|
|
|
|
|
// 에러 상태
|
|
|
|
|
if (!loading && !order) {
|
|
|
|
|
return (
|
|
|
|
|
<ServerErrorPage
|
|
|
|
|
title="수주 정보를 불러올 수 없습니다"
|
|
|
|
|
message="수주 정보를 찾을 수 없습니다."
|
|
|
|
|
showBackButton={true}
|
|
|
|
|
showHomeButton={true}
|
|
|
|
|
/>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<>
|
|
|
|
|
<IntegratedDetailTemplate
|
|
|
|
|
config={dynamicConfig}
|
|
|
|
|
mode="view"
|
|
|
|
|
initialData={order || {}}
|
|
|
|
|
itemId={orderId}
|
|
|
|
|
isLoading={loading}
|
|
|
|
|
headerActions={customHeaderActions}
|
|
|
|
|
renderView={() => renderFormContent()}
|
|
|
|
|
renderForm={() => renderFormContent()}
|
|
|
|
|
/>
|
2026-01-20 09:00:27 +09:00
|
|
|
|
|
|
|
|
{/* 문서 모달 */}
|
feat(WEB): Phase 6 IntegratedDetailTemplate 마이그레이션 완료
Phase 6 마이그레이션 (41개 컴포넌트 완료):
- 건설/시공: 협력업체, 시공관리, 기성관리, 발주관리, 계약관리 등
- 영업: 견적관리(V2), 고객관리(V2), 수주관리
- 회계: 청구관리, 매입관리, 매출관리, 거래처관리, 악성채권 등
- 생산: 작업지시, 검수관리
- 출고: 출하관리
- 자재: 입고관리, 재고현황
- 고객센터: 문의관리, 이벤트관리, 공지관리
- 인사: 직원관리
- 설정: 권한관리
주요 변경사항:
- 34개 xxxConfig.ts 파일 생성 (설정 기반 페이지 구성)
- PageLayout/PageHeader → IntegratedDetailTemplate 통합
- 일관된 타이틀/버튼 영역 (목록, 상세, 수정, 삭제)
- 1112줄 코드 감소 (중복 제거)
프로젝트 공통화 현황 분석 문서 추가:
- 상세 페이지 62%, 목록 페이지 82% 공통화 달성
- 추가 공통화 기회 및 로드맵 정리
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-20 15:51:02 +09:00
|
|
|
{order && (
|
|
|
|
|
<OrderDocumentModal
|
2026-01-20 09:00:27 +09:00
|
|
|
open={documentModalOpen}
|
|
|
|
|
onOpenChange={setDocumentModalOpen}
|
|
|
|
|
documentType={documentType}
|
|
|
|
|
data={{
|
|
|
|
|
lotNumber: order.lotNumber,
|
|
|
|
|
orderDate: order.orderDate,
|
|
|
|
|
client: order.client,
|
|
|
|
|
siteName: order.siteName,
|
|
|
|
|
manager: order.manager,
|
|
|
|
|
managerContact: order.contact,
|
|
|
|
|
deliveryRequestDate: order.deliveryRequestDate,
|
|
|
|
|
expectedShipDate: order.expectedShipDate,
|
|
|
|
|
deliveryMethod: order.deliveryMethod,
|
|
|
|
|
address: order.address,
|
|
|
|
|
items: order.items,
|
|
|
|
|
subtotal: order.subtotal,
|
|
|
|
|
discountRate: order.discountRate,
|
|
|
|
|
totalAmount: order.totalAmount,
|
|
|
|
|
remarks: order.remarks,
|
|
|
|
|
}}
|
|
|
|
|
/>
|
feat(WEB): Phase 6 IntegratedDetailTemplate 마이그레이션 완료
Phase 6 마이그레이션 (41개 컴포넌트 완료):
- 건설/시공: 협력업체, 시공관리, 기성관리, 발주관리, 계약관리 등
- 영업: 견적관리(V2), 고객관리(V2), 수주관리
- 회계: 청구관리, 매입관리, 매출관리, 거래처관리, 악성채권 등
- 생산: 작업지시, 검수관리
- 출고: 출하관리
- 자재: 입고관리, 재고현황
- 고객센터: 문의관리, 이벤트관리, 공지관리
- 인사: 직원관리
- 설정: 권한관리
주요 변경사항:
- 34개 xxxConfig.ts 파일 생성 (설정 기반 페이지 구성)
- PageLayout/PageHeader → IntegratedDetailTemplate 통합
- 일관된 타이틀/버튼 영역 (목록, 상세, 수정, 삭제)
- 1112줄 코드 감소 (중복 제거)
프로젝트 공통화 현황 분석 문서 추가:
- 상세 페이지 62%, 목록 페이지 82% 공통화 달성
- 추가 공통화 기회 및 로드맵 정리
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-20 15:51:02 +09:00
|
|
|
)}
|
2026-01-20 09:00:27 +09:00
|
|
|
|
|
|
|
|
{/* 취소 확인 다이얼로그 */}
|
feat(WEB): Phase 6 IntegratedDetailTemplate 마이그레이션 완료
Phase 6 마이그레이션 (41개 컴포넌트 완료):
- 건설/시공: 협력업체, 시공관리, 기성관리, 발주관리, 계약관리 등
- 영업: 견적관리(V2), 고객관리(V2), 수주관리
- 회계: 청구관리, 매입관리, 매출관리, 거래처관리, 악성채권 등
- 생산: 작업지시, 검수관리
- 출고: 출하관리
- 자재: 입고관리, 재고현황
- 고객센터: 문의관리, 이벤트관리, 공지관리
- 인사: 직원관리
- 설정: 권한관리
주요 변경사항:
- 34개 xxxConfig.ts 파일 생성 (설정 기반 페이지 구성)
- PageLayout/PageHeader → IntegratedDetailTemplate 통합
- 일관된 타이틀/버튼 영역 (목록, 상세, 수정, 삭제)
- 1112줄 코드 감소 (중복 제거)
프로젝트 공통화 현황 분석 문서 추가:
- 상세 페이지 62%, 목록 페이지 82% 공통화 달성
- 추가 공통화 기회 및 로드맵 정리
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-20 15:51:02 +09:00
|
|
|
{order && (
|
2026-01-20 09:00:27 +09:00
|
|
|
<Dialog open={isCancelDialogOpen} onOpenChange={setIsCancelDialogOpen}>
|
|
|
|
|
<DialogContent className="max-w-md">
|
|
|
|
|
<DialogHeader>
|
|
|
|
|
<DialogTitle className="flex items-center gap-2">
|
|
|
|
|
<XCircle className="h-5 w-5" />
|
|
|
|
|
수주 취소
|
|
|
|
|
</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 items-center">
|
|
|
|
|
<span className="text-muted-foreground">현재 상태</span>
|
|
|
|
|
{getOrderStatusBadge(order.status)}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{/* 취소 사유 선택 */}
|
|
|
|
|
<div className="space-y-2">
|
|
|
|
|
<Label htmlFor="cancelReason">
|
|
|
|
|
취소 사유 <span className="text-red-500">*</span>
|
|
|
|
|
</Label>
|
|
|
|
|
<Select value={cancelReason} onValueChange={setCancelReason}>
|
|
|
|
|
<SelectTrigger id="cancelReason">
|
|
|
|
|
<SelectValue placeholder="취소 사유를 선택하세요" />
|
|
|
|
|
</SelectTrigger>
|
|
|
|
|
<SelectContent>
|
|
|
|
|
<SelectItem value="customer_request">고객 요청</SelectItem>
|
|
|
|
|
<SelectItem value="spec_change">사양 변경</SelectItem>
|
|
|
|
|
<SelectItem value="price_issue">가격 문제</SelectItem>
|
|
|
|
|
<SelectItem value="delivery_issue">납기 문제</SelectItem>
|
|
|
|
|
<SelectItem value="duplicate_order">중복 수주</SelectItem>
|
|
|
|
|
<SelectItem value="other">기타</SelectItem>
|
|
|
|
|
</SelectContent>
|
|
|
|
|
</Select>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{/* 상세 사유 입력 */}
|
|
|
|
|
<div className="space-y-2">
|
|
|
|
|
<Label htmlFor="cancelDetail">상세 사유</Label>
|
|
|
|
|
<Textarea
|
|
|
|
|
id="cancelDetail"
|
|
|
|
|
placeholder="취소 사유에 대한 상세 내용을 입력하세요"
|
|
|
|
|
value={cancelDetail}
|
|
|
|
|
onChange={(e) => setCancelDetail(e.target.value)}
|
|
|
|
|
rows={3}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{/* 취소 시 유의사항 */}
|
|
|
|
|
<div className="bg-gray-50 border rounded-lg p-4 text-sm space-y-1">
|
|
|
|
|
<p className="font-medium mb-2">취소 시 유의사항</p>
|
|
|
|
|
<ul className="space-y-1 text-muted-foreground">
|
|
|
|
|
<li>• 취소된 수주는 목록에서 '취소' 상태로 표시됩니다</li>
|
|
|
|
|
<li>• 취소 후에는 수정이 불가능합니다</li>
|
|
|
|
|
<li>• 관련된 생산지시가 있는 경우 먼저 생산지시를 취소해야 합니다</li>
|
|
|
|
|
</ul>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<DialogFooter>
|
|
|
|
|
<Button
|
|
|
|
|
variant="outline"
|
|
|
|
|
onClick={() => setIsCancelDialogOpen(false)}
|
|
|
|
|
>
|
|
|
|
|
닫기
|
|
|
|
|
</Button>
|
|
|
|
|
<Button
|
|
|
|
|
variant="outline"
|
|
|
|
|
onClick={handleConfirmCancel}
|
|
|
|
|
className="border-gray-300"
|
|
|
|
|
disabled={isCancelling}
|
|
|
|
|
>
|
|
|
|
|
<XCircle className="h-4 w-4 mr-1" />
|
|
|
|
|
{isCancelling ? "취소 중..." : "취소 확정"}
|
|
|
|
|
</Button>
|
|
|
|
|
</DialogFooter>
|
|
|
|
|
</DialogContent>
|
|
|
|
|
</Dialog>
|
feat(WEB): Phase 6 IntegratedDetailTemplate 마이그레이션 완료
Phase 6 마이그레이션 (41개 컴포넌트 완료):
- 건설/시공: 협력업체, 시공관리, 기성관리, 발주관리, 계약관리 등
- 영업: 견적관리(V2), 고객관리(V2), 수주관리
- 회계: 청구관리, 매입관리, 매출관리, 거래처관리, 악성채권 등
- 생산: 작업지시, 검수관리
- 출고: 출하관리
- 자재: 입고관리, 재고현황
- 고객센터: 문의관리, 이벤트관리, 공지관리
- 인사: 직원관리
- 설정: 권한관리
주요 변경사항:
- 34개 xxxConfig.ts 파일 생성 (설정 기반 페이지 구성)
- PageLayout/PageHeader → IntegratedDetailTemplate 통합
- 일관된 타이틀/버튼 영역 (목록, 상세, 수정, 삭제)
- 1112줄 코드 감소 (중복 제거)
프로젝트 공통화 현황 분석 문서 추가:
- 상세 페이지 62%, 목록 페이지 82% 공통화 달성
- 추가 공통화 기회 및 로드맵 정리
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-20 15:51:02 +09:00
|
|
|
)}
|
2026-01-20 09:00:27 +09:00
|
|
|
|
|
|
|
|
{/* 수주 확정 다이얼로그 */}
|
feat(WEB): Phase 6 IntegratedDetailTemplate 마이그레이션 완료
Phase 6 마이그레이션 (41개 컴포넌트 완료):
- 건설/시공: 협력업체, 시공관리, 기성관리, 발주관리, 계약관리 등
- 영업: 견적관리(V2), 고객관리(V2), 수주관리
- 회계: 청구관리, 매입관리, 매출관리, 거래처관리, 악성채권 등
- 생산: 작업지시, 검수관리
- 출고: 출하관리
- 자재: 입고관리, 재고현황
- 고객센터: 문의관리, 이벤트관리, 공지관리
- 인사: 직원관리
- 설정: 권한관리
주요 변경사항:
- 34개 xxxConfig.ts 파일 생성 (설정 기반 페이지 구성)
- PageLayout/PageHeader → IntegratedDetailTemplate 통합
- 일관된 타이틀/버튼 영역 (목록, 상세, 수정, 삭제)
- 1112줄 코드 감소 (중복 제거)
프로젝트 공통화 현황 분석 문서 추가:
- 상세 페이지 62%, 목록 페이지 82% 공통화 달성
- 추가 공통화 기회 및 로드맵 정리
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-20 15:51:02 +09:00
|
|
|
{order && (
|
2026-01-20 09:00:27 +09:00
|
|
|
<Dialog open={isConfirmDialogOpen} onOpenChange={setIsConfirmDialogOpen}>
|
|
|
|
|
<DialogContent className="max-w-md">
|
|
|
|
|
<DialogHeader>
|
|
|
|
|
<DialogTitle className="flex items-center gap-2">
|
|
|
|
|
<CheckCircle2 className="h-5 w-5 text-green-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)}원
|
|
|
|
|
</span>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="flex justify-between items-center">
|
|
|
|
|
<span className="text-muted-foreground">현재 상태</span>
|
|
|
|
|
{getOrderStatusBadge(order.status)}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{/* 확정 안내 */}
|
|
|
|
|
<div className="bg-green-50 border border-green-200 rounded-lg p-4 text-sm space-y-1">
|
|
|
|
|
<p className="font-medium mb-2 text-green-700">확정 후 변경사항</p>
|
|
|
|
|
<ul className="space-y-1 text-green-600">
|
|
|
|
|
<li>• 수주 상태가 '수주확정'으로 변경됩니다</li>
|
|
|
|
|
<li>• 생산지시를 생성할 수 있습니다</li>
|
|
|
|
|
<li>• 확정 후에도 수정이 가능합니다</li>
|
|
|
|
|
</ul>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<DialogFooter>
|
|
|
|
|
<Button
|
|
|
|
|
variant="outline"
|
|
|
|
|
onClick={() => setIsConfirmDialogOpen(false)}
|
|
|
|
|
>
|
|
|
|
|
닫기
|
|
|
|
|
</Button>
|
|
|
|
|
<Button
|
|
|
|
|
onClick={handleConfirmOrderSubmit}
|
|
|
|
|
className="bg-green-600 hover:bg-green-700"
|
|
|
|
|
disabled={isConfirming}
|
|
|
|
|
>
|
|
|
|
|
<CheckCircle2 className="h-4 w-4 mr-1" />
|
|
|
|
|
{isConfirming ? "확정 중..." : "확정"}
|
|
|
|
|
</Button>
|
|
|
|
|
</DialogFooter>
|
|
|
|
|
</DialogContent>
|
|
|
|
|
</Dialog>
|
feat(WEB): Phase 6 IntegratedDetailTemplate 마이그레이션 완료
Phase 6 마이그레이션 (41개 컴포넌트 완료):
- 건설/시공: 협력업체, 시공관리, 기성관리, 발주관리, 계약관리 등
- 영업: 견적관리(V2), 고객관리(V2), 수주관리
- 회계: 청구관리, 매입관리, 매출관리, 거래처관리, 악성채권 등
- 생산: 작업지시, 검수관리
- 출고: 출하관리
- 자재: 입고관리, 재고현황
- 고객센터: 문의관리, 이벤트관리, 공지관리
- 인사: 직원관리
- 설정: 권한관리
주요 변경사항:
- 34개 xxxConfig.ts 파일 생성 (설정 기반 페이지 구성)
- PageLayout/PageHeader → IntegratedDetailTemplate 통합
- 일관된 타이틀/버튼 영역 (목록, 상세, 수정, 삭제)
- 1112줄 코드 감소 (중복 제거)
프로젝트 공통화 현황 분석 문서 추가:
- 상세 페이지 62%, 목록 페이지 82% 공통화 달성
- 추가 공통화 기회 및 로드맵 정리
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-20 15:51:02 +09:00
|
|
|
)}
|
|
|
|
|
</>
|
2026-01-20 09:00:27 +09:00
|
|
|
);
|
|
|
|
|
}
|