summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authordujinkim <dujin.kim@dtsolution.co.kr>2025-09-01 09:09:15 +0000
committerdujinkim <dujin.kim@dtsolution.co.kr>2025-09-01 09:09:15 +0000
commit089c70ffbe2303ab5e2611a152ddd3aed0e6e718 (patch)
tree1ce91012dba99495dde5eb8b414b2732197bfec4 /app
parent69648a25c2ac62bbc3354b3a0e41abc932273b7c (diff)
(최겸) 구매 pq, 기본정보 수정
Diffstat (limited to 'app')
-rw-r--r--app/[lng]/evcp/(evcp)/vendors/[id]/info/basic/actions.ts44
-rw-r--r--app/[lng]/evcp/(evcp)/vendors/[id]/info/basic/basic-info-client.tsx1458
-rw-r--r--app/[lng]/evcp/(evcp)/vendors/[id]/info/basic/constants.ts1
-rw-r--r--app/[lng]/evcp/(evcp)/vendors/[id]/info/basic/page.tsx4
-rw-r--r--app/[lng]/evcp/(evcp)/vendors/[id]/info/basic/types.ts180
-rw-r--r--app/[lng]/partners/(partners)/sales-force-test/page.tsx32
-rw-r--r--app/[lng]/partners/pq_new/[id]/page.tsx2
7 files changed, 3 insertions, 1718 deletions
diff --git a/app/[lng]/evcp/(evcp)/vendors/[id]/info/basic/actions.ts b/app/[lng]/evcp/(evcp)/vendors/[id]/info/basic/actions.ts
deleted file mode 100644
index 866103a6..00000000
--- a/app/[lng]/evcp/(evcp)/vendors/[id]/info/basic/actions.ts
+++ /dev/null
@@ -1,44 +0,0 @@
-"use server";
-
-import { getVendorBasicInfo } from "@/lib/vendors/service";
-import { VendorFormData } from "./types";
-
-/**
- * 벤더 기본정보를 가져오는 서버 액션
- */
-export async function getVendorData(vendorId: string) {
- try {
- const id = parseInt(vendorId);
- if (isNaN(id)) {
- return null;
- }
-
- const vendorData = await getVendorBasicInfo(id);
- return vendorData;
- } catch (error) {
- console.error("Error in getVendorData:", error);
- return null;
- }
-}
-
-/**
- * 벤더 기본정보를 업데이트하는 서버 액션 (향후 구현)
- */
-export async function updateVendorData(vendorId: string, formData: VendorFormData) {
- try {
- // TODO: 실제 업데이트 로직 구현
- console.log("Updating vendor data:", { vendorId, formData });
-
- // 임시로 성공 응답 반환
- return {
- success: true,
- message: "(개발중입니다) 벤더 정보가 성공적으로 업데이트되었습니다.",
- };
- } catch (error) {
- console.error("Error in updateVendorData:", error);
- return {
- success: false,
- message: "업데이트 중 오류가 발생했습니다.",
- };
- }
-} \ No newline at end of file
diff --git a/app/[lng]/evcp/(evcp)/vendors/[id]/info/basic/basic-info-client.tsx b/app/[lng]/evcp/(evcp)/vendors/[id]/info/basic/basic-info-client.tsx
deleted file mode 100644
index 78d21719..00000000
--- a/app/[lng]/evcp/(evcp)/vendors/[id]/info/basic/basic-info-client.tsx
+++ /dev/null
@@ -1,1458 +0,0 @@
-"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 {
- 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 } 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 (
- <div className="flex items-center space-x-2">
- <Checkbox
- id={fieldKey}
- checked={value as boolean}
- onCheckedChange={(checked) => onChange?.(checked)}
- />
- <Label
- htmlFor={fieldKey}
- className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
- >
- {value ? "있음" : "없음"}
- </Label>
- </div>
- );
-
- case "dropdown":
- return (
- <Select
- value={displayValue as string}
- onValueChange={(val) => onChange?.(val)}
- >
- <SelectTrigger className="h-8">
- <SelectValue placeholder={placeholder || "선택하세요"} />
- </SelectTrigger>
- <SelectContent>
- {options.map((option) => (
- <SelectItem key={option.value} value={option.value}>
- {option.label}
- </SelectItem>
- ))}
- </SelectContent>
- </Select>
- );
-
- case "file-button":
- return (
- <Button
- type="button"
- variant="outline"
- className="h-8 text-xs"
- onClick={onFileButtonClick}
- >
- {displayValue || "파일 관리"}
- </Button>
- );
-
- case "text":
- default:
- return (
- <Input
- id={fieldKey}
- value={displayValue as string}
- onChange={(e) => onChange?.(e.target.value)}
- className="h-8"
- placeholder={placeholder}
- />
- );
- }
- };
-
- const renderReadOnlyField = () => {
- switch (type) {
- case "checkbox":
- return (
- <div className="flex items-center space-x-2">
- <Checkbox
- id={`readonly-${fieldKey}`}
- checked={value as boolean}
- disabled={true}
- />
- <Label
- htmlFor={`readonly-${fieldKey}`}
- className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
- >
- {value ? "있음" : "없음"}
- </Label>
- </div>
- );
-
- case "file-button":
- return (
- <Button
- type="button"
- variant="ghost"
- className="h-auto p-0 text-xs text-left justify-start"
- onClick={onFileButtonClick}
- disabled={!onFileButtonClick}
- >
- {displayValue || noDataString}
- </Button>
- );
-
- case "dropdown":
- case "text":
- case "readonly":
- default:
- return showNoData ? noDataString : displayValue;
- }
- };
-
- return (
- <div className="grid grid-cols-2 gap-2 py-1 min-w-0">
- <div className="text-sm text-muted-foreground break-words">{title}:</div>
- <div className="text-sm font-medium space-y-1 break-words overflow-hidden min-w-0">
- {canEdit ? (
- <div className="space-y-1">
- <Label htmlFor={fieldKey} className="sr-only">
- {title}
- </Label>
- {renderEditableField()}
- </div>
- ) : (
- <span>{renderReadOnlyField()}</span>
- )}
- </div>
- </div>
- );
-};
-
-const OrganizationChart = ({
- data,
- editMode = false,
- onChange,
-}: {
- data: any;
- editMode?: boolean;
- onChange?: (field: string, value: string) => void;
-}) => {
- const organizationFields = [
- { key: "representative", label: "대표" },
- { key: "sales", label: "영업" },
- { key: "design", label: "설계" },
- { key: "procurement", label: "구매" },
- { key: "production", label: "생산" },
- { key: "quality", label: "품질" },
- ];
-
- return (
- <div className="space-y-4">
- <div className="text-sm font-semibold text-center">조직도</div>
- <div className="grid grid-cols-3 gap-4">
- {organizationFields.map((field) => (
- <div key={field.key} className="flex flex-col items-center space-y-2">
- <div className="text-sm font-medium text-center whitespace-nowrap">
- {field.label}
- </div>
- <div className="text-center">
- {editMode ? (
- <Input
- value={data?.[field.key]?.toString() || ""}
- onChange={(e) => onChange?.(field.key, e.target.value)}
- className="h-8 w-16 text-center"
- placeholder="0"
- />
- ) : (
- <span className="text-sm text-muted-foreground">
- {data?.[field.key]?.toString() || noDataString}
- </span>
- )}
- </div>
- </div>
- ))}
- </div>
- </div>
- );
-};
-
-const InfoSection = ({
- title,
- subtitle,
- column1,
- column2,
- column3,
- additionalContent,
-}: {
- title: string;
- subtitle?: string;
- column1: React.ReactNode;
- column2: React.ReactNode;
- column3: React.ReactNode;
- additionalContent?: React.ReactNode;
-}) => (
- <div className="border">
- <div className="flex">
- <div className="w-32 bg-muted p-4 border-r flex flex-col">
- <div className="text-sm font-semibold text-center w-full">{title}</div>
- {subtitle && (
- <div className="text-sm text-muted-foreground text-center w-full mt-1">
- {subtitle}
- </div>
- )}
- </div>
- <div className="flex-1 grid grid-cols-3 min-w-0">
- <div className="p-4 border-r min-w-0 overflow-hidden">{column1}</div>
- <div className="p-4 border-r min-w-0 overflow-hidden">{column2}</div>
- <div className="p-4 min-w-0 overflow-hidden">{column3}</div>
- </div>
- </div>
- {additionalContent && (
- <div className="flex">
- <div className="w-32 bg-muted border-r"></div>
- <div className="flex-1 p-4 border-t">{additionalContent}</div>
- </div>
- )}
- </div>
-);
-
-const WideInfoSection = ({
- title,
- subtitle,
- content,
- noPadding = false,
-}: {
- title?: string;
- subtitle?: string;
- content: React.ReactNode;
- noPadding?: boolean;
-}) => (
- <div className="border">
- <div className="flex">
- <div className="w-32 bg-muted p-4 border-r flex flex-col">
- <div className="text-sm font-semibold text-center w-full">{title}</div>
- {subtitle && (
- <div className="text-sm text-muted-foreground text-center w-full mt-1">
- {subtitle}
- </div>
- )}
- </div>
- <div className={`flex-1 min-w-0 overflow-x-auto ${noPadding ? '' : 'p-4'}`}>
- {content}
- </div>
- </div>
- </div>
-);
-
-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<any>(null);
- const [registrationData, setRegistrationData] = useState<any>(null);
-
- // 첨부파일 및 평가 정보 상태
- const [attachmentsByType, setAttachmentsByType] = useState<Record<string, any[]>>({});
- const [periodicGrade, setPeriodicGrade] = useState<string | null>(null);
- const [vendorTypeInfo, setVendorTypeInfo] = useState<any>(null);
- const [formData, setFormData] = useState<VendorFormData>({
- 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 }));
- };
-
- // PQ 조회 핸들러
- const handlePQView = () => {
- setPqDialogOpen(true);
- };
-
- // 실사 정보 조회 핸들러
- const handleSiteVisitView = async () => {
- try {
- const siteVisitRequests = await getSiteVisitRequestsByVendorId(parseInt(vendorId));
- if (siteVisitRequests.length === 0) {
- toast.info("실사 정보가 없습니다.");
- return;
- }
- setSelectedSiteVisitRequest(siteVisitRequests[0]); // 첫 번째 실사 정보 선택
- setSiteVisitDialogOpen(true);
- } catch (error) {
- console.error("실사 정보 조회 오류:", error);
- toast.error("실사 정보를 불러오는데 실패했습니다.");
- }
- };
-
- // 기본계약 현황 조회 핸들러
- 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 handleAdditionalInfoView = async () => {
- try {
- const result = await fetchVendorRegistrationStatus(parseInt(vendorId));
- if (!result.success || !result.data) {
- toast.info("추가정보가 없습니다.");
- return;
- }
-
- // 추가정보가 있는지 확인 (업무담당자 또는 추가정보 데이터가 있는지 체크)
- const { businessContacts, additionalInfo } = result.data;
- const hasBusinessContacts = businessContacts && businessContacts.length > 0;
- const hasAdditionalInfo = additionalInfo && Object.keys(additionalInfo).length > 0;
-
- if (!hasBusinessContacts && !hasAdditionalInfo) {
- toast.info("추가정보가 없습니다.");
- return;
- }
-
- setAdditionalInfoDialogOpen(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);
- }
- } 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("파일 다운로드에 실패했습니다.");
- }
- };
-
- // 첨부파일 관리 핸들러 (타입별)
- 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 (
- <div className="p-6 bg-background max-w-full">
- <div className="text-center py-8">
- <p className="text-muted-foreground">{noDataString}</p>
- </div>
- </div>
- );
- }
-
- // attachmentsByType는 상태로 관리되고 있으므로 제거
-
- return (
- <div className="p-6 bg-background w-full overflow-x-auto">
- <div className="mb-6 flex justify-between items-center">
- <h2 className="text-xl font-bold">협력업체 기본정보</h2>
- <div className="flex gap-2">
- {editMode ? (
- <>
- <Button
- onClick={handleSave}
- disabled={isPending}
- className="flex items-center gap-1"
- >
- <Save className="w-4 h-4" />
- 저장
- </Button>
- <Button
- variant="outline"
- onClick={handleCancel}
- disabled={isPending}
- className="flex items-center gap-1"
- >
- <X className="w-4 h-4" />
- 취소
- </Button>
- </>
- ) : (
- <Button
- onClick={() => setEditMode(true)}
- className="flex items-center gap-1"
- >
- <Edit className="w-4 h-4" />
- 수정
- </Button>
- )}
- </div>
- </div>
-
- <div className="space-y-4">
- {/* 업체정보 */}
- <InfoSection
- title="업체정보"
- column1={
- <div className="space-y-2">
- <InfoItem
- title="업체명"
- value={formData.vendorName}
- isEditable={true}
- editMode={editMode}
- fieldKey="vendorName"
- onChange={(value) => updateField("vendorName", value)}
- />
- {/* <InfoItem
- title="설립일"
- // 현재 필드 없고 linter error 나도 무시. createdAt은 데이터베이스 생성시점이므로 잘못된 필드.
- value={initialData.establishmentDate}
- type="readonly"
- /> */}
- <InfoItem
- title="대표전화"
- value={formData.phone}
- isEditable={true}
- editMode={editMode}
- fieldKey="phone"
- onChange={(value) => updateField("phone", value)}
- />
- {/* <InfoItem
- title="팩스"
- value={formData.fax}
- isEditable={true}
- editMode={editMode}
- fieldKey="fax"
- onChange={(value) => updateField("fax", value)}
- /> */}
- <InfoItem
- title="업체유형"
- value={formData.businessType}
- isEditable={true}
- editMode={editMode}
- fieldKey="businessType"
- onChange={(value) => updateField("businessType", value)}
- />
- {/* <InfoItem
- title="소개자료"
- value={`회사: ${
- attachmentsByType.COMPANY_INTRO?.length || 0
- }건 / 제품: ${attachmentsByType.PRODUCT_INTRO?.length || 0}건`}
- isEditable={true}
- editMode={editMode}
- type="file-button"
- onFileButtonClick={() => handleFileManagement("소개자료")}
- /> */}
- <InfoItem
- title="정기평가 등급"
- value={periodicGrade || ""}
- type="readonly"
- />
- </div>
- }
- column2={
- <div className="space-y-2">
- <InfoItem
- title="사업자번호"
- value={initialData.taxId}
- type="readonly"
- />
- <InfoItem
- title="법인등록번호"
- value={initialData.corporateRegistrationNumber}
- type="readonly"
- />
- <InfoItem
- title="회사주소"
- value={initialData.address || ""}
- type="readonly"
- />
- <InfoItem
- title="상세주소"
- value={initialData.addressDetail || ""}
- type="readonly"
- />
- <InfoItem
- title="우편번호"
- value={initialData.postalCode || ""}
- type="readonly"
- />
- <InfoItem
- title="E-mail"
- value={formData.email}
- isEditable={true}
- editMode={editMode}
- fieldKey="email"
- onChange={(value) => updateField("email", value)}
- />
- {/* <InfoItem
- title="사업유형"
- value={formData.businessType}
- isEditable={true}
- />
- <InfoItem
- title="기업규모"
- value={formData.businessSize}
- isEditable={true}
- editMode={editMode}
- fieldKey="businessSize"
- type="dropdown"
- options={[
- { value: "A", label: "대기업 (A)" },
- { value: "B", label: "중견기업 (B)" },
- { value: "C", label: "중소기업 (C)" },
- { value: "D", label: "소상공인 (D)" },
- ]}
- onChange={(value) => updateField("businessSize", value)}
- placeholder="기업규모를 선택하세요"
- /> */}
-
- {/* <InfoItem
- title="안전적격성평가"
- value={
- initialData.evaluationInfo?.safetyQualificationEvaluation ||
- null
- }
- type="readonly"
- /> */}
- </div>
- }
- column3={
- <div className="space-y-2">
- <InfoItem
- title="업체분류"
- value={vendorTypeInfo?.vendorTypeName || ""}
- type="readonly"
- />
- {/* <InfoItem
- title="그룹사"
- value={initialData.classificationInfo?.groupCompany || null}
- isEditable={true}
- /> */}
- <InfoItem
- title="국가"
- value={formData.country}
- isEditable={true}
- editMode={editMode}
- fieldKey="country"
- onChange={(value) => updateField("country", value)}
- />
- <InfoItem
- title="선호언어"
- value={
- initialData.classificationInfo?.preferredLanguage || ""
- }
- isEditable={true}
- />
- {/* <InfoItem
- title="산업유형"
- value={initialData.classificationInfo?.industryType || ""}
- isEditable={true}
- /> */}
-
- {/* <InfoItem
- title="당사거래비중"
- value={
- initialData.evaluationInfo?.companyTransactionRatio || ""
- }
- type="readonly"
- /> */}
- </div>
- }
- />
-
- <Separator />
-
- {/* 첨부파일 */}
- <WideInfoSection
- title="첨부파일"
- content={
- <div className="grid grid-cols-2 md:grid-cols-5 gap-4 p-4">
- {/* 사업자등록증 */}
- <div className="flex flex-col items-center gap-3">
- <div className="text-sm font-medium text-center">사업자등록증</div>
- <div className="text-center">
- <div className="text-lg font-semibold text-primary">
- {attachmentsByType.BUSINESS_REGISTRATION?.length || 0}건
- </div>
- {attachmentsByType.BUSINESS_REGISTRATION?.length > 0 && (
- <Button
- variant="outline"
- size="sm"
- className="mt-2"
- onClick={() => handleAttachmentFileManagement("BUSINESS_REGISTRATION", "사업자등록증")}
- >
- 파일 보기
- </Button>
- )}
- </div>
- </div>
-
- {/* 신용평가보고서 */}
- <div className="flex flex-col items-center gap-3">
- <div className="text-sm font-medium text-center">신용평가보고서</div>
- <div className="text-center">
- <div className="text-lg font-semibold text-primary">
- {attachmentsByType.CREDIT_REPORT?.length || 0}건
- </div>
- {attachmentsByType.CREDIT_REPORT?.length > 0 && (
- <Button
- variant="outline"
- size="sm"
- className="mt-2"
- onClick={() => handleAttachmentFileManagement("CREDIT_REPORT", "신용평가보고서")}
- >
- 파일 보기
- </Button>
- )}
- </div>
- </div>
-
- {/* 통장사본 */}
- <div className="flex flex-col items-center gap-3">
- <div className="text-sm font-medium text-center">통장사본</div>
- <div className="text-center">
- <div className="text-lg font-semibold text-primary">
- {attachmentsByType.BANK_ACCOUNT_COPY?.length || 0}건
- </div>
- {attachmentsByType.BANK_ACCOUNT_COPY?.length > 0 && (
- <Button
- variant="outline"
- size="sm"
- className="mt-2"
- onClick={() => handleAttachmentFileManagement("BANK_ACCOUNT_COPY", "통장사본")}
- >
- 파일 보기
- </Button>
- )}
- </div>
- </div>
-
- {/* ISO 인증서 */}
- <div className="flex flex-col items-center gap-3">
- <div className="text-sm font-medium text-center">ISO 인증서</div>
- <div className="text-center">
- <div className="text-lg font-semibold text-primary">
- {attachmentsByType.ISO_CERTIFICATION?.length || 0}건
- </div>
- {attachmentsByType.ISO_CERTIFICATION?.length > 0 && (
- <Button
- variant="outline"
- size="sm"
- className="mt-2"
- onClick={() => handleAttachmentFileManagement("ISO_CERTIFICATION", "ISO 인증서")}
- >
- 파일 보기
- </Button>
- )}
- </div>
- </div>
-
- {/* 기타 첨부파일 (GENERAL) */}
- <div className="flex flex-col items-center gap-3">
- <div className="text-sm font-medium text-center">기타 첨부파일</div>
- <div className="text-center">
- <div className="text-lg font-semibold text-primary">
- {attachmentsByType.GENERAL?.length || 0}건
- </div>
- {attachmentsByType.GENERAL?.length > 0 && (
- <Button
- variant="outline"
- size="sm"
- className="mt-2"
- onClick={() => handleAttachmentFileManagement("GENERAL", "기타 첨부파일")}
- >
- 파일 보기
- </Button>
- )}
- </div>
- </div>
- </div>
- }
- />
-
- <Separator />
-
- {/* 상세정보 */}
- {/* <InfoSection
- title="상세정보"
- column1={
- <div className="space-y-2">
- <InfoItem
- title="대표자명"
- value={formData.representativeName}
- isEditable={true}
- editMode={editMode}
- fieldKey="representativeName"
- onChange={(value) => updateField("representativeName", value)}
- />
- <InfoItem
- title="대표자 당사근무경험"
- value={formData.representativeWorkExperience}
- isEditable={true}
- editMode={editMode}
- fieldKey="representativeWorkExperience"
- type="checkbox"
- onChange={(value) =>
- updateField("representativeWorkExperience", value)
- }
- />
- <InfoItem
- title="대표자 생년월일"
- value={formData.representativeBirth || null}
- isEditable={true}
- />
- <InfoItem
- title="임직원수"
- value={formData.employeeCount.toString() || null}
- isEditable={true}
- />
- </div>
- }
- column2={
- <div className="space-y-2">
- <InfoItem
- title="대표자Tel"
- value={formData.representativePhone}
- isEditable={true}
- editMode={editMode}
- fieldKey="representativePhone"
- onChange={(value) => updateField("representativePhone", value)}
- />
- <InfoItem
- title="대표자 주소"
- value={formData.address || null}
- isEditable={true}
- />
- <InfoItem
- title="연간 매출"
- value={initialData.capacityInfo?.annualSales || null}
- isEditable={true}
- />
- </div>
- }
- column3={
- <div className="space-y-2">
- <InfoItem
- title="대표자 E-mail"
- value={formData.representativeEmail}
- isEditable={true}
- editMode={editMode}
- fieldKey="representativeEmail"
- onChange={(value) => updateField("representativeEmail", value)}
- />
- <InfoItem
- title="생산능력"
- value={initialData.capacityInfo?.productionCapacity || null}
- isEditable={true}
- />
- </div>
- }
- additionalContent={
- <div className="grid grid-cols-2 gap-8 py-4 min-w-0 overflow-x-auto">
- <OrganizationChart
- data={initialData.organization}
- editMode={editMode}
- onChange={(field, value) => {
- // TODO: 조직도 업데이트 로직 구현
- toast.info(
- `[개발중] 조직도 ${field} 필드 업데이트 기능을 구현 예정입니다.`
- );
- }}
- />
- <div className="flex flex-col items-center gap-3">
- <div className="text-sm font-semibold text-center">
- 관련 정보
- </div>
- <div className="space-y-2">
- <Button
- variant="outline"
- className="text-xs w-32 flex items-center gap-2"
- onClick={() => handleFileManagement("협력업체정보")}
- >
- 협력업체정보
- </Button>
- <Button
- variant="outline"
- className="text-xs w-32 flex items-center gap-2"
- onClick={() => handleFileManagement("외주화정보")}
- >
- 외주화정보
- </Button>
- <Button
- variant="outline"
- className="text-xs w-32 flex items-center gap-2"
- onClick={() => handleFileManagement("A/S 네트워크")}
- >
- A/S 네트워크
- </Button>
- </div>
- </div>
- </div>
- }
- /> */}
-
- {/* <Separator /> */}
-
- {/* 매출정보 */}
- {/* <WideInfoSection
- title="매출정보"
- subtitle="(3개년)"
- noPadding={true}
- content={
- <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 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>
- {["20231231", "20221231", "20211231"].map((dateKey) => {
- const year = dateKey;
- const salesData = initialData.salesInfo?.[year];
- const metricsData = initialData.calculatedMetrics?.[dateKey];
-
- return (
- <TableRow key={dateKey}>
- <TableCell className="text-center font-medium border-r bg-yellow-50">
- {year}
- </TableCell>
- <TableCell className="text-right border-r">
- {salesData
- ? (
- parseInt(salesData.totalDebt.replace(/,/g, "")) +
- parseInt(salesData.totalEquity.replace(/,/g, ""))
- ).toLocaleString()
- : "-"}
- </TableCell>
- <TableCell className="text-right border-r">
- {salesData?.totalDebt || "-"}
- </TableCell>
- <TableCell className="text-right border-r">
- {salesData?.totalEquity || "-"}
- </TableCell>
- <TableCell className="text-right border-r">
- {salesData?.operatingProfit || "-"}
- </TableCell>
- <TableCell className="text-right border-r">
- {salesData?.netIncome || "-"}
- </TableCell>
- <TableCell className="text-right border-r">
- {metricsData?.debtRatio?.toFixed(1) || "-"}
- </TableCell>
- <TableCell className="text-right border-r">
- {metricsData?.borrowingDependency?.toFixed(1) || "-"}
- </TableCell>
- <TableCell className="text-right border-r">
- {metricsData?.operatingMargin?.toFixed(1) || "-"}
- </TableCell>
- <TableCell className="text-right border-r">
- {metricsData?.netMargin?.toFixed(1) || "-"}
- </TableCell>
- <TableCell className="text-right border-r">
- {metricsData?.salesGrowth?.toFixed(1) || "-"}
- </TableCell>
- <TableCell className="text-right">
- {metricsData?.currentRatio?.toFixed(1) || "-"}
- </TableCell>
- </TableRow>
- );
- })}
- </TableBody>
- </Table>
- }
- /> */}
-
- {/* <Separator /> */}
-
- {/* 실사정보 */}
- {/* <InfoSection
- title="실사정보"
- subtitle="(3년)"
- column1={
- <div className="space-y-2">
- <InfoItem
- title="공장주소"
- value={initialData.factoryInfo?.factoryAddress || null}
- />
- <InfoItem
- title="공장설립일"
- value={
- initialData.factoryInfo?.factoryEstablishmentDate || null
- }
- />
- </div>
- }
- column2={
- <div className="space-y-2">
- <InfoItem
- title="공장 담당자"
- value={
- initialData.factoryInfo?.factoryPIC
- ? `${initialData.factoryInfo.factoryPIC} [${
- initialData.factoryInfo.factoryPICContact || ""
- }] [${initialData.factoryInfo.factoryPICEmail || ""}]`
- : null
- }
- />
- <InfoItem
- title="실사결과"
- value={
- initialData.inspectionInfo?.inspectionResult
- ? `${initialData.inspectionInfo.inspectionResult} (${
- initialData.inspectionInfo.inspectionDate || ""
- })`
- : null
- }
- />
- </div>
- }
- column3={
- <div className="flex flex-col gap-2">
- <div className="space-y-2">
- <InfoItem
- title="대표공급품목"
- value={initialData.capacityInfo?.mainSupplyItems || null}
- />
- </div>
- <Button
- variant="outline"
- onClick={() => handleFileManagement("대표공급품목")}
- >
- 대표 공급품목 상세보기
- </Button>
- </div>
- }
- additionalContent={
- <div className="grid grid-cols-5 gap-4 min-w-0 overflow-x-auto">
- <div className="text-center min-w-0">
- <div className="text-sm font-medium mb-2 break-words">
- 공정소개자료
- </div>
- <div className="text-sm text-muted-foreground">
- {attachmentsByType.BUSINESS_REGISTRATION?.length || 0}건
- </div>
- </div>
- <div className="text-center min-w-0">
- <div className="text-sm font-medium mb-2 break-words">
- QMS Cert
- </div>
- <div className="text-sm text-muted-foreground">
- {attachmentsByType.ISO_CERTIFICATION?.length || 0}건
- </div>
- </div>
- <div className="text-center min-w-0">
- <div className="text-sm font-medium mb-2 break-words">
- Product Cert
- </div>
- <div className="text-sm text-muted-foreground">
- {attachmentsByType.PRODUCT_CERT?.length || 0}건
- </div>
- </div>
- <div className="text-center min-w-0">
- <div className="text-sm font-medium mb-2 break-words">
- Ex. Cert
- </div>
- <div className="text-sm text-muted-foreground">
- {attachmentsByType.EX_CERT?.length || 0}건
- </div>
- </div>
- <div className="text-center min-w-0">
- <div className="text-sm font-medium mb-2 break-words">
- HSE Cert
- </div>
- <div className="text-sm text-muted-foreground">
- {attachmentsByType.HSE_CERT?.length || 0}건
- </div>
- </div>
- </div>
- }
- /> */}
-
- {/* <Separator /> */}
-
- {/* 계약정보 */}
- {/* <InfoSection
- title="계약정보"
- column1={
- <div className="space-y-2">
- <InfoItem
- title="정규등록현황"
- value={
- initialData.contractDetails?.regularRegistrationStatus || null
- }
- />
- </div>
- }
- column2={
- <div className="space-y-2">
- <InfoItem
- title="선호 계약조건"
- value={
- initialData.contractDetails?.preferredContractTerms || null
- }
- />
- </div>
- }
- column3={
- <div className="space-y-2">
- <InfoItem
- title="최근 거래현황"
- value={
- initialData.contractDetails?.recentTransactionStatus || null
- }
- />
- </div>
- }
- additionalContent={
- <div className="grid grid-cols-10 gap-4 min-w-0 overflow-x-auto">
- {[
- {
- title: "준법서약",
- value:
- initialData.contractDetails?.compliancePledgeDate || null,
- },
- {
- title: "기술자료",
- value: initialData.contractDetails?.technicalDataDate || null,
- },
- {
- title: "비밀유지",
- value:
- initialData.contractDetails?.confidentialityDate || null,
- },
- {
- title: "GTC",
- value: initialData.contractDetails?.gtcDate || null,
- },
- {
- title: "표준하도급",
- value:
- initialData.contractDetails?.standardSubcontractDate ||
- null,
- },
- {
- title: "안전보건",
- value: initialData.contractDetails?.safetyHealthDate || null,
- },
- {
- title: "직납자재",
- value:
- initialData.contractDetails?.directMaterialDate || null,
- },
- {
- title: "내국신용장",
- value: initialData.contractDetails?.domesticLCDate || null,
- },
- {
- title: "동반성장",
- value: initialData.contractDetails?.mutualGrowthDate || null,
- },
- {
- title: "윤리규범",
- value: initialData.contractDetails?.ethicsDate || null,
- },
- ].map((item, index) => (
- <div key={index} className="text-center min-w-0">
- <div className="text-sm font-medium mb-2 break-words">
- {item.title}
- </div>
- <div className="text-sm text-muted-foreground">
- {item.value || "-"}
- </div>
- </div>
- ))}
- </div>
- }
- /> */}
-
-
-
- {/* 추가 조회 기능 버튼들 */}
- <div className="border rounded-lg p-6">
- <div className="text-lg font-semibold mb-4">상세 정보 조회</div>
- <div className="grid grid-cols-2 md:grid-cols-4 gap-4">
- <Button
- variant="outline"
- onClick={handlePQView}
- className="h-20 flex flex-col items-center justify-center space-y-2"
- >
- <div className="text-sm font-medium">PQ 조회</div>
- <div className="text-xs text-muted-foreground">제출된 PQ 정보 확인</div>
- </Button>
-
- <Button
- variant="outline"
- onClick={handleSiteVisitView}
- className="h-20 flex flex-col items-center justify-center space-y-2"
- >
- <div className="text-sm font-medium">실사 정보</div>
- <div className="text-xs text-muted-foreground">협력업체 방문실사 조회</div>
- </Button>
-
- <Button
- variant="outline"
- onClick={handleContractView}
- className="h-20 flex flex-col items-center justify-center space-y-2"
- >
- <div className="text-sm font-medium">정규업체 등록 현황</div>
- <div className="text-xs text-muted-foreground">정규업체 등록 현황 보기</div>
- </Button>
-
- <Button
- variant="outline"
- onClick={handleAdditionalInfoView}
- className="h-20 flex flex-col items-center justify-center space-y-2"
- >
- <div className="text-sm font-medium">추가정보</div>
- <div className="text-xs text-muted-foreground">업체 추가정보 조회</div>
- </Button>
- </div>
- </div>
- </div>
-
- {/* 다이얼로그들 */}
- <PQSimpleDialog
- open={pqDialogOpen}
- onOpenChange={setPqDialogOpen}
- vendorId={vendorId}
- />
-
- <SiteVisitDetailDialog
- isOpen={siteVisitDialogOpen}
- onOpenChange={setSiteVisitDialogOpen}
- selectedRequest={selectedSiteVisitRequest}
- />
-
- {registrationData && (
- <DocumentStatusDialog
- open={contractDialogOpen}
- onOpenChange={setContractDialogOpen}
- registration={registrationData}
- />
- )}
-
- <AdditionalInfoDialog
- open={additionalInfoDialogOpen}
- onOpenChange={setAdditionalInfoDialogOpen}
- vendorId={parseInt(vendorId)}
- readonly={true}
- />
- </div>
- );
-}
diff --git a/app/[lng]/evcp/(evcp)/vendors/[id]/info/basic/constants.ts b/app/[lng]/evcp/(evcp)/vendors/[id]/info/basic/constants.ts
deleted file mode 100644
index d16f791f..00000000
--- a/app/[lng]/evcp/(evcp)/vendors/[id]/info/basic/constants.ts
+++ /dev/null
@@ -1 +0,0 @@
-export const noDataString = "-"; \ No newline at end of file
diff --git a/app/[lng]/evcp/(evcp)/vendors/[id]/info/basic/page.tsx b/app/[lng]/evcp/(evcp)/vendors/[id]/info/basic/page.tsx
index ae63d77d..629717fb 100644
--- a/app/[lng]/evcp/(evcp)/vendors/[id]/info/basic/page.tsx
+++ b/app/[lng]/evcp/(evcp)/vendors/[id]/info/basic/page.tsx
@@ -1,5 +1,5 @@
-import { getVendorData } from "./actions";
-import BasicInfoClient from "./basic-info-client";
+import { getVendorData } from "@/lib/vendor-basic-info/actions";
+import BasicInfoClient from "@/lib/vendor-basic-info/basic-info-client";
interface VendorBasicPageProps {
params: {
diff --git a/app/[lng]/evcp/(evcp)/vendors/[id]/info/basic/types.ts b/app/[lng]/evcp/(evcp)/vendors/[id]/info/basic/types.ts
deleted file mode 100644
index ead3a44c..00000000
--- a/app/[lng]/evcp/(evcp)/vendors/[id]/info/basic/types.ts
+++ /dev/null
@@ -1,180 +0,0 @@
-export interface VendorContact {
- id: number;
- contactName: string;
- contactPosition: string;
- contactEmail: string;
- contactPhone: string;
- isPrimary: boolean;
-}
-
-export interface VendorAttachment {
- id: number;
- fileName: string;
- filePath: string;
- attachmentType: string;
- createdAt: string;
-}
-
-export interface VendorProcessInfo {
- processCount: number;
- processPIC: string;
- processApprovalDate: string;
- implementationApproval: string;
-}
-
-export interface VendorContractInfo {
- contractRegistrationNumber: string;
- contractPeriod: string;
- lastEquipmentInspection: string;
-}
-
-export interface VendorSalesData {
- totalSales: string;
- totalDebt: string;
- totalEquity: string;
- operatingProfit: string;
- netIncome: string;
-}
-
-export interface VendorAdditionalInfo {
- postalCode: string;
- detailAddress: string;
- mainBusiness: string;
- employeeCount: number;
- businessType: string;
-}
-
-export interface VendorOrganization {
- representative: number;
- sales: number;
- design: number;
- procurement: number;
- production: number;
- quality: number;
-}
-
-export interface VendorFactoryInfo {
- factoryAddress: string;
- factoryEstablishmentDate: string;
- factoryPIC: string;
- factoryPICContact: string;
- factoryPICEmail: string;
-}
-
-export interface VendorInspectionInfo {
- inspectionResult: string;
- inspectionDate: string;
- inspectionReportUrl?: string;
-}
-
-export interface VendorEvaluationInfo {
- regularEvaluationGrade: string;
- safetyQualificationEvaluation: string;
- companyTransactionRatio: string;
-}
-
-export interface VendorClassificationInfo {
- vendorClassification: string;
- groupCompany: string;
- preferredLanguage: string;
- industryType: string;
- isoCertification: string;
-}
-
-export interface VendorContractDetails {
- regularRegistrationStatus: string;
- preferredContractTerms: string;
- recentTransactionStatus: string;
- compliancePledgeDate: string;
- technicalDataDate: string;
- confidentialityDate: string;
- gtcDate: string;
- standardSubcontractDate: string;
- safetyHealthDate: string;
- directMaterialDate: string;
- domesticLCDate: string;
- mutualGrowthDate: string;
- ethicsDate: string;
-}
-
-export interface VendorCapacityInfo {
- annualSales: string;
- productionCapacity: string;
- mainSupplyItems: string;
-}
-
-export interface VendorCalculatedMetrics {
- debtRatio: number;
- borrowingDependency: number;
- operatingMargin: number;
- netMargin: number;
- salesGrowth: number;
- currentRatio: number;
-}
-
-export interface VendorData {
- id: number;
- vendorName: string;
- vendorCode: string;
- taxId: string;
- address: string;
- addressDetail: string;
- postalCode: string;
- businessSize: string;
- country: string;
- phone: string;
- fax: string;
- email: string;
- website: string;
- status: string;
- representativeName: string;
- representativeBirth: string;
- representativeEmail: string;
- representativePhone: string;
- representativeWorkExperience: boolean;
- corporateRegistrationNumber: string;
- creditAgency: string;
- creditRating: string;
- cashFlowRating: string;
- createdAt: string;
- updatedAt: string;
- contacts: VendorContact[];
- attachments: VendorAttachment[];
- processInfo: VendorProcessInfo;
- contractInfo: VendorContractInfo;
- salesInfo: {
- [year: string]: VendorSalesData;
- };
- additionalInfo: VendorAdditionalInfo;
- organization: VendorOrganization;
- factoryInfo: VendorFactoryInfo;
- inspectionInfo: VendorInspectionInfo;
- evaluationInfo: VendorEvaluationInfo;
- classificationInfo: VendorClassificationInfo;
- contractDetails: VendorContractDetails;
- capacityInfo: VendorCapacityInfo;
- calculatedMetrics: {
- [year: string]: VendorCalculatedMetrics;
- };
-}
-
-export interface VendorFormData {
- vendorName: string;
- representativeName: string;
- representativeWorkExperience: boolean;
- representativeBirth: string;
- representativePhone: string;
- representativeEmail: string;
- addressDetail: string;
- postalCode: string;
- phone: string;
- fax: string;
- email: string;
- address: string;
- businessSize: string;
- country: string;
- website: string;
- businessType: string;
- employeeCount: number;
- mainBusiness: string;
-} \ No newline at end of file
diff --git a/app/[lng]/partners/(partners)/sales-force-test/page.tsx b/app/[lng]/partners/(partners)/sales-force-test/page.tsx
deleted file mode 100644
index 8d6cbfbc..00000000
--- a/app/[lng]/partners/(partners)/sales-force-test/page.tsx
+++ /dev/null
@@ -1,32 +0,0 @@
-import path from "path";
-import { promises as fs } from "fs";
-
-type PageProps = {
- params: { lng: string };
-};
-
-export default async function Page({ params }: PageProps) {
- const filePath = path.join(
- process.cwd(),
- "app",
- "[lng]",
- "partners",
- "(partners)",
- "sales-force-test",
- "AF_poc.html"
- );
-
- const html = await fs.readFile(filePath, "utf8");
-
- return (
- <div className="w-full h-[100vh]">
- <iframe
- title="Salesforce LWC Test"
- className="w-full h-full border-0"
- srcDoc={html}
- />
- </div>
- );
-}
-
-
diff --git a/app/[lng]/partners/pq_new/[id]/page.tsx b/app/[lng]/partners/pq_new/[id]/page.tsx
index 41c59b47..3c2858f2 100644
--- a/app/[lng]/partners/pq_new/[id]/page.tsx
+++ b/app/[lng]/partners/pq_new/[id]/page.tsx
@@ -160,7 +160,7 @@ export default async function PQEditPage(props: PQEditPageProps) {
)}
{/* PQ 입력 컴포넌트 */}
- <div className={isReadOnly ? "pointer-events-none opacity-60" : ""}>
+ <div className={isReadOnly ? "opacity-60" : ""}>
<PQInputTabs
data={pqData}
vendorId={idAsNumber}