summaryrefslogtreecommitdiff
path: root/lib/bidding/detail/table/bidding-award-dialog.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'lib/bidding/detail/table/bidding-award-dialog.tsx')
-rw-r--r--lib/bidding/detail/table/bidding-award-dialog.tsx190
1 files changed, 170 insertions, 20 deletions
diff --git a/lib/bidding/detail/table/bidding-award-dialog.tsx b/lib/bidding/detail/table/bidding-award-dialog.tsx
index 9a4614bd..ff104fac 100644
--- a/lib/bidding/detail/table/bidding-award-dialog.tsx
+++ b/lib/bidding/detail/table/bidding-award-dialog.tsx
@@ -26,7 +26,8 @@ import {
} from '@/components/ui/table'
import { Trophy, Building2, Calculator } from 'lucide-react'
import { useToast } from '@/hooks/use-toast'
-import { getAwardedCompanies, awardBidding } from '@/lib/bidding/detail/service'
+import { getAwardedCompanies } from '@/lib/bidding/detail/service'
+import { requestBiddingAwardWithApproval } from '@/lib/bidding/approval-actions'
import { AwardSimpleFileUpload } from './components/award-simple-file-upload'
interface BiddingAwardDialogProps {
@@ -34,6 +35,12 @@ interface BiddingAwardDialogProps {
open: boolean
onOpenChange: (open: boolean) => void
onSuccess: () => void
+ onApprovalPreview?: (data: {
+ templateName: string
+ variables: Record<string, string>
+ title: string
+ selectionReason: string
+ }) => void
}
interface AwardedCompany {
@@ -47,7 +54,8 @@ export function BiddingAwardDialog({
biddingId,
open,
onOpenChange,
- onSuccess
+ onSuccess,
+ onApprovalPreview
}: BiddingAwardDialogProps) {
const { toast } = useToast()
const { data: session } = useSession()
@@ -106,26 +114,36 @@ const userId = session?.user?.id || '2';
return
}
- startTransition(async () => {
- const result = await awardBidding(biddingId, selectionReason, userId)
+ // 결재 템플릿 변수 준비
+ const { mapBiddingAwardToTemplateVariables } = await import('@/lib/bidding/handlers')
- if (result.success) {
- toast({
- title: '성공',
- description: result.message,
- })
- onSuccess()
- onOpenChange(false)
- // 폼 초기화
- setSelectionReason('')
- } else {
- toast({
- title: '오류',
- description: result.error,
- variant: 'destructive',
+ try {
+ const variables = await mapBiddingAwardToTemplateVariables({
+ biddingId,
+ selectionReason,
+ requestedAt: new Date()
+ })
+
+ // 상위 컴포넌트로 결재 미리보기 데이터 전달
+ if (onApprovalPreview) {
+ onApprovalPreview({
+ templateName: '입찰 결과 업체 선정 품의 요청서',
+ variables,
+ title: `낙찰 - ${bidding?.title}`,
+ selectionReason
})
}
- })
+
+ onOpenChange(false)
+ setSelectionReason('')
+ } catch (error) {
+ console.error('낙찰 템플릿 변수 준비 실패:', error)
+ toast({
+ title: '오류',
+ description: '결재 문서 준비 중 오류가 발생했습니다.',
+ variant: 'destructive',
+ })
+ }
}
@@ -251,11 +269,143 @@ const userId = session?.user?.id || '2';
type="submit"
disabled={isPending || awardedCompanies.length === 0}
>
- {isPending ? '처리 중...' : '낙찰 완료'}
+ {isPending ? '상신 중...' : '결재 상신'}
</Button>
</DialogFooter>
</form>
</DialogContent>
</Dialog>
)
+
+ return (
+ <>
+ <Dialog open={open} onOpenChange={onOpenChange}>
+ <DialogContent className="max-w-4xl max-h-[90vh] overflow-y-auto">
+ <DialogHeader>
+ <DialogTitle className="flex items-center gap-2">
+ <Trophy className="w-5 h-5 text-yellow-600" />
+ 낙찰 처리
+ </DialogTitle>
+ <DialogDescription>
+ 낙찰된 업체의 발주비율과 선정 사유를 확인하고 낙찰을 완료하세요.
+ </DialogDescription>
+ </DialogHeader>
+
+ <form onSubmit={handleSubmit}>
+ <div className="space-y-6">
+ {/* 낙찰 업체 정보 */}
+ <Card>
+ <CardHeader>
+ <CardTitle className="flex items-center gap-2">
+ <Building2 className="w-4 h-4" />
+ 낙찰 업체 정보
+ </CardTitle>
+ </CardHeader>
+ <CardContent>
+ {isLoading ? (
+ <div className="text-center py-4">
+ <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-primary mx-auto"></div>
+ <p className="mt-2 text-sm text-muted-foreground">낙찰 업체 정보를 불러오는 중...</p>
+ </div>
+ ) : awardedCompanies.length > 0 ? (
+ <div className="space-y-4">
+ <Table>
+ <TableHeader>
+ <TableRow>
+ <TableHead>업체명</TableHead>
+ <TableHead className="text-right">견적금액</TableHead>
+ <TableHead className="text-right">발주비율</TableHead>
+ <TableHead className="text-right">발주금액</TableHead>
+ </TableRow>
+ </TableHeader>
+ <TableBody>
+ {awardedCompanies.map((company) => (
+ <TableRow key={company.companyId}>
+ <TableCell className="font-medium">
+ <div className="flex items-center gap-2">
+ <Badge variant="default" className="bg-green-600">낙찰</Badge>
+ {company.companyName}
+ </div>
+ </TableCell>
+ <TableCell className="text-right">
+ {company.finalQuoteAmount.toLocaleString()}원
+ </TableCell>
+ <TableCell className="text-right">
+ {company.awardRatio}%
+ </TableCell>
+ <TableCell className="text-right font-semibold">
+ {(company.finalQuoteAmount * company.awardRatio / 100).toLocaleString()}원
+ </TableCell>
+ </TableRow>
+ ))}
+ </TableBody>
+ </Table>
+
+ {/* 최종입찰가 요약 */}
+ <div className="flex items-center justify-between p-4 bg-blue-50 border border-blue-200 rounded-lg">
+ <div className="flex items-center gap-2">
+ <Calculator className="w-5 h-5 text-blue-600" />
+ <span className="font-semibold text-blue-800">최종입찰가</span>
+ </div>
+ <span className="text-xl font-bold text-blue-800">
+ {finalBidPrice.toLocaleString()}원
+ </span>
+ </div>
+ </div>
+ ) : (
+ <div className="text-center py-8">
+ <Trophy className="w-12 h-12 text-gray-400 mx-auto mb-4" />
+ <p className="text-gray-500 mb-2">낙찰된 업체가 없습니다</p>
+ <p className="text-sm text-gray-400">
+ 먼저 업체 수정 다이얼로그에서 발주비율을 산정해주세요.
+ </p>
+ </div>
+ )}
+ </CardContent>
+ </Card>
+
+ {/* 낙찰 사유 */}
+ <div className="space-y-2">
+ <Label htmlFor="selectionReason">
+ 낙찰 사유 <span className="text-red-500">*</span>
+ </Label>
+ <Textarea
+ id="selectionReason"
+ placeholder="낙찰 사유를 상세히 입력해주세요..."
+ value={selectionReason}
+ onChange={(e) => setSelectionReason(e.target.value)}
+ rows={4}
+ className="resize-none"
+ />
+ </div>
+
+ {/* 첨부파일 */}
+ <AwardSimpleFileUpload
+ biddingId={biddingId}
+ userId={userId}
+ readOnly={false}
+ />
+ </div>
+
+ <DialogFooter className="mt-6">
+ <Button
+ type="button"
+ variant="outline"
+ onClick={() => onOpenChange(false)}
+ disabled={isPending}
+ >
+ 취소
+ </Button>
+ <Button
+ type="submit"
+ disabled={isPending || awardedCompanies.length === 0}
+ >
+ {isPending ? '상신 중...' : '결재 상신'}
+ </Button>
+ </DialogFooter>
+ </form>
+ </DialogContent>
+ </Dialog>
+ </>
+ )
}