From 8a19a6fa336768d8b6712752c9d713360067ecb0 Mon Sep 17 00:00:00 2001 From: dujinkim Date: Mon, 8 Dec 2025 08:45:20 +0000 Subject: (최겸) 구매 피드백 수정, 안전담당자, pq항목 내 첨부, 내외자 구분, 도로명주소 api 반영(운영기준) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/site-visit/client-site-visit-wrapper.tsx | 1 + lib/site-visit/service.ts | 5 +- lib/site-visit/site-visit-detail-dialog.tsx | 583 +++++++++++++++------------ 3 files changed, 328 insertions(+), 261 deletions(-) (limited to 'lib/site-visit') diff --git a/lib/site-visit/client-site-visit-wrapper.tsx b/lib/site-visit/client-site-visit-wrapper.tsx index e2664ac3..ab63fa0b 100644 --- a/lib/site-visit/client-site-visit-wrapper.tsx +++ b/lib/site-visit/client-site-visit-wrapper.tsx @@ -100,6 +100,7 @@ interface SiteVisitRequest { // 협력업체 정보 vendorInfo?: { id: number + country?: string siteVisitRequestId: number factoryName: string factoryLocation: string diff --git a/lib/site-visit/service.ts b/lib/site-visit/service.ts index 684e73f1..54f2bf54 100644 --- a/lib/site-visit/service.ts +++ b/lib/site-visit/service.ts @@ -593,6 +593,7 @@ export async function getSiteVisitRequestAction(investigationId: number) { vendorName: vendors.vendorName, vendorCode: vendors.vendorCode, vendorEmail: vendors.email, + vendorCountry: vendors.country, }) .from(siteVisitRequests) .leftJoin( @@ -658,7 +659,9 @@ export async function getSiteVisitRequestAction(investigationId: number) { ...item, shiAttendees: item.shiAttendees as Record | null, vendorRequests: item.vendorRequests as Record | null, - vendorInfo, + vendorInfo: vendorInfo + ? { ...vendorInfo, country: (item as any).vendorCountry || "" } + : null, shiAttachments, }; }) diff --git a/lib/site-visit/site-visit-detail-dialog.tsx b/lib/site-visit/site-visit-detail-dialog.tsx index 7788454a..74e749c4 100644 --- a/lib/site-visit/site-visit-detail-dialog.tsx +++ b/lib/site-visit/site-visit-detail-dialog.tsx @@ -1,261 +1,324 @@ -"use client" - -import * as React from "react" -import { format } from "date-fns" -import { ko } from "date-fns/locale" -import { FileText, Download } from "lucide-react" -import { toast } from "sonner" - -import { Button } from "@/components/ui/button" -import { - Dialog, - DialogContent, - DialogDescription, - DialogHeader, - DialogTitle, -} from "@/components/ui/dialog" -import { Separator } from "@/components/ui/separator" -import { formatDate } from "../utils" - -interface SiteVisitRequest { - id: number - investigationId: number - requesterId: number | null - inspectionDuration: string | null - requestedStartDate: Date | null - requestedEndDate: Date | null - shiAttendees: Record | null - shiAttendeeDetails?: string | null - vendorRequests: Record | null - additionalRequests: string | null - status: string - sentAt: Date | null - createdAt: Date - updatedAt: Date - - // 실사정보 - investigationMethod: string | null // QM담당자가 작성한 실사방법 - investigationAddress: string | null - investigationNotes: string | null - forecastedAt: Date | null - actualAt: Date | null - result: string | null - resultNotes: string | null - - // PQ 정보 - pqItems: string | null | Array<{itemCode: string, itemName: string}> - - // 요청자 정보 - requesterName: string | null - requesterEmail: string | null - requesterTitle: string | null - - // QM 매니저 정보 - qmManagerName: string | null - qmManagerEmail: string | null - qmManagerTitle: string | null - - // 협력업체 정보 - vendorInfo?: { - id: number - siteVisitRequestId: number - factoryName: string - factoryLocation: string - factoryAddress: string - factoryPicName: string - factoryPicPhone: string - factoryPicEmail: string - factoryDirections: string | null - accessProcedure: string | null - hasAttachments: boolean - otherInfo: string | null - submittedAt: Date - submittedBy: number - createdAt: Date - updatedAt: Date - } | null - - // SHI 첨부파일 - shiAttachments?: Array<{ - id: number - siteVisitRequestId: number - vendorSiteVisitInfoId: number | null - fileName: string - originalFileName: string - filePath: string - fileSize: number - mimeType: string - createdAt: Date - updatedAt: Date - }> | null -} - -interface SiteVisitDetailDialogProps { - isOpen: boolean - onOpenChange: (open: boolean) => void - selectedRequest: SiteVisitRequest | null -} - -export function SiteVisitDetailDialog({ - isOpen, - onOpenChange, - selectedRequest, -}: SiteVisitDetailDialogProps) { - - return ( - - - - 방문실사 상세 정보 - - 작성한 방문실사 정보의 상세 내용입니다. - - - - {selectedRequest && ( -
- {/* 기본 정보 */} - - {/* 협력업체 정보 */} - {selectedRequest.vendorInfo && ( - <> - -
-

작성한 협력업체 정보

-
-
-
-
-

공장 기본 정보

-
-
공장명: {selectedRequest.vendorInfo.factoryName}
-
공장위치: {selectedRequest.vendorInfo.factoryLocation}
-
공장주소: {selectedRequest.vendorInfo.factoryAddress}
-
-
- -
-

공장 담당자 정보

-
-
이름: {selectedRequest.vendorInfo.factoryPicName}
-
전화번호: {selectedRequest.vendorInfo.factoryPicPhone}
-
이메일: {selectedRequest.vendorInfo.factoryPicEmail}
-
-
-
- -
- {selectedRequest.vendorInfo.factoryDirections && ( -
-

공장 가는 법

-
-

{selectedRequest.vendorInfo.factoryDirections}

-
-
- )} - - {selectedRequest.vendorInfo.accessProcedure && ( -
-

공장 출입절차

-
-

{selectedRequest.vendorInfo.accessProcedure}

-
-
- )} -
-
- - {/* 기타 정보 */} - {selectedRequest.vendorInfo.otherInfo && ( -
-

기타 정보

-
-

{selectedRequest.vendorInfo.otherInfo}

-
-
- )} - - {/* 제출 정보 */} -
-

제출 정보

-
-
제출일: {formatDate(selectedRequest.vendorInfo.submittedAt, "kr")}
-
첨부파일: {selectedRequest.vendorInfo.hasAttachments ? "있음" : "없음"}
-
-
-
-
- - )} - - - - {/* SHI 첨부파일 */} - {selectedRequest.shiAttachments && selectedRequest.shiAttachments.length > 0 && ( - <> -
-

SHI 첨부파일 ({selectedRequest.shiAttachments.length}개)

-
-
- {selectedRequest.shiAttachments.map((attachment) => ( -
-
- - {attachment.originalFileName} - - ({Math.round((attachment.fileSize || 0) / 1024)}KB) - -
- -
- ))} -
-
-
- - )} - - {/* 추가 요청사항 */} - {selectedRequest.additionalRequests && ( - <> -
-

SHI 추가 요청사항

-
-

{selectedRequest.additionalRequests}

-
-
- - - )} -
- )} -
-
- ) +"use client" + +import * as React from "react" +import { format } from "date-fns" +import { ko } from "date-fns/locale" +import { FileText, Download } from "lucide-react" +import { toast } from "sonner" + +import { Button } from "@/components/ui/button" +import { Input } from "@/components/ui/input" +import { + Dialog, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle, +} from "@/components/ui/dialog" +import { Separator } from "@/components/ui/separator" +import { formatDate } from "../utils" + +interface SiteVisitRequest { + id: number + investigationId: number + requesterId: number | null + inspectionDuration: string | null + requestedStartDate: Date | null + requestedEndDate: Date | null + shiAttendees: Record | null + shiAttendeeDetails?: string | null + vendorRequests: Record | null + additionalRequests: string | null + status: string + sentAt: Date | null + createdAt: Date + updatedAt: Date + + // 실사정보 + investigationMethod: string | null // QM담당자가 작성한 실사방법 + investigationAddress: string | null + investigationNotes: string | null + forecastedAt: Date | null + actualAt: Date | null + result: string | null + resultNotes: string | null + + // PQ 정보 + pqItems: string | null | Array<{itemCode: string, itemName: string}> + + // 요청자 정보 + requesterName: string | null + requesterEmail: string | null + requesterTitle: string | null + + // QM 매니저 정보 + qmManagerName: string | null + qmManagerEmail: string | null + qmManagerTitle: string | null + + // 협력업체 정보 + vendorInfo?: { + id: number + country?: string + siteVisitRequestId: number + factoryName: string + factoryLocation: string + factoryAddress: string + factoryPicName: string + factoryPicPhone: string + factoryPicEmail: string + factoryDirections: string | null + accessProcedure: string | null + hasAttachments: boolean + otherInfo: string | null + submittedAt: Date + submittedBy: number + createdAt: Date + updatedAt: Date + } | null + + // SHI 첨부파일 + shiAttachments?: Array<{ + id: number + siteVisitRequestId: number + vendorSiteVisitInfoId: number | null + fileName: string + originalFileName: string + filePath: string + fileSize: number + mimeType: string + createdAt: Date + updatedAt: Date + }> | null +} + +interface SiteVisitDetailDialogProps { + isOpen: boolean + onOpenChange: (open: boolean) => void + selectedRequest: SiteVisitRequest | null +} + +export function SiteVisitDetailDialog({ + isOpen, + onOpenChange, + selectedRequest, +}: SiteVisitDetailDialogProps) { + const vendorCountry = (selectedRequest?.vendorInfo as any)?.country || "" + const isDomestic = vendorCountry === "KR" + + const [factoryLocation, setFactoryLocation] = React.useState( + selectedRequest?.vendorInfo?.factoryLocation || "" + ) + const [factoryAddress, setFactoryAddress] = React.useState( + selectedRequest?.vendorInfo?.factoryAddress || "" + ) + + React.useEffect(() => { + setFactoryLocation(selectedRequest?.vendorInfo?.factoryLocation || "") + setFactoryAddress(selectedRequest?.vendorInfo?.factoryAddress || "") + }, [selectedRequest?.vendorInfo?.factoryLocation, selectedRequest?.vendorInfo?.factoryAddress]) + + React.useEffect(() => { + const handleMessage = (event: MessageEvent) => { + if (!event.data || event.data.type !== "JUSO_SELECTED") return + const { roadAddrPart1, roadAddrPart2, addrDetail } = event.data.payload || {} + const combinedRoad = [roadAddrPart1, roadAddrPart2].filter(Boolean).join(" ").trim() + setFactoryLocation(combinedRoad || factoryLocation) + setFactoryAddress(addrDetail || factoryAddress) + } + window.addEventListener("message", handleMessage) + return () => window.removeEventListener("message", handleMessage) + }, [factoryLocation, factoryAddress]) + + const handleJusoSearch = () => { + window.open( + "/api/juso", + "jusoSearch", + "width=570,height=420,scrollbars=yes,resizable=yes" + ) + } + + return ( + + + + 방문실사 상세 정보 + + 작성한 방문실사 정보의 상세 내용입니다. + + + + {selectedRequest && ( +
+ {/* 기본 정보 */} + + {/* 협력업체 정보 */} + {selectedRequest.vendorInfo && ( + <> + +
+

작성한 협력업체 정보

+
+
+
+
+

공장 기본 정보

+
+
공장명: {selectedRequest.vendorInfo.factoryName}
+
+ 공장위치(도로명): + {isDomestic && ( + + )} +
+ setFactoryLocation(e.target.value)} + readOnly={!isDomestic} + className={!isDomestic ? "" : "bg-muted text-muted-foreground"} + placeholder="도로명 주소" + /> +
공장주소(상세):
+ setFactoryAddress(e.target.value)} + readOnly={!isDomestic} + className={!isDomestic ? "" : "bg-muted text-muted-foreground"} + placeholder="상세 주소" + /> +
+
+ +
+

공장 담당자 정보

+
+
이름: {selectedRequest.vendorInfo.factoryPicName}
+
전화번호: {selectedRequest.vendorInfo.factoryPicPhone}
+
이메일: {selectedRequest.vendorInfo.factoryPicEmail}
+
+
+
+ +
+ {selectedRequest.vendorInfo.factoryDirections && ( +
+

공장 가는 법

+
+

{selectedRequest.vendorInfo.factoryDirections}

+
+
+ )} + + {selectedRequest.vendorInfo.accessProcedure && ( +
+

공장 출입절차

+
+

{selectedRequest.vendorInfo.accessProcedure}

+
+
+ )} +
+
+ + {/* 기타 정보 */} + {selectedRequest.vendorInfo.otherInfo && ( +
+

기타 정보

+
+

{selectedRequest.vendorInfo.otherInfo}

+
+
+ )} + + {/* 제출 정보 */} +
+

제출 정보

+
+
제출일: {formatDate(selectedRequest.vendorInfo.submittedAt, "kr")}
+
첨부파일: {selectedRequest.vendorInfo.hasAttachments ? "있음" : "없음"}
+
+
+
+
+ + )} + + + + {/* SHI 첨부파일 */} + {selectedRequest.shiAttachments && selectedRequest.shiAttachments.length > 0 && ( + <> +
+

SHI 첨부파일 ({selectedRequest.shiAttachments.length}개)

+
+
+ {selectedRequest.shiAttachments.map((attachment) => ( +
+
+ + {attachment.originalFileName} + + ({Math.round((attachment.fileSize || 0) / 1024)}KB) + +
+ +
+ ))} +
+
+
+ + )} + + {/* 추가 요청사항 */} + {selectedRequest.additionalRequests && ( + <> +
+

SHI 추가 요청사항

+
+

{selectedRequest.additionalRequests}

+
+
+ + + )} +
+ )} +
+
+ ) } \ No newline at end of file -- cgit v1.2.3