From 02b1cf005cf3e1df64183d20ba42930eb2767a9f Mon Sep 17 00:00:00 2001 From: dujinkim Date: Thu, 21 Aug 2025 06:57:36 +0000 Subject: (대표님, 최겸) 설계메뉴추가, 작업사항 업데이트 설계메뉴 - 문서관리 설계메뉴 - 벤더 데이터 gtc 메뉴 업데이트 정보시스템 - 메뉴리스트 및 정보 업데이트 파일 라우트 업데이트 엑셀임포트 개선 기본계약 개선 벤더 가입과정 변경 및 개선 벤더 기본정보 - pq 돌체 오류 수정 및 개선 벤더 로그인 과정 이메일 오류 수정 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/vendor-info/pq-simple-dialog.tsx | 417 ++++++++++++++++++++++++++++ 1 file changed, 417 insertions(+) create mode 100644 components/vendor-info/pq-simple-dialog.tsx (limited to 'components/vendor-info') diff --git a/components/vendor-info/pq-simple-dialog.tsx b/components/vendor-info/pq-simple-dialog.tsx new file mode 100644 index 00000000..bb26685d --- /dev/null +++ b/components/vendor-info/pq-simple-dialog.tsx @@ -0,0 +1,417 @@ +"use client" + +import { useState, useEffect } from "react" +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, +} from "@/components/ui/dialog" +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table" +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select" +import { Button } from "@/components/ui/button" +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" +import { Badge } from "@/components/ui/badge" +import { Download, FileText, ChevronDown, ChevronUp, Search } from "lucide-react" +import { Input } from "@/components/ui/input" +import { toast } from "sonner" +import { getPQProjectsByVendorId, ProjectPQ, getPQDataByVendorId, PQGroupData } from "@/lib/pq/service" +import { downloadFile } from "@/lib/file-download" + +interface PQSimpleDialogProps { + open: boolean + onOpenChange: (open: boolean) => void + vendorId: string +} + +interface PQItemData { + groupName: string + code: string + checkPoint: string + description: string + answer: string | null + inputFormat: string + fileName?: string | null + filePath?: string | null +} + +export function PQSimpleDialog({ + open, + onOpenChange, + vendorId, +}: PQSimpleDialogProps) { + const [projects, setProjects] = useState([]) + const [selectedProject, setSelectedProject] = useState(null) + const [pqData, setPqData] = useState([]) + const [loading, setLoading] = useState(false) + const [expandedGroups, setExpandedGroups] = useState>(new Set()) + const [searchTerm, setSearchTerm] = useState("") + + // vendorId를 숫자로 변환 + const numericVendorId = parseInt(vendorId) + + useEffect(() => { + if (open && !isNaN(numericVendorId)) { + loadProjects() + } + }, [open, numericVendorId]) + + const loadProjects = async () => { + try { + setLoading(true) + const projectList = await getPQProjectsByVendorId(numericVendorId) + setProjects(projectList) + + if (projectList.length > 0) { + setSelectedProject(projectList[0]) + await loadPQData(projectList[0].projectId) + } + } catch (error) { + console.error("프로젝트 목록 로드 실패:", error) + toast.error("PQ 프로젝트 목록을 불러오는데 실패했습니다.") + } finally { + setLoading(false) + } + } + + const loadPQData = async (projectId: number | null) => { + if (projectId === null) return + + try { + setLoading(true) + const data = await getPQDataByVendorId(numericVendorId, projectId) + setPqData(data) + } catch (error) { + console.error("PQ 데이터 로드 실패:", error) + toast.error("PQ 데이터를 불러오는데 실패했습니다.") + } finally { + setLoading(false) + } + } + + const handleProjectChange = async (project: ProjectPQ) => { + setSelectedProject(project) + await loadPQData(project.projectId) + } + + const handleFileDownload = async (filePath: string, fileName: string) => { + try { + const result = await downloadFile(filePath, fileName) + if (result.success) { + toast.success(`${fileName} 파일이 다운로드되었습니다.`) + } else { + toast.error(result.error || "파일 다운로드에 실패했습니다.") + } + } catch (error) { + console.error("파일 다운로드 오류:", error) + toast.error("파일 다운로드에 실패했습니다.") + } + } + + // 코드 순서로 정렬하는 함수 (1-1-1, 1-1-2, 1-2-1 순서) + const sortByCode = (items: any[]) => { + return [...items].sort((a, b) => { + const parseCode = (code: string) => { + return code.split('-').map(part => parseInt(part, 10)) + } + + const aCode = parseCode(a.code) + const bCode = parseCode(b.code) + + for (let i = 0; i < Math.max(aCode.length, bCode.length); i++) { + const aPart = aCode[i] || 0 + const bPart = bCode[i] || 0 + if (aPart !== bPart) { + return aPart - bPart + } + } + return 0 + }) + } + + // 검색 필터링 함수 + const filterItems = (items: any[], searchTerm: string) => { + if (!searchTerm.trim()) return items + + const search = searchTerm.toLowerCase() + return items.filter(item => + item.checkPoint?.toLowerCase().includes(search) || + item.description?.toLowerCase().includes(search) || + item.code?.toLowerCase().includes(search) + ) + } + + // 그룹별로 정렬 및 필터링된 데이터 계산 + const processedPQData = pqData.map(group => ({ + ...group, + items: filterItems(sortByCode(group.items), searchTerm) + })).filter(group => group.items.length > 0) // 검색 결과가 없는 그룹은 제외 + + const toggleGroup = (groupName: string) => { + setExpandedGroups(prev => { + const newSet = new Set(prev) + if (newSet.has(groupName)) { + newSet.delete(groupName) + } else { + newSet.add(groupName) + } + return newSet + }) + } + + const renderPQContent = (groupData: PQGroupData) => { + const isExpanded = expandedGroups.has(groupData.groupName) + const itemCount = groupData.items.length + + return ( + + toggleGroup(groupData.groupName)} + > +
+
+ + {groupData.groupName} + + + {itemCount}개 항목 + +
+ {isExpanded ? ( + + ) : ( + + )} +
+
+ + {isExpanded && ( + +
+ {groupData.items.map((item, index) => ( +
+
+
+
+ + {item.code} + + + {item.inputFormat} + +
+

+ {item.checkPoint} +

+ {item.description && ( +

+ {item.description} +

+ )} +
+ +
+
+ +

+ {item.answer || "답변 없음"} +

+
+ + {item.attachments && item.attachments.length > 0 && ( +
+ +
+ {item.attachments.map((attachment, idx) => ( + + ))} +
+
+ )} +
+
+
+ ))} +
+
+ )} +
+ ) + } + + if (projects.length === 0 && !loading) { + return ( + + + + PQ 조회 + +
+

제출된 PQ가 없습니다.

+
+
+
+ ) + } + + return ( + + + + PQ 조회 + + + {loading ? ( +
+

로딩 중...

+
+ ) : selectedProject ? ( +
+ {/* 프로젝트 선택 */} + {projects.length > 1 && ( +
+ + +
+ )} + + {/* 프로젝트 정보 카드 */} + + +
+
+ {selectedProject.projectName} + + {selectedProject.status} + +
+
+
+ 프로젝트 코드: {selectedProject.projectCode} • + 제출일: {selectedProject.submittedAt ? new Date(selectedProject.submittedAt).toLocaleDateString('ko-KR') : '-'} +
+
+
+ + {/* 검색 및 PQ 그룹 데이터 */} +
+
+

PQ 항목

+
+ + +
+
+ + {/* 검색 박스 */} +
+ + setSearchTerm(e.target.value)} + className="pl-10" + /> + {searchTerm && ( + + )} +
+ + {/* 검색 결과 카운트 */} + {searchTerm && ( +
+ 검색 결과: {processedPQData.reduce((total, group) => total + group.items.length, 0)}개 항목 + ({processedPQData.length}개 그룹) +
+ )} + + {/* PQ 그룹 목록 */} + {processedPQData.length > 0 ? ( + processedPQData.map((groupData) => renderPQContent(groupData)) + ) : ( +
+

+ {searchTerm ? "검색 결과가 없습니다." : "PQ 데이터가 없습니다."} +

+
+ )} +
+
+ ) : null} +
+
+ ) +} -- cgit v1.2.3