From 089c70ffbe2303ab5e2611a152ddd3aed0e6e718 Mon Sep 17 00:00:00 2001 From: dujinkim Date: Mon, 1 Sep 2025 09:09:15 +0000 Subject: (최겸) 구매 pq, 기본정보 수정 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/vendor-basic-info/basic-info-client.tsx | 1650 +++++++++++++++++++++++++++ 1 file changed, 1650 insertions(+) create mode 100644 lib/vendor-basic-info/basic-info-client.tsx (limited to 'lib/vendor-basic-info/basic-info-client.tsx') diff --git a/lib/vendor-basic-info/basic-info-client.tsx b/lib/vendor-basic-info/basic-info-client.tsx new file mode 100644 index 00000000..ce8e4dfc --- /dev/null +++ b/lib/vendor-basic-info/basic-info-client.tsx @@ -0,0 +1,1650 @@ +"use client"; + +import React, { useState, useTransition } from "react"; +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { Separator } from "@/components/ui/separator"; +import { Checkbox } from "@/components/ui/checkbox"; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; +import { Edit, Save, X } from "lucide-react"; +import { toast } from "sonner"; +import { VendorData, VendorFormData, VendorAttachment } from "./types"; +import { updateVendorData, getVendorPQData, getVendorPQSubmissionData, getVendorAdditionalInfo } from "./actions"; +import { getVendorBusinessContacts } from "./actions"; +import { noDataString } from "./constants"; +import { PQSimpleDialog } from "@/components/vendor-info/pq-simple-dialog"; +import { SiteVisitDetailDialog } from "@/lib/site-visit/site-visit-detail-dialog"; +import { DocumentStatusDialog } from "@/components/vendor-regular-registrations/document-status-dialog"; +import { AdditionalInfoDialog } from "@/components/vendor-regular-registrations/additional-info-dialog"; +import { getSiteVisitRequestsByVendorId } from "@/lib/site-visit/service"; +import { fetchVendorRegistrationStatus } from "@/lib/vendor-regular-registrations/service"; +import { getVendorAttachmentsByType, getVendorPeriodicGrade, getVendorTypeInfo } from "@/lib/vendor-info/service"; +// downloadFile은 동적으로 import +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table"; + +interface BasicInfoClientProps { + initialData: VendorData | null; + vendorId: string; +} + +interface DropdownOption { + value: string; + label: string; +} + +interface InfoItemProps { + title: string; + value: string | boolean; + isEditable?: boolean; + editMode?: boolean; + onChange?: (value: string | boolean) => void; + fieldKey?: string; + type?: "text" | "checkbox" | "dropdown" | "file-button" | "readonly"; + options?: DropdownOption[]; // dropdown용 옵션들 + onFileButtonClick?: () => void; // 파일 버튼 클릭 핸들러 + placeholder?: string; // input placeholder +} + +const InfoItem = ({ + title, + value, + isEditable = false, + editMode = false, + onChange, + fieldKey, + type = "text", + options = [], + onFileButtonClick, + placeholder, +}: InfoItemProps) => { + // 편집 가능 여부 결정 (readonly 타입은 항상 읽기 전용) + const canEdit = isEditable && editMode && type !== "readonly"; + + // 표시할 값 결정 (빈 값일 때 처리) + const displayValue = value || ""; + const showNoData = !value && !canEdit; + + const renderEditableField = () => { + switch (type) { + case "checkbox": + return ( +
+ onChange?.(checked)} + /> + +
+ ); + + case "dropdown": + return ( + + ); + + case "file-button": + return ( + + ); + + case "text": + default: + return ( + onChange?.(e.target.value)} + className="h-8" + placeholder={placeholder} + /> + ); + } + }; + + const renderReadOnlyField = () => { + switch (type) { + case "checkbox": + return ( +
+ + +
+ ); + + case "file-button": + return ( + + ); + + case "dropdown": + case "text": + case "readonly": + default: + return showNoData ? noDataString : displayValue; + } + }; + + return ( +
+
{title}:
+
+ {canEdit ? ( +
+ + {renderEditableField()} +
+ ) : ( + {renderReadOnlyField()} + )} +
+
+ ); +}; + +const OrganizationChart = ({ + data, + editMode = false, + onChange, + pqData, +}: { + data: any; + editMode?: boolean; + onChange?: (field: string, value: string) => void; + pqData: any[]; +}) => { + const organizationFields = [ + { key: "representative", label: "대표", code: "1-5-1" }, + { key: "sales", label: "영업", code: "1-5-2" }, + { key: "design", label: "설계", code: "1-5-3" }, + { key: "procurement", label: "구매", code: "1-5-4" }, + { key: "production", label: "생산", code: "1-5-5" }, + { key: "quality", label: "품질", code: "1-5-6" }, + ]; + + return ( +
+
조직도
+
+ {organizationFields.map((field) => ( +
+
+ {field.label} +
+
+ {editMode ? ( + onChange?.(field.key, e.target.value)} + className="h-8 w-16 text-center" + placeholder="0" + /> + ) : ( + + {pqData && Array.isArray(pqData) && pqData.find((a: any) => a.criteriaCode === field.code)?.answer || data?.[field.key]?.toString() || noDataString} + + )} +
+
+ ))} +
+
+ ); +}; + +const InfoSection = ({ + title, + subtitle, + column1, + column2, + column3, + additionalContent, +}: { + title: string; + subtitle?: string; + column1: React.ReactNode; + column2: React.ReactNode; + column3: React.ReactNode; + additionalContent?: React.ReactNode; +}) => ( +
+
+
+
{title}
+ {subtitle && ( +
+ {subtitle} +
+ )} +
+
+
{column1}
+
{column2}
+
{column3}
+
+
+ {additionalContent && ( +
+
+
{additionalContent}
+
+ )} +
+); + +const WideInfoSection = ({ + title, + subtitle, + content, + noPadding = false, +}: { + title?: string; + subtitle?: string; + content: React.ReactNode; + noPadding?: boolean; +}) => ( +
+
+
+
{title}
+ {subtitle && ( +
+ {subtitle} +
+ )} +
+
+ {content} +
+
+
+); + +export default function BasicInfoClient({ + initialData, + vendorId, +}: BasicInfoClientProps) { + const [editMode, setEditMode] = useState(false); + const [isPending, startTransition] = useTransition(); + + // 다이얼로그 상태 + const [pqDialogOpen, setPqDialogOpen] = useState(false); + const [siteVisitDialogOpen, setSiteVisitDialogOpen] = useState(false); + const [contractDialogOpen, setContractDialogOpen] = useState(false); + const [additionalInfoDialogOpen, setAdditionalInfoDialogOpen] = useState(false); + + // 각 다이얼로그에 필요한 데이터 상태 + const [selectedSiteVisitRequest, setSelectedSiteVisitRequest] = useState(null); + const [registrationData, setRegistrationData] = useState(null); + + // 첨부파일 및 평가 정보 상태 + const [attachmentsByType, setAttachmentsByType] = useState>({}); + const [periodicGrade, setPeriodicGrade] = useState(null); + const [vendorTypeInfo, setVendorTypeInfo] = useState(null); + const [pqData, setPqData] = useState([]); + const [pqSubmissionData, setPqSubmissionData] = useState([]); + const [additionalInfo, setAdditionalInfo] = useState(null); + const [businessContacts, setBusinessContacts] = useState([]); + const [formData, setFormData] = useState({ + vendorName: initialData?.vendorName || "", + representativeName: initialData?.representativeName || "", + representativeWorkExperience: + initialData?.representativeWorkExperience || false, + representativeBirth: initialData?.representativeBirth || "", + representativePhone: initialData?.representativePhone || "", + representativeEmail: initialData?.representativeEmail || "", + phone: initialData?.phone || "", + fax: initialData?.fax || "", + email: initialData?.email || "", + address: initialData?.address || "", + addressDetail: initialData?.addressDetail || "", + postalCode: initialData?.postalCode || "", + businessSize: initialData?.businessSize || "", + country: initialData?.country || "", + website: initialData?.website || "", + businessType: initialData?.additionalInfo?.businessType || "", + employeeCount: initialData?.additionalInfo?.employeeCount || 0, + mainBusiness: initialData?.additionalInfo?.mainBusiness || "", + }); + + const handleSave = () => { + // startTransition(async () => { + // try { + // const result = await updateVendorData(vendorId, formData); + // if (result.success) { + // toast.success("[개발중] 저장되지 않습니다. 업데이트는 구현중입니다."); + // setEditMode(false); + // } else { + // toast.error(result.message || "저장에 실패했습니다."); + // } + // } catch { + // toast.error("저장 중 오류가 발생했습니다."); + // } + // }); + }; + + const handleCancel = () => { + setFormData({ + vendorName: initialData?.vendorName || "", + representativeName: initialData?.representativeName || "", + representativeWorkExperience: + initialData?.representativeWorkExperience || false, + representativeBirth: initialData?.representativeBirth || "", + representativePhone: initialData?.representativePhone || "", + representativeEmail: initialData?.representativeEmail || "", + phone: initialData?.phone || "", + fax: initialData?.fax || "", + email: initialData?.email || "", + address: initialData?.address || "", + addressDetail: initialData?.addressDetail || "", + postalCode: initialData?.postalCode || "", + businessSize: initialData?.businessSize || "", + country: initialData?.country || "", + website: initialData?.website || "", + businessType: initialData?.additionalInfo?.businessType || "", + employeeCount: initialData?.additionalInfo?.employeeCount || 0, + mainBusiness: initialData?.additionalInfo?.mainBusiness || "", + }); + setEditMode(false); + }; + + const updateField = ( + field: keyof VendorFormData, + value: string | number | boolean + ) => { + setFormData((prev) => ({ ...prev, [field]: value })); + }; + + // 기본계약 현황 조회 핸들러 + const handleContractView = async () => { + try { + const result = await fetchVendorRegistrationStatus(parseInt(vendorId)); + if (!result.success || !result.data) { + toast.info("기본계약 정보가 없습니다."); + return; + } + + // DocumentStatusDialog가 기대하는 형태로 데이터 구성 + const dialogData = { + // 기본 정보 + id: result.data.registration?.id || 0, + vendorId: parseInt(vendorId), + companyName: result.data.vendor.vendorName, + businessNumber: result.data.vendor.taxId, + representative: result.data.vendor.representativeName, + country: result.data.vendor.country, + status: result.data.registration?.status || "정보없음", + + // 문서 제출 현황 - documentSubmissions 속성으로 매핑 + documentSubmissions: result.data.documentStatus, + + // 문서별 파일 정보 추가 + documentFiles: result.data.documentFiles || { + businessRegistration: [], + creditEvaluation: [], + bankCopy: [], + auditResult: [] + }, + + // 기본계약 정보 + basicContracts: result.data.basicContracts || [], + + // 안전적격성 평가 + safetyQualificationContent: result.data.registration?.safetyQualificationContent || null, + + // 추가정보 완료 여부 + additionalInfo: result.data.additionalInfoCompleted, + }; + + setRegistrationData(dialogData); + setContractDialogOpen(true); + } catch (error) { + console.error("기본계약 정보 조회 오류:", error); + toast.error("기본계약 정보를 불러오는데 실패했습니다."); + } + }; + + // 첨부파일 및 평가 정보 로드 + const loadVendorData = async () => { + try { + // 첨부파일 조회 + const attachmentsResult = await getVendorAttachmentsByType(parseInt(vendorId)); + if (attachmentsResult.success && attachmentsResult.data) { + setAttachmentsByType(attachmentsResult.data); + } + + // 정기평가 등급 조회 + const gradeResult = await getVendorPeriodicGrade(parseInt(vendorId)); + if (gradeResult.success && gradeResult.data) { + setPeriodicGrade(gradeResult.data.finalGrade); + } + + // 벤더 타입 정보 조회 + const typeResult = await getVendorTypeInfo(parseInt(vendorId)); + if (typeResult.success && typeResult.data) { + setVendorTypeInfo(typeResult.data); + } + + // PQ 데이터 조회 + const pqResult = await getVendorPQData(vendorId); + if (pqResult) { + setPqData(pqResult); + } + + // PQ 제출 데이터 조회 + const pqSubmissionResult = await getVendorPQSubmissionData(vendorId); + if (pqSubmissionResult) { + setPqSubmissionData(pqSubmissionResult); + } + + // 추가정보 조회 + const additionalInfoResult = await getVendorAdditionalInfo(vendorId); + if (additionalInfoResult) { + setAdditionalInfo(additionalInfoResult); + } + + // 업무담당자 정보 조회 + const contacts = await getVendorBusinessContacts(vendorId); + setBusinessContacts(contacts || []); + } catch (error) { + console.error("벤더 데이터 로드 오류:", error); + } + }; + + // 컴포넌트 마운트 시 데이터 로드 + React.useEffect(() => { + if (vendorId) { + loadVendorData(); + } + }, [vendorId]); + + // 첨부파일 다운로드 핸들러 + const handleAttachmentDownload = async (filePath: string, fileName: string) => { + try { + // 동적으로 downloadFile 함수 import + const { downloadFile } = await import('@/lib/file-download') + + const result = await downloadFile(filePath, fileName); + if (result.success) { + toast.success(`${fileName} 파일이 다운로드되었습니다.`); + } else { + toast.error(result.error || "파일 다운로드에 실패했습니다."); + } + } catch (error) { + console.error("파일 다운로드 오류:", error); + toast.error("파일 다운로드에 실패했습니다."); + } + }; + + // PQ 데이터에서 실사 정보 추출 + const extractFactoryInfo = (pqData: any[]) => { + const factoryInfo = { + factoryAddress: "", + factoryPhone: "", + factoryFax: "", + factoryPIC: "", + factoryPICPosition: "", + factoryPICContact: "", + factoryPICEmail: "", + mainSupplyItems: "", + inspectionResult: "", + inspectionDate: "", + inspectionFiles: [] as any[] + }; + + if (!pqData || !Array.isArray(pqData)) { + return factoryInfo; + } + + pqData.forEach(group => { + if (group && group.items && Array.isArray(group.items)) { + group.items.forEach((item: any) => { + const code = item.code; + const answer = item.answer; + const files = item.uploadedFiles || []; + + // 공장주소 (1-4-1) + if (code === "1-4-1") { + factoryInfo.factoryAddress = answer || ""; + } + // 공장 전화 (1-4-2) + else if (code === "1-4-2") { + factoryInfo.factoryPhone = answer || ""; + } + // 공장 팩스 (1-4-3) + else if (code === "1-4-3") { + factoryInfo.factoryFax = answer || ""; + } + // 공장 대표/담당자 이름 (1-4-4) + else if (code === "1-4-4") { + factoryInfo.factoryPIC = answer || ""; + } + // 공장 대표/담당자 직책 (1-4-5) + else if (code === "1-4-5") { + factoryInfo.factoryPICPosition = answer || ""; + } + // 공장 대표/담당자 전화 (1-4-6) + else if (code === "1-4-6") { + factoryInfo.factoryPICContact = answer || ""; + } + // 공장 대표/담당자 이메일 (1-4-7) + else if (code === "1-4-7") { + factoryInfo.factoryPICEmail = answer || ""; + } + // 공급품목 (첫 번째 것만 가져오기) + else if (code.startsWith("1-5") && !factoryInfo.mainSupplyItems) { + try { + const supplyItems = JSON.parse(answer || "[]"); + if (Array.isArray(supplyItems) && supplyItems.length > 0) { + factoryInfo.mainSupplyItems = supplyItems[0].name || supplyItems[0] || ""; + } + } catch { + factoryInfo.mainSupplyItems = answer || ""; + } + } + // 실사 결과 + else if (code.startsWith("4-") && answer && !factoryInfo.inspectionResult) { + factoryInfo.inspectionResult = answer; + factoryInfo.inspectionFiles = files; + } + }); + } + }); + + return factoryInfo; + }; + + // PQ 제출 데이터에서 특정 코드의 답변 가져오기 + const getPQAnswerByCode = (targetCode: string) => { + if (!pqSubmissionData || !Array.isArray(pqSubmissionData)) { + return ""; + } + + for (const submission of pqSubmissionData) { + if (submission && submission.answers && Array.isArray(submission.answers)) { + const answer = submission.answers.find((a: any) => a.criteriaCode === targetCode); + if (answer) { + return answer.answer; + } + } + } + return ""; + }; + + // PQ 제출 데이터에서 특정 코드의 첨부파일 가져오기 + const getPQAttachmentsByCode = (targetCode: string) => { + const files: any[] = []; + + if (!pqSubmissionData || !Array.isArray(pqSubmissionData)) { + return files; + } + + for (const submission of pqSubmissionData) { + if (submission && submission.answers && Array.isArray(submission.answers)) { + const answer = submission.answers.find((a: any) => a.criteriaCode === targetCode); + if (answer && answer.uploadedFiles) { + files.push(...answer.uploadedFiles); + } + } + } + + return files; + }; + + // 첨부파일 관리 핸들러 (타입별) + const handleAttachmentFileManagement = (attachmentType: string, typeName: string) => { + const files = attachmentsByType[attachmentType] || []; + + if (files.length === 0) { + toast.info(`${typeName} 파일이 없습니다.`); + return; + } + + // 파일이 하나인 경우 바로 다운로드 + if (files.length === 1) { + handleAttachmentDownload(files[0].filePath, files[0].fileName); + return; + } + + // 파일이 여러 개인 경우 순차적으로 모든 파일 다운로드 + toast.info(`${typeName} 파일 ${files.length}개를 다운로드합니다.`); + files.forEach((file, index) => { + setTimeout(() => { + handleAttachmentDownload(file.filePath, file.fileName); + }, index * 500); // 500ms 간격으로 순차 다운로드 + }); + }; + + if (!initialData) { + return ( +
+
+

{noDataString}

+
+
+ ); + } + + // attachmentsByType는 상태로 관리되고 있으므로 제거 + + return ( +
+
+

협력업체 기본정보

+
+ {editMode ? ( + <> + + + + ) : ( + <> + + + + )} +
+
+ +
+ {/* 업체정보 */} + + updateField("vendorName", value)} + /> + {/* */} + updateField("phone", value)} + /> + {/* updateField("fax", value)} + /> */} + updateField("businessType", value)} + /> + {/* handleFileManagement("소개자료")} + /> */} + +
+ } + column2={ +
+ + + + + + updateField("email", value)} + /> + {/* + updateField("businessSize", value)} + placeholder="기업규모를 선택하세요" + /> */} + + {/* */} +
+ } + column3={ +
+ + {/* */} + updateField("country", value)} + /> + + {/* */} + + {/* */} +
+ } + /> + + {/* 첨부파일 */} + + {/* 사업자등록증 */} +
+
사업자등록증
+
+
+ {attachmentsByType.BUSINESS_REGISTRATION?.length || 0}건 +
+ {attachmentsByType.BUSINESS_REGISTRATION?.length > 0 && ( + + )} +
+
+ + {/* 신용평가보고서 */} +
+
신용평가보고서
+
+
+ {attachmentsByType.CREDIT_REPORT?.length || 0}건 +
+ {attachmentsByType.CREDIT_REPORT?.length > 0 && ( + + )} +
+
+ + {/* 통장사본 */} +
+
통장사본
+
+
+ {attachmentsByType.BANK_ACCOUNT_COPY?.length || 0}건 +
+ {attachmentsByType.BANK_ACCOUNT_COPY?.length > 0 && ( + + )} +
+
+ + {/* ISO 인증서 */} +
+
ISO 인증서
+
+
+ {attachmentsByType.ISO_CERTIFICATION?.length || 0}건 +
+ {attachmentsByType.ISO_CERTIFICATION?.length > 0 && ( + + )} +
+
+ + {/* 기타 첨부파일 (GENERAL) */} +
+
기타 첨부파일
+
+
+ {attachmentsByType.GENERAL?.length || 0}건 +
+ {attachmentsByType.GENERAL?.length > 0 && ( + + )} +
+
+
+ } + /> + + + {/* 상세정보 */} + + updateField("representativeName", value)} + /> + + updateField("representativeWorkExperience", value) + } + /> + updateField("representativeBirth", value)} + /> + + + } + column2={ +
+ updateField("representativePhone", value)} + /> + updateField("address", value)} + /> + +
+ } + column3={ +
+ updateField("representativeEmail", value)} + /> + +
+ } + additionalContent={ +
+ s.answers || []) : []} + onChange={(field, value) => { + // TODO: 조직도 업데이트 로직 구현 + }} + /> +
+
+ 관련 첨부파일 +
+
+ + + +
+
+
+ } + /> + + {/* */} + + {/* 매출정보 */} + + + + + 기준일 + + + 자산 구성 + + + 영업이익 +
+ (백만원) +
+ + 당기순이익 +
+ (백만원) +
+ + 부채비율 +
+ (%) +
+ + 차입금의존도 +
+ (%) +
+ + 영업이익률 +
+ (%) +
+ + 순이익률 +
+ (%) +
+ + 매출액증감 +
+ (%) +
+ + 유동비율 +
+ (%) +
+
+ + 총자산 + + 부채총계 + + + 자본총계 + + +
+ + {["20231231", "20221231", "20211231"].map((dateKey) => { + const year = dateKey; + const salesData = initialData.salesInfo?.[year]; + const metricsData = initialData.calculatedMetrics?.[dateKey]; + + return ( + + + {year} + + + {salesData + ? ( + parseInt(salesData.totalDebt.replace(/,/g, "")) + + parseInt(salesData.totalEquity.replace(/,/g, "")) + ).toLocaleString() + : "-"} + + + {salesData?.totalDebt || "-"} + + + {salesData?.totalEquity || "-"} + + + {salesData?.operatingProfit || "-"} + + + {salesData?.netIncome || "-"} + + + {metricsData?.debtRatio?.toFixed(1) || "-"} + + + {metricsData?.borrowingDependency?.toFixed(1) || "-"} + + + {metricsData?.operatingMargin?.toFixed(1) || "-"} + + + {metricsData?.netMargin?.toFixed(1) || "-"} + + + {metricsData?.salesGrowth?.toFixed(1) || "-"} + + + {metricsData?.currentRatio?.toFixed(1) || "-"} + + + ); + })} + + + } + /> + + {/* */} + + {/* 실사정보 */} + {pqSubmissionData && pqSubmissionData.length > 0 && pqSubmissionData.map((submission, index) => { + const factoryInfo = extractFactoryInfo([{ + groupName: "Factory Info", + items: submission.answers.map((answer: any) => ({ + code: answer.criteriaCode, + answer: answer.answer, + uploadedFiles: answer.uploadedFiles || [] + })) + }]); + const inspectionFiles = getPQAttachmentsByCode("4-1"); + + return ( + + + + + + } + column2={ +
+ + + {inspectionFiles.length > 0 && ( + + )} +
+ } + column3={ +
+
+ +
+
+ } + additionalContent={ +
+
+
+ 공장소개자료 +
+
+ {getPQAttachmentsByCode("1-4").length}건 +
+ {getPQAttachmentsByCode("1-4").length > 0 && ( + + )} +
+
+
+ QMS Cert +
+
+ {getPQAttachmentsByCode("2-1").length}건 +
+ {getPQAttachmentsByCode("2-1").length > 0 && ( + + )} +
+
+
+ Product Cert +
+
+ {getPQAttachmentsByCode("2-2").length}건 +
+ {getPQAttachmentsByCode("2-2").length > 0 && ( + + )} +
+
+
+ Ex. Cert +
+
+ {getPQAttachmentsByCode("2-17").length}건 +
+ {getPQAttachmentsByCode("2-17").length > 0 && ( + + )} +
+
+
+ HSE Cert +
+
+ {getPQAttachmentsByCode("3-1").length}건 +
+ {getPQAttachmentsByCode("3-1").length > 0 && ( + + )} +
+
+ } + /> + ); + })} + {/* 추가정보 */} + + + + + + } + column2={ +
+ + + +
+ } + column3={ +
+ {/* 추가 정보가 더 있다면 여기에 배치 */} +
+ } + /> + {/* 업무담당자 */} + +
+
영업 담당자
+ c.contactType === "sales")?.contactName || ""} type="readonly" /> + c.contactType === "sales")?.position || ""} type="readonly" /> + c.contactType === "sales")?.department || ""} type="readonly" /> + c.contactType === "sales")?.responsibility || ""} type="readonly" /> + c.contactType === "sales")?.email || ""} type="readonly" /> +
+ + } + column2={ +
+
+
설계 담당자
+ c.contactType === "design")?.contactName || ""} type="readonly" /> + c.contactType === "design")?.position || ""} type="readonly" /> + c.contactType === "design")?.department || ""} type="readonly" /> + c.contactType === "design")?.responsibility || ""} type="readonly" /> + c.contactType === "design")?.email || ""} type="readonly" /> +
+
+
납기 담당자
+ c.contactType === "delivery")?.contactName || ""} type="readonly" /> + c.contactType === "delivery")?.position || ""} type="readonly" /> + c.contactType === "delivery")?.department || ""} type="readonly" /> + c.contactType === "delivery")?.responsibility || ""} type="readonly" /> + c.contactType === "delivery")?.email || ""} type="readonly" /> +
+
+ } + column3={ +
+
+
품질 담당자
+ c.contactType === "quality")?.contactName || ""} type="readonly" /> + c.contactType === "quality")?.position || ""} type="readonly" /> + c.contactType === "quality")?.department || ""} type="readonly" /> + c.contactType === "quality")?.responsibility || ""} type="readonly" /> + c.contactType === "quality")?.email || ""} type="readonly" /> +
+
+
세금계산서 담당자
+ c.contactType === "tax_invoice")?.contactName || ""} type="readonly" /> + c.contactType === "tax_invoice")?.position || ""} type="readonly" /> + c.contactType === "tax_invoice")?.department || ""} type="readonly" /> + c.contactType === "tax_invoice")?.responsibility || ""} type="readonly" /> + c.contactType === "tax_invoice")?.email || ""} type="readonly" /> +
+
+ } + /> + + + + + ); +} -- cgit v1.2.3