Files
vexplor_dev/docs/smart-excel-upload.md
kjs dffa16f3e5 feat: Add Smart Excel Upload functionality for item inspection
- Introduced a new SmartExcelUploadModal component to facilitate bulk item inspection uploads via Excel.
- Implemented logic for downloading templates, validating uploaded files, and parsing data for inspection criteria.
- Enhanced the item inspection page to support dynamic loading of item process mappings and reference data for improved user experience.
- Added necessary types and utility functions for template generation and parsing, ensuring robust handling of Excel data.
- These changes aim to streamline the item inspection process and improve data management across multiple company implementations.
2026-04-15 14:23:44 +09:00

13 KiB

SmartExcelUpload

설정(Config) 기반 엑셀 업로드 공통 모듈. Config 객체와 데이터를 넘기면 템플릿 생성, 업로드, 검증, 미리보기까지 자동 처리된다. 화면별로 Config 정의 + 데이터 조회 + 저장 콜백만 작성하면 어디든 적용 가능.

기존 ExcelUploadModal과의 차이

기존 ExcelUploadModal은 단일 테이블의 단순 데이터를 일괄 업로드하는 용도(거래처 목록 등).

SmartExcelUpload는 아래와 같이 기존 컴포넌트로 처리하기 어려운 복잡한 구조에서 사용한다.

상황 예시
셀 간 연동이 필요할 때 A 컬럼 선택 → B 컬럼 자동 입력
선택한 값에 따라 드롭다운이 달라질 때 마스터 데이터별로 선택 가능한 하위 항목이 다름
조건에 따라 입력 가능/불가가 바뀔 때 특정 유형일 때만 특정 컬럼 입력 가능
멀티 시트로 유형을 구분할 때 유형별 시트 분리
참조 데이터 기반 자동 검증이 필요할 때 기준 데이터 변경 시 템플릿 재다운로드 유도 (해시 검증)
1:N 관계의 데이터를 등록할 때 마스터 1개에 디테일 N개, 유형 다수

단순 일괄 등록은 기존 ExcelUploadModal을 쓰면 된다.

참고: 셀 간 연동 수식(VLOOKUP, INDEX/MATCH 등)은 화면마다 다르다. SmartExcelUpload가 제공하는 것은 수식 자체가 아니라 수식을 적용하는 메커니즘(autoFill, customFormula, INDIRECT 등)이다. 어떤 컬럼에 어떤 수식이 들어갈지는 Config에서 화면별로 정의한다.

파일 구조

SmartExcelUpload/
  index.ts                  # export
  types.ts                  # Config 인터페이스, 검증 타입
  templateGenerator.ts      # ExcelJS 기반 엑셀 템플릿 생성
  templateParser.ts         # 업로드 파일 파싱 + 해시 검증 + 데이터 검증
  SmartExcelUploadModal.tsx  # 모달 UI (다운로드 → 업로드 → 검증 → 미리보기)

핵심 개념

Config 기반 동작

모든 동작은 SmartExcelUploadConfig로 결정된다.

const config: SmartExcelUploadConfig = {
  templateName: "파일명",
  sheets: [...],              // 시트 정의 (단일/멀티)
  referenceSheet: {...},      // 참조 데이터 숨김시트 (선택)
  conditionalRules: [...],    // 조건부 검증 규칙 (선택)
  indirectOptions: {...},     // ACC_ 동적 드롭다운 옵션 정의 (선택)
};

엑셀 템플릿 구조

[시트: 안내]              ← Config 기반 자동 생성 (컬럼 설명, 입력 규칙, 사용법)
[시트: 데이터1]           ← 사용자가 작성하는 시트 (여러 개 가능)
[시트: 데이터2]           
[숨김: 참조시트]          ← VLOOKUP 참조 데이터 (referenceSheet 설정 시)
[숨김: _품목공정]         ← INDIRECT 이름 범위 (itemProcessMappings 설정 시)
[숨김: _품목목록]         ← 마스터 드롭다운 소스 (itemProcessMappings 설정 시)
[숨김: _합격기준옵션]     ← INDIRECT ACC_ 이름 범위 (indirectOptions 설정 시)
[숨김: _meta]             ← 버전 해시, 생성일

숨김시트들은 해당 기능을 사용하는 Config일 때만 생성된다.

버전 해시 검증

  • 템플릿 생성 시: 참조 데이터 + 드롭다운 옵션 + 매핑 데이터 → 해시 생성 → _meta 시트에 저장
  • 업로드 시: 현재 DB 데이터로 해시 재생성 → 일치 여부 확인
  • 불일치 시: "기준 데이터가 변경되었습니다. 최신 템플릿을 다시 다운로드해주세요" 경고

안내시트 자동 생성

Config의 컬럼 정의를 기반으로 안내시트가 자동 생성된다.

  • 컬럼별 설명 (필수 여부, 자동 입력 여부, 드롭다운 유형 등)
  • 조건부 규칙 설명 (conditionalRules 기반)
  • 잠금 셀 목록 (autoFill/readOnly/customFormula 컬럼)
  • 사용 방법 단계

컬럼 타입

기본 타입

type 설명
text 자유 텍스트
number 숫자 (천단위 서식 자동 적용)
date 날짜
dropdown 드롭다운 선택

드롭다운 source 유형

source 설명 예시
custom 고정 값 목록 values: ["Y", "N"]
category 카테고리 테이블 조회 tableName: "...", columnName: "..."
indirect 다른 셀 값에 따라 동적 변경 indirectKeyColumn: "...", indirectPrefix: "P_"

컬럼 속성

속성 설명
required 필수 여부 — 업로드 검증 시 빈 값 체크
readOnly 읽기전용 — 셀 잠금
autoFill 참조시트에서 VLOOKUP 자동 입력 — 셀 잠금, 회색 배경
customFormula 커스텀 엑셀 수식 — {col:key} 플레이스홀더로 같은 행 참조
enableWhen 조건부 활성화 — 참조시트에서 직접 조회하여 판단 (VLOOKUP 미계산 문제 없음)
disableWhen 조건부 비활성화 — 특정 조건일 때 입력 차단
width 컬럼 너비 (기본 18)

주요 기능

1. VLOOKUP 자동 입력 (autoFill)

참조시트의 데이터를 기반으로 다른 셀 값에 연동되어 자동 입력된다.

{
  key: "detail_column",
  label: "상세정보",
  readOnly: true,
  autoFill: {
    lookupColumn: "master_key",       // 같은 행의 이 컬럼 값을 기준으로
    referenceColumn: "detail",        // 참조시트에서 이 컬럼 값을 가져옴
  }
}

2. 커스텀 수식 (customFormula)

{col:key} 플레이스홀더를 사용하여 같은 행의 다른 컬럼을 참조하는 수식을 정의한다. 절대참조($)는 행 치환에서 자동 보호된다.

{
  key: "code_column",
  readOnly: true,
  customFormula: `IFERROR(INDEX('_시트명'!$A$1:$A$9999,MATCH({col:name_column},'_시트명'!$B$1:$B$9999,0)),"")`
}

3. INDIRECT 동적 드롭다운

다른 셀 값에 따라 드롭다운 옵션이 동적으로 변경된다.

P_ prefix (이름 범위 직접 참조):

{
  key: "sub_item",
  type: "dropdown",
  dropdown: {
    source: "indirect",
    indirectKeyColumn: "master_code",   // 이 컬럼 값을 기준으로
    indirectPrefix: "P_",               // P_{값} 이름 범위 참조
  }
}

ACC_ prefix (MATCH 인덱스 기반 참조):

{
  key: "criteria_value",
  type: "dropdown",
  dropdown: {
    source: "indirect",
    indirectKeyColumn: "standard_key",
    indirectPrefix: "ACC_",             // ACC_{인덱스} — MATCH로 인덱스 조회
  }
}

ACC_ prefix 사용 시 Config에 indirectOptions 설정 필요:

indirectOptions: {
  conditionColumn: "condition_type",           // 참조시트에서 조건 판단할 컬럼
  optionsByCondition: { "타입A": ["O", "X"] }, // 조건값별 고정 옵션
  selectionOptionsColumn: "options_column",     // 동적 옵션 (콤마 구분 문자열)
}

4. 조건부 활성화/비활성화

다른 컬럼 값에 따라 셀 입력 가능 여부가 결정된다. 참조시트에서 직접 조회하는 방식이라 VLOOKUP 미계산 문제가 없다.

{ key: "value_a", type: "number", enableWhen: { column: "condition_col", equals: "특정값" } }

5. 조건부 검증 규칙

업로드 시 특정 조건에 따라 필수/무시 컬럼이 달라진다. autoFill 컬럼의 값도 참조데이터에서 직접 조회하여 조건 판단.

conditionalRules: [
  {
    when: { column: "condition_col", equals: "타입A" },
    require: ["required_col"],     // 필수
    ignore: ["optional_col"],      // 무시
  },
]

6. ItemProcessMapping (마스터-디테일 매핑)

마스터 항목별로 선택 가능한 하위 항목이 다를 때 사용. 벌크 API로 전체 데이터를 한 번에 조회하여 INDIRECT 이름 범위로 등록.

itemProcessMappings: [
  { itemCode: "M-001", itemName: "마스터A", processes: [{ code: "S01", name: "하위1" }] },
  { itemCode: "M-002", itemName: "마스터B", processes: [{ code: "S02", name: "하위2" }, { code: "S03", name: "하위3" }] },
]

업로드 검증 시 마스터에 맞지 않는 하위 항목은 자동으로 에러 처리된다.


성능 구조

항목 방식 범위
드롭다운/validation 컬럼 범위 1회 설정 65,000행
수식 (VLOOKUP, customFormula) 행별 개별 삽입 2,000행 (FORMULA_END)
셀 보호 (잠금/해제) 행별 개별 설정 2,000행
셀 스타일 (배경, 테두리) 행별 개별 설정 2,000행
데이터 캐싱 최초 로드 후 재사용 페이지 세션

드롭다운은 범위 단위라 행 수 제한 없음. 수식/스타일은 FORMULA_END 상수로 조절 가능.


사용법

1. 기본 사용 (단순 드롭다운만)

import { SmartExcelUploadModal } from "@/components/common/SmartExcelUpload";
import type { SmartExcelUploadConfig, ParsedSheetData } from "@/components/common/SmartExcelUpload";

const config: SmartExcelUploadConfig = {
  templateName: "거래처",
  sheets: [{
    name: "거래처",
    columns: [
      { key: "name", label: "거래처명", required: true, type: "text", width: 24 },
      { key: "division", label: "구분", type: "dropdown",
        dropdown: { source: "custom", values: ["매출처", "매입처"] } },
    ],
  }],
};

const handleUpload = async (data: ParsedSheetData[]) => {
  for (const sheet of data) {
    for (const row of sheet.rows) await api.create(row);
  }
};

<SmartExcelUploadModal
  open={open}
  onOpenChange={setOpen}
  config={config}
  dropdownOptions={{ division: ["매출처", "매입처"] }}
  onUpload={handleUpload}
/>

2. 고급 사용 (참조시트 + INDIRECT + 조건부 검증)

<SmartExcelUploadModal
  open={open}
  onOpenChange={setOpen}
  config={config}                          // 시트/컬럼/규칙 정의
  referenceData={refData}                  // 참조시트 데이터
  dropdownOptions={dropdownOpts}           // 드롭다운 옵션
  itemProcessMappings={processMappings}    // 마스터-디테일 매핑
  labelToCodeMap={labelMap}                // 라벨→코드 변환
  onUpload={handleUpload}                  // 저장 콜백
  dataLoading={loading}                    // 로딩 상태
  loadProgress={{ loaded: 100, total: 500 }} // 진행률
/>

3. Props

prop 타입 필수 설명
open boolean O 모달 열림 상태
onOpenChange (open: boolean) => void O 모달 상태 변경
config SmartExcelUploadConfig O 전체 설정
referenceData Record[] 참조시트 데이터
dropdownOptions Record<string, string[]> 드롭다운 옵션 (키: 시트명:컬럼key 또는 컬럼key)
itemProcessMappings ItemProcessMapping[] 마스터-디테일 매핑 데이터
labelToCodeMap Record<string, Record<string, string>> 라벨→코드 변환
extraMeta Record<string, string> _meta 시트에 추가할 정보
onUpload (data: ParsedSheetData[]) => Promise O 업로드 완료 콜백
subtitle string 제목 아래 부가 설명
dataLoading boolean 외부 데이터 로딩 중 표시
loadProgress { loaded, total } 로딩 진행률 표시

4. 벌크 조회 API (백엔드)

마스터별 하위 항목을 한 번에 조회하는 API. 5,000건 단위 청크 분할로 대량 데이터 대응.

POST /work-instruction/routing-versions-bulk
Body: { itemCodes: ["M-001", "M-002", ...] }
Response: { success: true, data: { "M-001": [{ code, name }], "M-002": [...] } }

검증 흐름

업로드 → 메타 해시 검증 → 시트별 파싱 (사용자 입력 컬럼만 빈 행 체크)
  → 필수값 검증 (conditionalRules 적용, autoFill 값은 참조데이터에서 직접 조회)
  → 드롭다운 유효성 검증
  → INDIRECT 매핑 검증 (마스터에 맞지 않는 하위 항목 에러)
  → 에러 있으면 에러 리포트 / 없으면 미리보기 → 저장

확장 시 참고

  • 새 화면에 적용할 때: Config 정의 + 데이터 조회 + 저장 콜백만 작성
  • 단일 시트 / 멀티 시트 모두 지원 (sheets 배열 크기로 결정)
  • 참조시트 필요 없으면 referenceSheet 생략 → 숨김시트 미생성
  • 조건부 검증 필요 없으면 conditionalRules 생략 → 단순 필수값 체크만
  • INDIRECT 필요 없으면 itemProcessMappings 생략 → 일반 드롭다운만
  • ACC_ 동적 드롭다운 필요 없으면 indirectOptions 생략 → 해당 시트 미생성
  • FORMULA_END (기본 2,000) / VALIDATION_END (기본 65,000)으로 범위 조절 가능