From 0d08239697a94718a938ed98b0dec23171c62bfc Mon Sep 17 00:00:00 2001
From: joonhoekim <26rote@gmail.com>
Date: Wed, 3 Sep 2025 01:35:54 +0000
Subject: (김준회) 협력업체 기본정보 - 매출정보 섹션 오류 수정
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 lib/vendor-basic-info/sales-info-table.tsx | 179 +++++++++++++++++++++++++++++
 1 file changed, 179 insertions(+)
 create mode 100644 lib/vendor-basic-info/sales-info-table.tsx

(limited to 'lib/vendor-basic-info/sales-info-table.tsx')

diff --git a/lib/vendor-basic-info/sales-info-table.tsx b/lib/vendor-basic-info/sales-info-table.tsx
new file mode 100644
index 00000000..4381e878
--- /dev/null
+++ b/lib/vendor-basic-info/sales-info-table.tsx
@@ -0,0 +1,179 @@
+"use client";
+
+import React from "react";
+import {
+  Table,
+  TableBody,
+  TableCell,
+  TableHead,
+  TableHeader,
+  TableRow,
+} from "@/components/ui/table";
+import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
+
+interface SalesInfoTableProps {
+  creditLoading: boolean;
+  creditError: string | null;
+  creditResults: any[];
+  selectedCreditService: string;
+  bestResult: any;
+  getCurrentResult: () => any | null;
+  handleCreditServiceChange: (code: string) => void;
+  creditServices: { code: string; name: string }[];
+}
+
+export function SalesInfoTable({
+  creditLoading,
+  creditError,
+  creditResults,
+  selectedCreditService,
+  bestResult,
+  getCurrentResult,
+  handleCreditServiceChange,
+  creditServices,
+}: SalesInfoTableProps) {
+  // 'auto' 선택 시 bestResult 우선 사용, 수동 선택 시 해당 코드의 결과 사용
+  const currentResult = React.useMemo(() => {
+    // 'auto' 선택 시에만 bestResult 사용
+    if (selectedCreditService === "auto") {
+      return bestResult || getCurrentResult?.() || null;
+    }
+    // 수동 선택 시 해당 평가사 결과
+    return creditResults.find((r) => r.code === selectedCreditService) || null;
+  }, [selectedCreditService, bestResult, creditResults, getCurrentResult]);
+
+  const data = currentResult?.data || null;
+
+  // 가용한 지표 인덱스 탐색: bs_dt{n} 키를 모두 수집해 인덱스 배열 생성
+  const availableIndexes: number[] = React.useMemo(() => {
+    if (!data) return [];
+    // 0,1,2(3개년)만 표시. 해당 인덱스의 기준일 키가 존재하는 경우만 포함
+    return [0, 1, 2].filter((n) => (data as any)[`BS_DT${n}`] || (data as any)[`bs_dt${n}`]);
+  }, [data]);
+
+  // TR 계열(비율) 키는 연도 인덱스에 따라 0→3, 1→2, 2→1 매핑됨
+  const mapIdxToSuffix = (idx: number): string | null => {
+    if (idx === 0) return "3";
+    if (idx === 1) return "2";
+    if (idx === 2) return "1";
+    return null; // 3년 초과 시 해당 비율 데이터가 없을 수 있음
+  };
+
+  const getField = (prefix: string, idx: number): string => {
+    // prefix는 소문자 기준(e.g., bs59_, pl27_), 대문자 키(e.g., BS59_)도 함께 조회
+    const lowerKey = `${prefix}${idx}`;
+    const upperKey = `${prefix.toUpperCase()}${idx}`;
+    const v = (data && (data[lowerKey] ?? data[upperKey])) as unknown as string | number | undefined | null;
+    return v !== undefined && v !== null && v !== "" ? String(v) : "-";
+  };
+
+  const getRatio = (baseKey: string, idx: number): string => {
+    const suffix = mapIdxToSuffix(idx);
+    if (!suffix) return "-";
+    const key = `${baseKey}${suffix}`;
+    const v = data?.[key];
+    return v && v !== "" ? String(v) : "-";
+  };
+
+  return (
+    <div className="space-y-4">
+      <div className="p-4 border-b bg-muted/30">
+        <div className="flex items-center justify-between mb-2">
+          <span className="text-sm font-medium">신용평가사 데이터</span>
+          {creditLoading && (
+            <div className="flex items-center gap-2 text-sm text-muted-foreground">
+              <div className="animate-spin h-4 w-4 border-2 border-primary border-t-transparent rounded-full"></div>
+              로딩 중...
+            </div>
+          )}
+        </div>
+        <div className="flex items-center gap-4">
+          <Select value={selectedCreditService} onValueChange={handleCreditServiceChange}>
+            <SelectTrigger className="w-48">
+              <SelectValue placeholder="신용평가사 선택" />
+            </SelectTrigger>
+            <SelectContent>
+              {creditServices.map((service) => {
+                const result = creditResults.find((r) => r.code === service.code);
+                return (
+                  <SelectItem key={service.code} value={service.code}>
+                    {service.name}
+                    {service.code !== "auto" && result && (
+                      <span className="ml-2 text-xs text-muted-foreground">
+                        {result.success ? `(${result.dataCount}개 항목)` : "(조회 실패)"}
+                      </span>
+                    )}
+                  </SelectItem>
+                );
+              })}
+            </SelectContent>
+          </Select>
+
+          {currentResult && (
+            <div className="text-sm text-muted-foreground">
+              선택됨: <span className="font-medium">{currentResult?.name}</span>
+              {selectedCreditService === "auto" && bestResult && (
+                <span className="ml-1">({bestResult.dataCount}개 항목으로 자동선택)</span>
+              )}
+            </div>
+          )}
+
+          {creditError && <div className="text-sm text-destructive">{creditError}</div>}
+
+          {!creditLoading && !creditError && creditResults.length > 0 && !currentResult?.data && (
+            <div className="text-sm text-muted-foreground">신용평가 데이터가 없습니다</div>
+          )}
+        </div>
+      </div>
+
+      <Table>
+        <TableHeader>
+          <TableRow>
+            <TableHead rowSpan={2} className="text-center border-r align-middle">기준일</TableHead>
+            <TableHead colSpan={3} className="text-center border-r">자산 구성</TableHead>
+            <TableHead rowSpan={2} className="text-center border-r align-middle">매출액<br />(백만원)</TableHead>
+            <TableHead rowSpan={2} className="text-center border-r align-middle">영업이익<br />(백만원)</TableHead>
+            <TableHead rowSpan={2} className="text-center border-r align-middle">당기순이익<br />(백만원)</TableHead>
+            <TableHead rowSpan={2} className="text-center border-r align-middle">부채비율<br />(%)</TableHead>
+            <TableHead rowSpan={2} className="text-center border-r align-middle">차입금의존도<br />(%)</TableHead>
+            <TableHead rowSpan={2} className="text-center border-r align-middle">영업이익률<br />(%)</TableHead>
+            <TableHead rowSpan={2} className="text-center border-r align-middle">순이익률<br />(%)</TableHead>
+            <TableHead rowSpan={2} className="text-center border-r align-middle">매출액증감<br />(%)</TableHead>
+            <TableHead rowSpan={2} className="text-center align-middle">유동비율<br />(%)</TableHead>
+          </TableRow>
+          <TableRow>
+            <TableHead className="text-center border-r">총자산</TableHead>
+            <TableHead className="text-center border-r">부채총계</TableHead>
+            <TableHead className="text-center border-r">자본총계</TableHead>
+          </TableRow>
+        </TableHeader>
+        <TableBody>
+          {availableIndexes.length === 0 && (
+            <TableRow>
+              <TableCell colSpan={13} className="text-center text-sm text-muted-foreground">표시할 데이터가 없습니다</TableCell>
+            </TableRow>
+          )}
+          {availableIndexes.map((idx) => (
+            <TableRow key={`row-${idx}`}>
+              <TableCell className="text-center font-medium border-r bg-yellow-50">{(data?.[`BS_DT${idx}`] || data?.[`bs_dt${idx}`] || "-") as any}</TableCell>
+              <TableCell className="text-right border-r">{getField("bs59_", idx)}</TableCell>
+              <TableCell className="text-right border-r">{getField("bs91_", idx)}</TableCell>
+              <TableCell className="text-right border-r">{getField("bs113_", idx)}</TableCell>
+              <TableCell className="text-right border-r">{getField("pl01_", idx)}</TableCell>
+              <TableCell className="text-right border-r">{getField("pl27_", idx)}</TableCell>
+              <TableCell className="text-right border-r">{getField("pl71_", idx)}</TableCell>
+              <TableCell className="text-right border-r">{getRatio("TR005", idx)}</TableCell>
+              <TableCell className="text-right border-r">{getRatio("TR051", idx)}</TableCell>
+              <TableCell className="text-right border-r">{getRatio("TR052", idx)}</TableCell>
+              <TableCell className="text-right border-r">{getRatio("TR010", idx)}</TableCell>
+              <TableCell className="text-right border-r">{getRatio("TR022", idx)}</TableCell>
+              <TableCell className="text-right">{getRatio("TR001", idx)}</TableCell>
+            </TableRow>
+          ))}
+        </TableBody>
+      </Table>
+    </div>
+  );
+}
+
+
-- 
cgit v1.2.3

