summaryrefslogtreecommitdiff
path: root/components/pq-input/pq-review-wrapper.tsx
diff options
context:
space:
mode:
authordujinkim <dujin.kim@dtsolution.co.kr>2025-10-29 07:43:44 +0000
committerdujinkim <dujin.kim@dtsolution.co.kr>2025-10-29 07:43:44 +0000
commit2eb717eb2bbfd97a5f149d13049aa336c26c393b (patch)
tree274283b7759bfba619e6d143edccf3845ba45ed6 /components/pq-input/pq-review-wrapper.tsx
parentbfc26491991997b5b109af6ea6bc75a8be138e9a (diff)
(최겸) 구매 실사 개발(진행중)
Diffstat (limited to 'components/pq-input/pq-review-wrapper.tsx')
-rw-r--r--components/pq-input/pq-review-wrapper.tsx260
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>