diff options
| author | dujinkim <dujin.kim@dtsolution.co.kr> | 2025-09-01 09:12:09 +0000 |
|---|---|---|
| committer | dujinkim <dujin.kim@dtsolution.co.kr> | 2025-09-01 09:12:09 +0000 |
| commit | 18954df6565108a469fb1608ea3715dd9bb1b02d (patch) | |
| tree | 2675d254c547861a903a32459d89283a324e0e0d /lib/basic-contract/status-detail | |
| parent | f91cd16a872d9cda04aeb5c4e31538e3e2bd1895 (diff) | |
(대표님) 구매 기본계약, gtc 개발
Diffstat (limited to 'lib/basic-contract/status-detail')
3 files changed, 123 insertions, 25 deletions
diff --git a/lib/basic-contract/status-detail/basic-contract-detail-table-toolbar-actions.tsx b/lib/basic-contract/status-detail/basic-contract-detail-table-toolbar-actions.tsx index 3b5cdd21..37ae135c 100644 --- a/lib/basic-contract/status-detail/basic-contract-detail-table-toolbar-actions.tsx +++ b/lib/basic-contract/status-detail/basic-contract-detail-table-toolbar-actions.tsx @@ -21,7 +21,7 @@ import { Badge } from "@/components/ui/badge" import { Textarea } from "@/components/ui/textarea" import { Label } from "@/components/ui/label" import { Separator } from "@/components/ui/separator" -import { prepareFinalApprovalAction, quickFinalApprovalAction, requestLegalReviewAction } from "../service" +import { prepareFinalApprovalAction, quickFinalApprovalAction, requestLegalReviewAction, resendContractsAction } from "../service" import { BasicContractSignDialog } from "../vendor-table/basic-contract-sign-dialog" interface BasicContractDetailTableToolbarActionsProps { @@ -222,12 +222,12 @@ export function BasicContractDetailTableToolbarActions({ table }: BasicContractD setFinalApproveDialog(true) } - // 재발송 확인 + // 재요청 확인 const confirmResend = async () => { setLoading(true) try { // TODO: 서버액션 호출 - // await resendContractsAction(resendContracts.map(c => c.id)) + await resendContractsAction(resendContracts.map(c => c.id)) console.log("대량 재발송:", resendContracts) toast.success(`${resendContracts.length}건의 계약서 재발송을 완료했습니다`) @@ -339,7 +339,7 @@ export function BasicContractDetailTableToolbarActions({ table }: BasicContractD </span> </Button> - {/* 재발송 버튼 */} + {/* 재요청 버튼 */} <Button variant="outline" size="sm" @@ -350,7 +350,7 @@ export function BasicContractDetailTableToolbarActions({ table }: BasicContractD > <Mail className="size-4" aria-hidden="true" /> <span className="hidden sm:inline"> - 재발송 {hasSelectedRows ? `(${selectedRows.length})` : ''} + 재요청 {hasSelectedRows ? `(${selectedRows.length})` : ''} </span> </Button> diff --git a/lib/basic-contract/status-detail/basic-contracts-detail-columns.tsx b/lib/basic-contract/status-detail/basic-contracts-detail-columns.tsx index 80c39d1e..9a140b27 100644 --- a/lib/basic-contract/status-detail/basic-contracts-detail-columns.tsx +++ b/lib/basic-contract/status-detail/basic-contracts-detail-columns.tsx @@ -1,4 +1,4 @@ -// basic-contracts-detail-columns.tsx +// simple-basic-contracts-detail-columns.tsx "use client" import * as React from "react" @@ -10,7 +10,16 @@ import { Badge } from "@/components/ui/badge" import { Checkbox } from "@/components/ui/checkbox" import { DataTableColumnHeaderSimple } from "@/components/data-table/data-table-column-simple-header" import { Button } from "@/components/ui/button" -import { MoreHorizontal, Download, Eye, Mail, FileText, Clock } from "lucide-react" +import { + MoreHorizontal, + Download, + Eye, + Mail, + FileText, + Clock, + MessageCircle, + Loader2 +} from "lucide-react" import { DropdownMenu, DropdownMenuContent, @@ -20,11 +29,18 @@ import { import { BasicContractView } from "@/db/schema" import { downloadFile, quickPreview } from "@/lib/file-download" import { toast } from "sonner" +import { useRouter } from "next/navigation" interface GetColumnsProps { setRowAction: React.Dispatch<React.SetStateAction<DataTableRowAction<BasicContractView> | null>> + gtcData: Record<number, { gtcDocumentId: number | null; hasComments: boolean }> + isLoadingGtcData: boolean + router: NextRouter; } +type NextRouter = ReturnType<typeof useRouter>; + + const CONTRACT_STATUS_CONFIG = { PENDING: { label: "발송완료", color: "gray" }, VENDOR_SIGNED: { label: "협력업체 서명완료", color: "blue" }, @@ -35,7 +51,12 @@ const CONTRACT_STATUS_CONFIG = { REJECTED: { label: "거절됨", color: "red" }, } as const -export function getDetailColumns({ setRowAction }: GetColumnsProps): ColumnDef<BasicContractView>[] { +export function getDetailColumns({ + setRowAction, + gtcData, + isLoadingGtcData, + router +}: GetColumnsProps): ColumnDef<BasicContractView>[] { const selectColumn: ColumnDef<BasicContractView> = { id: "select", @@ -163,7 +184,7 @@ export function getDetailColumns({ setRowAction }: GetColumnsProps): ColumnDef<B minSize: 120, }, - // 업체명 + // 업체명 (GTC 정보 포함) { accessorKey: "vendorName", header: ({ column }) => ( @@ -171,11 +192,51 @@ export function getDetailColumns({ setRowAction }: GetColumnsProps): ColumnDef<B ), cell: ({ row }) => { const name = row.getValue("vendorName") as string | null + const contract = row.original + const isGTCTemplate = contract.templateName?.includes('GTC') + const contractGtcData = gtcData[contract.id] + + const handleOpenGTC = (e: React.MouseEvent) => { + e.stopPropagation() + if (contractGtcData?.gtcDocumentId) { + const gtcUrl = `/evcp/basic-contract/vendor-gtc/${contractGtcData.gtcDocumentId}?vendorId=${contract.vendorId}&vendorName=${encodeURIComponent(contract.vendorName || '')}&contractId=${contract.id}&templateId=${contract.templateId}` + window.open(gtcUrl, '_blank') + } + } + return ( + <div className="flex items-center gap-2"> <div className="font-medium">{name || "-"}</div> + {isGTCTemplate && ( + <div className="flex items-center gap-1"> + {isLoadingGtcData ? ( + <Loader2 className="h-3 w-3 animate-spin text-gray-400" /> + ) : contractGtcData ? ( + <div className="flex items-center gap-1"> + {contractGtcData.hasComments && ( + <Badge + variant="secondary" + className="text-xs bg-orange-100 text-orange-700 cursor-pointer hover:bg-orange-200" + title={`GTC Document ID: ${contractGtcData.gtcDocumentId} - 클릭하여 협의이력 보기`} + onClick={handleOpenGTC} + > + <MessageCircle className="h-3 w-3 mr-1" /> + 협의이력 + </Badge> + )} + + </div> + ) : ( + <Badge variant="secondary" className="text-xs"> + GTC + </Badge> + )} + </div> + )} + </div> ) }, - minSize: 180, + minSize: 250, }, // 진행상태 @@ -349,7 +410,6 @@ export function getDetailColumns({ setRowAction }: GetColumnsProps): ColumnDef<B minSize: 120, }, - // 서명된 파일 { accessorKey: "signedFileName", diff --git a/lib/basic-contract/status-detail/basic-contracts-detail-table.tsx b/lib/basic-contract/status-detail/basic-contracts-detail-table.tsx index 2698842e..f18359de 100644 --- a/lib/basic-contract/status-detail/basic-contracts-detail-table.tsx +++ b/lib/basic-contract/status-detail/basic-contracts-detail-table.tsx @@ -9,9 +9,11 @@ import type { DataTableRowAction, } from "@/types/table" import { getDetailColumns } from "./basic-contracts-detail-columns" -import { getBasicContractsByTemplateId } from "@/lib/basic-contract/service" +import { getBasicContractsByTemplateId, checkGTCCommentsForContracts } from "@/lib/basic-contract/service" import { BasicContractView } from "@/db/schema" import { BasicContractDetailTableToolbarActions } from "./basic-contract-detail-table-toolbar-actions" +import { toast } from "sonner" +import { useRouter } from "next/navigation" interface BasicContractsDetailTableProps { templateId: number @@ -25,14 +27,52 @@ interface BasicContractsDetailTableProps { export function BasicContractsDetailTable({ templateId, promises }: BasicContractsDetailTableProps) { const [rowAction, setRowAction] = React.useState<DataTableRowAction<BasicContractView> | null>(null) + + // GTC data 상태 관리 + const [gtcData, setGtcData] = React.useState<Record<number, { gtcDocumentId: number | null; hasComments: boolean }>>({}) + const [isLoadingGtcData, setIsLoadingGtcData] = React.useState(false) const [{ data, pageCount }] = React.use(promises) + const router = useRouter() - console.log(data,"data") + console.log(gtcData, "gtcData") + console.log(data, "data") + + // GTC data 로딩 + React.useEffect(() => { + const loadGtcData = async () => { + if (!data || data.length === 0) return; + + // GTC가 포함된 template이 있는지 확인 + const hasGtcTemplates = data.some(contract => + contract.templateName?.includes('GTC') + ); + + if (!hasGtcTemplates) return; + + setIsLoadingGtcData(true); + try { + const gtcResults = await checkGTCCommentsForContracts(data); + setGtcData(gtcResults); + } catch (error) { + console.error('Error checking GTC data:', error); + toast.error("GTC 데이터를 불러오는데 실패했습니다."); + } finally { + setIsLoadingGtcData(false); + } + }; + + loadGtcData(); + }, [data]); const columns = React.useMemo( - () => getDetailColumns({ setRowAction }), - [setRowAction] + () => getDetailColumns({ + setRowAction, + gtcData, + isLoadingGtcData , + router + }), + [setRowAction, gtcData, isLoadingGtcData, router] ) const advancedFilterFields: DataTableAdvancedFilterField<BasicContractView>[] = [ @@ -76,15 +116,13 @@ export function BasicContractsDetailTable({ templateId, promises }: BasicContrac }) return ( - <> - <DataTable table={table}> - <DataTableAdvancedToolbar - table={table} - filterFields={advancedFilterFields} - > - <BasicContractDetailTableToolbarActions table={table} /> - </DataTableAdvancedToolbar> - </DataTable> - </> + <DataTable table={table}> + <DataTableAdvancedToolbar + table={table} + filterFields={advancedFilterFields} + > + <BasicContractDetailTableToolbarActions table={table} /> + </DataTableAdvancedToolbar> + </DataTable> ) }
\ No newline at end of file |
