diff options
| author | dujinkim <dujin.kim@dtsolution.co.kr> | 2025-10-29 07:43:44 +0000 |
|---|---|---|
| committer | dujinkim <dujin.kim@dtsolution.co.kr> | 2025-10-29 07:43:44 +0000 |
| commit | 2eb717eb2bbfd97a5f149d13049aa336c26c393b (patch) | |
| tree | 274283b7759bfba619e6d143edccf3845ba45ed6 /components/pq-input/pq-review-wrapper.tsx | |
| parent | bfc26491991997b5b109af6ea6bc75a8be138e9a (diff) | |
(최겸) 구매 실사 개발(진행중)
Diffstat (limited to 'components/pq-input/pq-review-wrapper.tsx')
| -rw-r--r-- | components/pq-input/pq-review-wrapper.tsx | 260 |
1 files changed, 226 insertions, 34 deletions
diff --git a/components/pq-input/pq-review-wrapper.tsx b/components/pq-input/pq-review-wrapper.tsx index 1545314c..9b719644 100644 --- a/components/pq-input/pq-review-wrapper.tsx +++ b/components/pq-input/pq-review-wrapper.tsx @@ -23,7 +23,7 @@ import { import { useToast } from "@/hooks/use-toast" import { CheckCircle, AlertCircle, Paperclip, Square } from "lucide-react" import { PQGroupData } from "@/lib/pq/service" -import { approvePQAction, rejectPQAction, updateSHICommentAction } from "@/lib/pq/service" +import { approvePQAction, rejectPQAction, updateSHICommentAction, approveQMReviewAction, rejectQMReviewAction } from "@/lib/pq/service" // import * as ExcelJS from 'exceljs'; // import { saveAs } from "file-saver"; @@ -61,9 +61,14 @@ export function PQReviewWrapper({ const { toast } = useToast() const [isApproving, setIsApproving] = React.useState(false) const [isRejecting, setIsRejecting] = React.useState(false) + const [isQMApproving, setIsQMApproving] = React.useState(false) + const [isQMRejecting, setIsQMRejecting] = React.useState(false) const [showApproveDialog, setShowApproveDialog] = React.useState(false) const [showRejectDialog, setShowRejectDialog] = React.useState(false) + const [showQMApproveDialog, setShowQMApproveDialog] = React.useState(false) + const [showQMRejectDialog, setShowQMRejectDialog] = React.useState(false) const [rejectReason, setRejectReason] = React.useState("") + const [qmRejectReason, setQmRejectReason] = React.useState("") const [shiComments, setShiComments] = React.useState<Record<number, string>>({}) const [isUpdatingComment, setIsUpdatingComment] = React.useState<number | null>(null) @@ -103,7 +108,7 @@ export function PQReviewWrapper({ setShiComments(initialComments) }, [pqData]) - // PQ 승인 처리 + // PQ 승인 처리 (구매 담당자) const handleApprove = async () => { try { setIsApproving(true) @@ -116,7 +121,7 @@ export function PQReviewWrapper({ if (result.ok) { toast({ title: "PQ 승인 완료", - description: "PQ가 성공적으로 승인되었습니다.", + description: "PQ가 QM 검토 단계로 전환되었습니다.", }) // 페이지 새로고침 router.refresh() @@ -139,6 +144,90 @@ export function PQReviewWrapper({ setShowApproveDialog(false) } } + + // QM 승인 처리 + const handleQMApprove = async () => { + try { + setIsQMApproving(true) + + const result = await approveQMReviewAction({ + pqSubmissionId: pqSubmission.id, + vendorId: vendorId + }) + + if (result.ok) { + toast({ + title: "QM 승인 완료", + description: "PQ가 최종 승인되어 실사 프로세스가 시작됩니다.", + }) + // 페이지 새로고침 + router.refresh() + } else { + toast({ + title: "QM 승인 실패", + description: result.error || "QM 승인 중 오류가 발생했습니다.", + variant: "destructive" + }) + } + } catch (error) { + console.error("QM 승인 오류:", error) + toast({ + title: "QM 승인 실패", + description: "QM 승인 중 오류가 발생했습니다.", + variant: "destructive" + }) + } finally { + setIsQMApproving(false) + setShowQMApproveDialog(false) + } + } + + // QM 거절 처리 + const handleQMReject = async () => { + if (!qmRejectReason.trim()) { + toast({ + title: "거절 사유 필요", + description: "거절 사유를 입력해주세요.", + variant: "destructive" + }) + return + } + + try { + setIsQMRejecting(true) + + const result = await rejectQMReviewAction({ + pqSubmissionId: pqSubmission.id, + vendorId: vendorId, + rejectReason: qmRejectReason + }) + + if (result.ok) { + toast({ + title: "QM 거절 완료", + description: "PQ가 QM에 의해 거절되었습니다.", + }) + // 페이지 새로고침 + router.refresh() + } else { + toast({ + title: "QM 거절 실패", + description: result.error || "QM 거절 중 오류가 발생했습니다.", + variant: "destructive" + }) + } + } catch (error) { + console.error("QM 거절 오류:", error) + toast({ + title: "QM 거절 실패", + description: "QM 거절 중 오류가 발생했습니다.", + variant: "destructive" + }) + } finally { + setIsQMRejecting(false) + setShowQMRejectDialog(false) + } + } // SHI 코멘트 업데이트 처리 const handleSHICommentUpdate = async (answerId: number) => { @@ -643,48 +732,87 @@ export function PQReviewWrapper({ </div> ))} - {/* 검토 버튼 */} + {/* 검토 버튼 - 상태에 따라 다른 버튼 표시 */} <div className="fixed bottom-4 right-4 bg-background p-4 rounded-lg shadow-md border"> <div className="flex gap-2"> + {/* SUBMITTED 상태: 구매 담당자 승인/거절 */} + {pqSubmission.status === "SUBMITTED" && ( + <> + <Button + variant="outline" + onClick={() => setShowRejectDialog(true)} + disabled={isRejecting} + > + {isRejecting ? "거부 중..." : "거부"} + </Button> + <Button + variant="default" + onClick={() => setShowApproveDialog(true)} + disabled={isApproving} + > + {isApproving ? "승인 중..." : "구매 승인"} + </Button> + </> + )} + {/* QM_REVIEWING 상태: QM 승인/거절 */} + {pqSubmission.status === "QM_REVIEWING" && ( + <> + <Button + variant="outline" + onClick={() => setShowQMRejectDialog(true)} + disabled={isQMRejecting} + > + {isQMRejecting ? "QM 거절 중..." : "QM 거절"} + </Button> + <Button + variant="default" + onClick={() => setShowQMApproveDialog(true)} + disabled={isQMApproving} + > + {isQMApproving ? "QM 승인 중..." : "QM 승인"} + </Button> + </> + )} - {/* <Button - variant="outline" - onClick={handleExportToExcel} - disabled={isExporting} - > - <Download className="h-4 w-4 mr-2" /> - {isExporting ? "내보내기 중..." : "Excel 내보내기"} - </Button> */} - <Button - variant="outline" - onClick={() => setShowRejectDialog(true)} - disabled={isRejecting} - > - {isRejecting ? "거부 중..." : "거부"} - </Button> - <Button - variant="default" - onClick={() => setShowApproveDialog(true)} - disabled={isApproving} - > - {isApproving ? "승인 중..." : "승인"} - </Button> + {/* QM_APPROVED 상태: 완료 표시 */} + {pqSubmission.status === "QM_APPROVED" && ( + <div className="flex items-center gap-2 text-green-600"> + <CheckCircle className="h-4 w-4" /> + <span>QM 승인 완료</span> + </div> + )} + + {/* QM_REJECTED 상태: 거절 표시 */} + {pqSubmission.status === "QM_REJECTED" && ( + <div className="flex items-center gap-2 text-red-600"> + <AlertCircle className="h-4 w-4" /> + <span>QM 거절됨</span> + </div> + )} + + {/* REJECTED 상태: 거절 표시 */} + {pqSubmission.status === "REJECTED" && ( + <div className="flex items-center gap-2 text-red-600"> + <AlertCircle className="h-4 w-4" /> + <span>거절됨</span> + </div> + )} </div> </div> - {/* 승인 확인 다이얼로그 */} + {/* 구매 승인 확인 다이얼로그 */} <Dialog open={showApproveDialog} onOpenChange={setShowApproveDialog}> <DialogContent> <DialogHeader> - <DialogTitle>PQ 승인 확인</DialogTitle> + <DialogTitle>PQ 구매 승인 확인</DialogTitle> <DialogDescription> {pqSubmission.vendorName || "알 수 없는 업체"}의 { pqSubmission.type === "GENERAL" ? "일반" : pqSubmission.type === "PROJECT" ? "프로젝트" : pqSubmission.type === "NON_INSPECTION" ? "미실사" : "일반" - } PQ를 승인하시겠습니까? + } PQ를 구매 승인하여 QM 검토 단계로 전환하시겠습니까? {pqSubmission.projectId && ( <span> 프로젝트: {pqSubmission.projectName}</span> )} @@ -695,23 +823,50 @@ export function PQReviewWrapper({ 취소 </Button> <Button onClick={handleApprove} disabled={isApproving}> - {isApproving ? "승인 중..." : "승인"} + {isApproving ? "승인 중..." : "구매 승인"} + </Button> + </DialogFooter> + </DialogContent> + </Dialog> + + {/* QM 승인 확인 다이얼로그 */} + <Dialog open={showQMApproveDialog} onOpenChange={setShowQMApproveDialog}> + <DialogContent> + <DialogHeader> + <DialogTitle>QM 승인 확인</DialogTitle> + <DialogDescription> + {pqSubmission.vendorName || "알 수 없는 업체"}의 { + pqSubmission.type === "GENERAL" ? "일반" : + pqSubmission.type === "PROJECT" ? "프로젝트" : + pqSubmission.type === "NON_INSPECTION" ? "미실사" : "일반" + } PQ를 QM에서 최종 승인하여 실사 프로세스를 시작하시겠습니까? + {pqSubmission.projectId && ( + <span> 프로젝트: {pqSubmission.projectName}</span> + )} + </DialogDescription> + </DialogHeader> + <DialogFooter> + <Button variant="outline" onClick={() => setShowQMApproveDialog(false)}> + 취소 + </Button> + <Button onClick={handleQMApprove} disabled={isQMApproving}> + {isQMApproving ? "QM 승인 중..." : "QM 승인"} </Button> </DialogFooter> </DialogContent> </Dialog> - {/* 거부 확인 다이얼로그 */} + {/* 구매 거부 확인 다이얼로그 */} <Dialog open={showRejectDialog} onOpenChange={setShowRejectDialog}> <DialogContent> <DialogHeader> - <DialogTitle>PQ 거부</DialogTitle> + <DialogTitle>PQ 구매 거부</DialogTitle> <DialogDescription> {pqSubmission.vendorName || "알 수 없는 업체"}의 { pqSubmission.type === "GENERAL" ? "일반" : pqSubmission.type === "PROJECT" ? "프로젝트" : pqSubmission.type === "NON_INSPECTION" ? "미실사" : "일반" - } PQ를 거부하는 이유를 입력해주세요. + } PQ를 구매에서 거부하는 이유를 입력해주세요. {pqSubmission.projectId && ( <span> 프로젝트: {pqSubmission.projectName}</span> )} @@ -732,7 +887,44 @@ export function PQReviewWrapper({ onClick={handleReject} disabled={isRejecting || !rejectReason.trim()} > - {isRejecting ? "거부 중..." : "거부"} + {isRejecting ? "거부 중..." : "구매 거부"} + </Button> + </DialogFooter> + </DialogContent> + </Dialog> + + {/* QM 거절 확인 다이얼로그 */} + <Dialog open={showQMRejectDialog} onOpenChange={setShowQMRejectDialog}> + <DialogContent> + <DialogHeader> + <DialogTitle>QM 거절</DialogTitle> + <DialogDescription> + {pqSubmission.vendorName || "알 수 없는 업체"}의 { + pqSubmission.type === "GENERAL" ? "일반" : + pqSubmission.type === "PROJECT" ? "프로젝트" : + pqSubmission.type === "NON_INSPECTION" ? "미실사" : "일반" + } PQ를 QM에서 거절하는 이유를 입력해주세요. + {pqSubmission.projectId && ( + <span> 프로젝트: {pqSubmission.projectName}</span> + )} + </DialogDescription> + </DialogHeader> + <Textarea + value={qmRejectReason} + onChange={(e) => setQmRejectReason(e.target.value)} + placeholder="QM 거절 사유를 입력하세요" + className="min-h-24" + /> + <DialogFooter> + <Button variant="outline" onClick={() => setShowQMRejectDialog(false)}> + 취소 + </Button> + <Button + variant="destructive" + onClick={handleQMReject} + disabled={isQMRejecting || !qmRejectReason.trim()} + > + {isQMRejecting ? "QM 거절 중..." : "QM 거절"} </Button> </DialogFooter> </DialogContent> |
