From 54c654260c098864a8e113d46a242a057b58aae6 Mon Sep 17 00:00:00 2001
From: joonhoekim <26rote@gmail.com>
Date: Tue, 18 Nov 2025 15:03:15 +0900
Subject: (김준회) swp 수정: Activity Level에 따라 REV/Stage 표시하도록 변경,
 필드 NOTE->NOTE1, NOTE2 구조 변경 등
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 lib/swp/table/swp-inbox-table.tsx | 98 +++++++++++++++++++++++----------------
 1 file changed, 57 insertions(+), 41 deletions(-)

(limited to 'lib/swp/table/swp-inbox-table.tsx')

diff --git a/lib/swp/table/swp-inbox-table.tsx b/lib/swp/table/swp-inbox-table.tsx
index a88ff656..633191a1 100644
--- a/lib/swp/table/swp-inbox-table.tsx
+++ b/lib/swp/table/swp-inbox-table.tsx
@@ -19,6 +19,7 @@ import { toast } from "sonner";
 import { cn } from "@/lib/utils";
 import { formatSwpDate } from "@/lib/swp/utils";
 import { SwpInboxHistoryDialog } from "./swp-inbox-history-dialog";
+import { SwpNoteDialog } from "./swp-note-dialog";
 
 // 업로드 필요 문서 타입 (DB stageDocuments에서 조회)
 interface RequiredDocument {
@@ -45,7 +46,8 @@ interface TableRowData {
   statusNm: string | null;
   actvNo: string | null;
   crter: string | null; // CRTER (그대로 표시)
-  note: string | null; // Activity의 note 또는 buyerSystemComment
+  note1: string | null; // DC Note (Activity의 NOTE1 또는 buyerSystemComment)
+  pkgNo: string | null; // PKG_NO
   file: SwpFileApiResponse | null; // 업로드 필요 문서는 null
   uploadDate: string | null;
   // 각 행이 속한 그룹의 정보 (계층적 rowSpan 처리)
@@ -79,6 +81,8 @@ export function SwpInboxTable({
   const [selectedFiles, setSelectedFiles] = useState<Set<string>>(new Set()); // 선택된 파일 (fileKey)
   const [historyDialogOpen, setHistoryDialogOpen] = useState(false);
   const [selectedDocNo, setSelectedDocNo] = useState<string | null>(null);
+  const [noteDialogOpen, setNoteDialogOpen] = useState(false);
+  const [noteDialogContent, setNoteDialogContent] = useState<{ title: string; content: string | null }>({ title: "", content: null });
 
   // Status 집계 (API 응답 + 업로드 필요 문서)
   const statusCounts = useMemo(() => {
@@ -175,39 +179,23 @@ export function SwpInboxTable({
 
       // Document No별로 처리
       docGroups.forEach((docFiles, docNo) => {
-        // 3단계: 최신 RevNo 찾기 (CRTE_DTM 기준)
-        const sortedByDate = [...docFiles].sort((a, b) =>
-          (b.CRTE_DTM || "").localeCompare(a.CRTE_DTM || "")
-        );
-        const latestRevNo = sortedByDate[0]?.REV_NO || "";
-        const latestStage = sortedByDate[0]?.STAGE || null;
-        const latestStatus = sortedByDate[0]?.STAT || null;
-        const latestStatusNm = sortedByDate[0]?.STAT_NM || null;
-
-        // 4단계: 최신 Rev의 파일들만 필터링
-        const latestRevFiles = docFiles.filter(
-          (file) => file.REV_NO === latestRevNo
-        );
-
-        const totalDocFileCount = latestRevFiles.length;
+        const totalDocFileCount = docFiles.length;
         let isFirstInDoc = true;
 
-        // 5단계: Activity 기준으로 그룹화
+        // 3단계: ACTV_SEQ 기준으로 그룹화 (최신 Rev 필터링 제거)
         const activityGroups = new Map<string, SwpFileApiResponse[]>();
         
-        latestRevFiles.forEach((file) => {
-          const actvNo = file.ACTV_NO || "NO_ACTIVITY";
-          if (!activityGroups.has(actvNo)) {
-            activityGroups.set(actvNo, []);
+        docFiles.forEach((file) => {
+          const actvSeq = file.ACTV_SEQ || "NO_ACTIVITY";
+          if (!activityGroups.has(actvSeq)) {
+            activityGroups.set(actvSeq, []);
           }
-          activityGroups.get(actvNo)!.push(file);
+          activityGroups.get(actvSeq)!.push(file);
         });
 
-        let isFirstInRev = true;
-
         // Activity별로 처리
-        activityGroups.forEach((activityFiles, actvNo) => {
-          // 6단계: Upload Date 기준 DESC 정렬
+        activityGroups.forEach((activityFiles) => {
+          // 4단계: Upload Date 기준 DESC 정렬
           const sortedFiles = activityFiles.sort((a, b) =>
             (b.CRTE_DTM || "").localeCompare(a.CRTE_DTM || "")
           );
@@ -218,26 +206,27 @@ export function SwpInboxTable({
           const firstActivityFile = sortedFiles[0];
           if (!firstActivityFile) return;
 
-          // 7단계: 각 파일을 테이블 행으로 변환
+          // 5단계: 각 파일을 테이블 행으로 변환
           sortedFiles.forEach((file, idx) => {
             rows.push({
               uploadId,
               docNo,
-              revNo: latestRevNo,
-              stage: latestStage,
-              status: latestStatus,
-              statusNm: latestStatusNm,
-              actvNo: actvNo === "NO_ACTIVITY" ? null : actvNo,
+              revNo: file.REV_NO || null,
+              stage: file.STAGE || null,
+              status: file.STAT || null,
+              statusNm: file.STAT_NM || null,
+              actvNo: file.ACTV_NO || null,
               crter: firstActivityFile.CRTER, // Activity 첫 파일의 CRTER
-              note: firstActivityFile.NOTE || null, // Activity 첫 파일의 note
+              note1: firstActivityFile.NOTE1 || null, // Activity 첫 파일의 DC Note
+              pkgNo: file.PKG_NO || null,
               file,
               uploadDate: file.CRTE_DTM,
               isFirstInUpload,
               fileCountInUpload: totalUploadFileCount,
               isFirstInDoc,
               fileCountInDoc: totalDocFileCount,
-              isFirstInRev,
-              fileCountInRev: totalDocFileCount, // Rev = Doc의 최신 Rev이므로 파일 수 동일
+              isFirstInRev: idx === 0,
+              fileCountInRev: totalActivityFileCount, // Activity 내 파일 수
               isFirstInActivity: idx === 0,
               fileCountInActivity: totalActivityFileCount,
               isRequiredDoc: false,
@@ -247,7 +236,6 @@ export function SwpInboxTable({
             if (idx === 0) {
               isFirstInUpload = false;
               isFirstInDoc = false;
-              isFirstInRev = false;
             }
           });
         });
@@ -266,7 +254,8 @@ export function SwpInboxTable({
           statusNm: "Upload Required",
           actvNo: null,
           crter: null,
-          note: doc.buyerSystemComment,
+          note1: doc.buyerSystemComment, // DB의 comment를 DC Note에 매핑
+          pkgNo: null,
           file: null,
           uploadDate: null,
           isFirstInUpload: true,
@@ -488,7 +477,8 @@ export function SwpInboxTable({
                 <TableHead className="w-[120px]">Status</TableHead>
                 <TableHead className="w-[100px]">Activity</TableHead>
                 <TableHead className="w-[120px]">Upload ID (User)</TableHead>
-                <TableHead className="w-[150px]">Note</TableHead>
+                <TableHead className="w-[150px]">DC Note</TableHead>
+                <TableHead className="w-[120px]">PKG NO</TableHead>
                 <TableHead className="w-[400px]">Attachment File</TableHead>
                 <TableHead className="w-[180px]">Upload Date</TableHead>
               </TableRow>
@@ -564,17 +554,35 @@ export function SwpInboxTable({
                       </TableCell>
                     ) : null}
 
-                    {/* Note - Activity의 첫 파일에만 표시 (개행문자 처리) */}
+                    {/* DC Note - Activity의 첫 파일에만 표시 */}
                     {row.isFirstInActivity ? (
                       <TableCell 
                         rowSpan={row.fileCountInActivity} 
-                        className="text-xs max-w-[150px] align-top whitespace-pre-wrap"
+                        className="text-xs max-w-[150px] align-top"
                         style={{ verticalAlign: "top" }}
+                        onClick={(e) => {
+                          if (row.note1) {
+                            e.stopPropagation();
+                            setNoteDialogContent({ title: "DC Note", content: row.note1 });
+                            setNoteDialogOpen(true);
+                          }
+                        }}
                       >
-                        {row.note || <span className="text-muted-foreground">-</span>}
+                        {row.note1 ? (
+                          <div className="truncate cursor-pointer hover:text-primary underline" title="클릭하여 전체 내용 보기">
+                            {row.note1}
+                          </div>
+                        ) : (
+                          <span className="text-muted-foreground">-</span>
+                        )}
                       </TableCell>
                     ) : null}
 
+                    {/* PKG NO - 각 파일마다 표시 */}
+                    <TableCell className="font-mono text-sm">
+                      {row.pkgNo || <span className="text-muted-foreground">-</span>}
+                    </TableCell>
+
                     {/* Attachment File - 각 파일마다 표시 (줄바꿈 허용) */}
                     <TableCell className="max-w-[400px]">
                       {row.file ? (
@@ -620,6 +628,14 @@ export function SwpInboxTable({
         projNo={projNo}
         userId={userId}
       />
+
+      {/* Note 전체 내용 Dialog */}
+      <SwpNoteDialog
+        open={noteDialogOpen}
+        onOpenChange={setNoteDialogOpen}
+        title={noteDialogContent.title}
+        content={noteDialogContent.content}
+      />
     </div>
   );
 }
-- 
cgit v1.2.3

