diff options
| author | 0-Zz-ang <s1998319@gmail.com> | 2025-11-20 17:39:10 +0900 |
|---|---|---|
| committer | 0-Zz-ang <s1998319@gmail.com> | 2025-11-20 17:39:10 +0900 |
| commit | f95fbb0719c5754360472d066b0bbed4bda6a40a (patch) | |
| tree | d58b69d97c1dc300ccba8174d27c3a2023d34af6 /lib/basic-contract | |
| parent | 088431a6572d87f7ee287252a4357e6c332d04f7 (diff) | |
(박서영)준법설문조사 redFlag관련사항수정
Diffstat (limited to 'lib/basic-contract')
3 files changed, 146 insertions, 3 deletions
diff --git a/lib/basic-contract/actions/check-red-flags.ts b/lib/basic-contract/actions/check-red-flags.ts new file mode 100644 index 00000000..dd45a56a --- /dev/null +++ b/lib/basic-contract/actions/check-red-flags.ts @@ -0,0 +1,48 @@ +"use server"; + +import { BasicContractView } from "@/db/schema"; +import { getTriggeredRedFlagQuestions } from "@/lib/compliance/red-flag-notifier"; + +/** + * 여러 계약서에 대한 Red Flag 발생 여부를 한 번에 확인 + */ +export async function checkRedFlagsForContracts( + contracts: BasicContractView[] +): Promise<Record<number, boolean>> { + const result: Record<number, boolean> = {}; + + // 준법서약 템플릿인 계약서만 필터링 + const complianceContracts = contracts.filter(contract => + contract.templateName?.includes('준법') + ); + + if (complianceContracts.length === 0) { + return result; + } + + // 각 계약서에 대해 Red Flag 발생 여부 확인 + const redFlagChecks = await Promise.all( + complianceContracts.map(async (contract) => { + try { + const triggeredFlags = await getTriggeredRedFlagQuestions(contract.id); + return { + contractId: contract.id, + hasRedFlag: triggeredFlags.length > 0 + }; + } catch (error) { + console.error(`Error checking red flags for contract ${contract.id}:`, error); + return { + contractId: contract.id, + hasRedFlag: false + }; + } + }) + ); + + // 결과를 Record 형태로 변환 + redFlagChecks.forEach(check => { + result[check.contractId] = check.hasRedFlag; + }); + + return result; +} 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 5a875541..c872aede 100644 --- a/lib/basic-contract/status-detail/basic-contracts-detail-columns.tsx +++ b/lib/basic-contract/status-detail/basic-contracts-detail-columns.tsx @@ -36,6 +36,9 @@ interface GetColumnsProps { setRowAction: React.Dispatch<React.SetStateAction<DataTableRowAction<BasicContractView> | null>> gtcData: Record<number, { gtcDocumentId: number | null; hasComments: boolean }> isLoadingGtcData: boolean + redFlagData: Record<number, boolean> + isLoadingRedFlagData: boolean + isComplianceTemplate: boolean router: NextRouter; } @@ -56,6 +59,9 @@ export function getDetailColumns({ setRowAction, gtcData, isLoadingGtcData, + redFlagData, + isLoadingRedFlagData, + isComplianceTemplate, router }: GetColumnsProps): ColumnDef<BasicContractView>[] { @@ -184,7 +190,41 @@ export function getDetailColumns({ maxSize: 80, } - return [ + // Red Flag 발생여부 컬럼 (준법서약 템플릿만) + const redFlagColumn: ColumnDef<BasicContractView> = { + id: "redFlag", + header: ({ column }) => ( + <DataTableColumnHeaderSimple column={column} title="Red Flag" /> + ), + cell: ({ row }) => { + const contract = row.original; + const contractId = contract.id; + + // 로딩 중이면 로딩 표시 + if (isLoadingRedFlagData) { + return <Loader2 className="h-4 w-4 animate-spin text-muted-foreground" />; + } + + const hasRedFlag = redFlagData[contractId] || false; + + if (hasRedFlag) { + return ( + <Badge variant="destructive" className="font-medium"> + Red Flag + </Badge> + ); + } + + return ( + <div className="text-sm text-gray-400">-</div> + ); + }, + minSize: 120, + enableHiding: false, + } + + // 기본 컬럼 배열 + const baseColumns: ColumnDef<BasicContractView>[] = [ selectColumn, // 업체 코드 @@ -513,4 +553,18 @@ export function getDetailColumns({ actionsColumn, ] + + // 준법서약 템플릿인 경우 Red Flag 컬럼을 법무검토 상태 뒤에 추가 + if (isComplianceTemplate) { + const legalReviewStatusIndex = baseColumns.findIndex((col) => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + return (col as any).accessorKey === 'legalReviewStatus' + }) + + if (legalReviewStatusIndex !== -1) { + baseColumns.splice(legalReviewStatusIndex + 1, 0, redFlagColumn) + } + } + + return baseColumns }
\ No newline at end of file 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 0df46066..93853560 100644 --- a/lib/basic-contract/status-detail/basic-contracts-detail-table.tsx +++ b/lib/basic-contract/status-detail/basic-contracts-detail-table.tsx @@ -11,6 +11,7 @@ import type { import { getDetailColumns } from "./basic-contracts-detail-columns" import { getBasicContractsByTemplateId } from "@/lib/basic-contract/service" import { checkGTCCommentsForContracts } from "@/lib/basic-contract/actions/check-gtc-comments" +import { checkRedFlagsForContracts } from "@/lib/basic-contract/actions/check-red-flags" import { BasicContractView } from "@/db/schema" import { BasicContractDetailTableToolbarActions } from "./basic-contract-detail-table-toolbar-actions" import { toast } from "sonner" @@ -32,6 +33,10 @@ export function BasicContractsDetailTable({ templateId, promises }: BasicContrac // GTC data 상태 관리 const [gtcData, setGtcData] = React.useState<Record<number, { gtcDocumentId: number | null; hasComments: boolean }>>({}) const [isLoadingGtcData, setIsLoadingGtcData] = React.useState(false) + + // Red Flag data 상태 관리 + const [redFlagData, setRedFlagData] = React.useState<Record<number, boolean>>({}) + const [isLoadingRedFlagData, setIsLoadingRedFlagData] = React.useState(false) const [{ data, pageCount }] = React.use(promises) const router = useRouter() @@ -66,14 +71,50 @@ export function BasicContractsDetailTable({ templateId, promises }: BasicContrac loadGtcData(); }, [data]); + // Red Flag data 로딩 + React.useEffect(() => { + const loadRedFlagData = async () => { + if (!data || data.length === 0) return; + + // 준법서약 템플릿이 있는지 확인 + const hasComplianceTemplates = data.some(contract => + contract.templateName?.includes('준법') + ); + + if (!hasComplianceTemplates) return; + + setIsLoadingRedFlagData(true); + try { + const redFlagResults = await checkRedFlagsForContracts(data); + setRedFlagData(redFlagResults); + } catch (error) { + console.error('Error checking Red Flag data:', error); + toast.error("Red Flag 데이터를 불러오는데 실패했습니다."); + } finally { + setIsLoadingRedFlagData(false); + } + }; + + loadRedFlagData(); + }, [data]); + + // 준법서약 템플릿인지 확인 + const isComplianceTemplate = React.useMemo(() => { + if (!data || data.length === 0) return false; + return data.some(contract => contract.templateName?.includes('준법')); + }, [data]); + const columns = React.useMemo( () => getDetailColumns({ setRowAction, gtcData, - isLoadingGtcData , + isLoadingGtcData, + redFlagData, + isLoadingRedFlagData, + isComplianceTemplate, router }), - [setRowAction, gtcData, isLoadingGtcData, router] + [setRowAction, gtcData, isLoadingGtcData, redFlagData, isLoadingRedFlagData, isComplianceTemplate, router] ) const advancedFilterFields: DataTableAdvancedFilterField<BasicContractView>[] = [ |
