diff options
Diffstat (limited to 'lib/bidding/detail/table')
| -rw-r--r-- | lib/bidding/detail/table/bidding-award-dialog.tsx | 136 | ||||
| -rw-r--r-- | lib/bidding/detail/table/bidding-detail-vendor-table.tsx | 9 |
2 files changed, 105 insertions, 40 deletions
diff --git a/lib/bidding/detail/table/bidding-award-dialog.tsx b/lib/bidding/detail/table/bidding-award-dialog.tsx index b168e884..613e2fc8 100644 --- a/lib/bidding/detail/table/bidding-award-dialog.tsx +++ b/lib/bidding/detail/table/bidding-award-dialog.tsx @@ -27,14 +27,27 @@ import { import { Trophy, Building2, Calculator } from 'lucide-react' import { useToast } from '@/hooks/use-toast' import { getAwardedCompanies } from '@/lib/bidding/detail/service' -import { requestBiddingAwardWithApproval } from '@/lib/bidding/approval-actions' +import { requestBiddingAwardWithApproval, prepareBiddingAwardApprovalData } from '@/lib/bidding/approval-actions' import { AwardSimpleFileUpload } from './components/award-simple-file-upload' +import { ApprovalPreviewDialog } from '@/lib/approval/approval-preview-dialog' interface BiddingAwardDialogProps { biddingId: number open: boolean onOpenChange: (open: boolean) => void onSuccess: () => void + onApprovalPreview?: (data: { + templateName: string + variables: Record<string, string> + title: string + selectionReason: string + awardedCompanies: { + companyId: number + companyName: string | null + finalQuoteAmount: number + awardRatio: number + }[] + }) => void } interface AwardedCompany { @@ -48,7 +61,8 @@ export function BiddingAwardDialog({ biddingId, open, onOpenChange, - onSuccess + onSuccess, + onApprovalPreview }: BiddingAwardDialogProps) { const { toast } = useToast() const { data: session } = useSession() @@ -56,7 +70,10 @@ export function BiddingAwardDialog({ const [selectionReason, setSelectionReason] = React.useState('') const [awardedCompanies, setAwardedCompanies] = React.useState<AwardedCompany[]>([]) const [isLoading, setIsLoading] = React.useState(false) -const userId = session?.user?.id || '2'; + const [isApprovalDialogOpen, setIsApprovalDialogOpen] = React.useState(false) + const [approvalVariables, setApprovalVariables] = React.useState<Record<string, string>>({}) + const [approvalTitle, setApprovalTitle] = React.useState('') + const userId = session?.user?.id || '2'; // 낙찰된 업체 정보 로드 React.useEffect(() => { if (open) { @@ -86,9 +103,8 @@ const userId = session?.user?.id || '2'; }, 0) }, [awardedCompanies]) - const handleSubmit = (e: React.FormEvent) => { - e.preventDefault() - + // 다음단계 버튼 핸들러 - 결재 준비 및 부모로 데이터 전달 + const handleNextStep = async () => { if (!selectionReason.trim()) { toast({ title: '유효성 오류', @@ -107,45 +123,83 @@ const userId = session?.user?.id || '2'; return } - // 서버 액션을 사용하여 결재 상신 - startTransition(async () => { - try { - const result = await requestBiddingAwardWithApproval({ - biddingId, + try { + // 결재 데이터 준비 (템플릿 변수, 제목 등) + const approvalData = await prepareBiddingAwardApprovalData({ + biddingId, + selectionReason: selectionReason.trim(), + awardedCompanies, + }) + + // 결재 준비 완료 - 부모 컴포넌트의 결재 미리보기 콜백 호출 + if (onApprovalPreview) { + onApprovalPreview({ + templateName: '입찰 결과 업체 선정 품의 요청서', + variables: approvalData.variables, + title: `낙찰 - ${approvalData.bidding.title}`, selectionReason: selectionReason.trim(), - currentUser: { - id: Number(userId), - epId: session?.user?.epId || null, - email: session?.user?.email || undefined, - }, + awardedCompanies, }) + } else { + // 기존 로직 유지 (내부 결재 다이얼로그 사용) + setApprovalVariables(approvalData.variables) + setApprovalTitle(`낙찰 - ${approvalData.bidding.title}`) + setIsApprovalDialogOpen(true) + } + } catch (error) { + console.error('결재 준비 중 오류 발생:', error) + toast({ + title: '오류', + description: '결재 준비 중 오류가 발생했습니다.', + variant: 'destructive', + }) + } + } - if (result.status === 'pending_approval') { - toast({ - title: '성공', - description: '낙찰 결재가 상신되었습니다.', - }) - onOpenChange(false) - setSelectionReason('') - onSuccess() - } else { - toast({ - title: '오류', - description: '결재 상신에 실패했습니다.', - variant: 'destructive', - }) - } - } catch (error) { - console.error('낙찰 결재 상신 실패:', error) + // 결재 상신 핸들러 - 결재 완료 시 실제 낙찰 등록 실행 + const handleApprovalSubmit = async ({ approvers, title, attachments }: { approvers: string[], title: string, attachments?: File[] }) => { + try { + if (!session?.user?.id || !session.user.epId) { toast({ title: '오류', - description: error instanceof Error ? error.message : '결재 상신 중 오류가 발생했습니다.', + description: '필요한 정보가 없습니다.', variant: 'destructive', }) + return } - }) - } + // 결재 상신 + const result = await requestBiddingAwardWithApproval({ + biddingId, + selectionReason: selectionReason.trim(), + awardedCompanies, // ✅ 결재 상신 시점의 낙찰 대상 정보 전달 + currentUser: { + id: Number(session.user.id), + epId: session.user.epId, + email: session.user.email || undefined, + }, + approvers, + }) + + if (result.status === 'pending_approval') { + toast({ + title: '낙찰 결재 상신 완료', + description: `결재가 상신되었습니다. (ID: ${result.approvalId})`, + }) + setIsApprovalDialogOpen(false) + onOpenChange(false) + setSelectionReason('') + onSuccess() + } + } catch (error) { + console.error('결재 상신 중 오류 발생:', error) + toast({ + title: '오류', + description: '결재 상신 중 오류가 발생했습니다.', + variant: 'destructive', + }) + } + } return ( <Dialog open={open} onOpenChange={onOpenChange}> @@ -160,7 +214,7 @@ const userId = session?.user?.id || '2'; </DialogDescription> </DialogHeader> - <form onSubmit={handleSubmit}> + <div> <div className="space-y-6"> {/* 낙찰 업체 정보 */} <Card> @@ -266,14 +320,16 @@ const userId = session?.user?.id || '2'; 취소 </Button> <Button - type="submit" + type="button" + onClick={handleNextStep} disabled={isPending || awardedCompanies.length === 0} > - {isPending ? '상신 중...' : '결재 상신'} + 다음단계 </Button> </DialogFooter> - </form> + </div> </DialogContent> </Dialog> + ) } diff --git a/lib/bidding/detail/table/bidding-detail-vendor-table.tsx b/lib/bidding/detail/table/bidding-detail-vendor-table.tsx index 08fc0293..edb72aca 100644 --- a/lib/bidding/detail/table/bidding-detail-vendor-table.tsx +++ b/lib/bidding/detail/table/bidding-detail-vendor-table.tsx @@ -15,6 +15,7 @@ import { Bidding } from '@/db/schema' import { PriceAdjustmentDialog } from '@/components/bidding/price-adjustment-dialog' import { QuotationHistoryDialog } from './quotation-history-dialog' import { ApprovalPreviewDialog } from '@/lib/approval/approval-preview-dialog' +import { ApplicationReasonDialog } from '@/lib/rfq-last/vendor/application-reason-dialog' import { requestBiddingAwardWithApproval } from '@/lib/bidding/approval-actions' import { useToast } from '@/hooks/use-toast' @@ -106,6 +107,12 @@ export function BiddingDetailVendorTableContent({ variables: Record<string, string> title: string selectionReason: string + awardedCompanies: { + companyId: number + companyName: string | null + finalQuoteAmount: number + awardRatio: number + }[] } | null>(null) const [isApprovalPreviewDialogOpen, setIsApprovalPreviewDialogOpen] = React.useState(false) @@ -204,6 +211,7 @@ export function BiddingDetailVendorTableContent({ const result = await requestBiddingAwardWithApproval({ biddingId, selectionReason: approvalPreviewData.selectionReason, + awardedCompanies: approvalPreviewData.awardedCompanies, currentUser: { id: Number(session.user.id), epId: session.user.epId || null, @@ -273,6 +281,7 @@ export function BiddingDetailVendorTableContent({ onSuccess={onRefresh} onApprovalPreview={(data) => { setApprovalPreviewData(data) + setIsAwardDialogOpen(false) setIsApprovalPreviewDialogOpen(true) }} /> |
