From 9afe98ec60bcff59596698cd91d147b26ca22583 Mon Sep 17 00:00:00 2001 From: SeongHyun Kim Date: Tue, 24 Mar 2026 19:14:34 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20pop-field=EC=97=90=20json=5Fextract=5Fl?= =?UTF-8?q?ookup=20valueSource=20=EC=B6=94=EA=B0=80=20cart=5Fitems.row=5Fd?= =?UTF-8?q?ata=EC=97=90=EC=84=9C=20=EC=BD=94=EB=93=9C=EA=B0=92(partner=5Fi?= =?UTF-8?q?d)=EC=9D=84=20=EC=B6=94=EC=B6=9C=ED=95=9C=20=ED=9B=84=20?= =?UTF-8?q?=EC=B0=B8=EC=A1=B0=20=ED=85=8C=EC=9D=B4=EB=B8=94(customer=5Fmng?= =?UTF-8?q?)=EC=97=90=EC=84=9C=20=ED=91=9C=EC=8B=9C=EA=B0=92(customer=5Fna?= =?UTF-8?q?me)=EC=9D=84=20=EC=A1=B0=ED=9A=8C=ED=95=98=EB=8A=94=20json=5Fex?= =?UTF-8?q?tract=5Flookup=20=EA=B8=B0=EB=8A=A5=EC=9D=84=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=ED=95=9C=EB=8B=A4.=20=ED=99=94=EB=A9=B4=204579(?= =?UTF-8?q?=EC=B6=9C=EA=B3=A0=20=ED=99=95=EC=A0=95)=EC=97=90=EC=84=9C=20?= =?UTF-8?q?=EA=B1=B0=EB=9E=98=EC=B2=98=EB=AA=85=EC=9D=B4=20=ED=91=9C?= =?UTF-8?q?=EC=8B=9C=EB=90=98=EC=A7=80=20=EC=95=8A=EB=8A=94=20=EB=AC=B8?= =?UTF-8?q?=EC=A0=9C=EB=A5=BC=20=ED=95=B4=EA=B2=B0=ED=95=9C=EB=8B=A4.=20Co?= =?UTF-8?q?-Authored-By:=20Claude=20Opus=204.6=20(1M=20context)=20?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pop-field/PopFieldComponent.tsx | 38 +++++++++++++++++++ .../pop-components/pop-field/types.ts | 9 ++++- 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/frontend/lib/registry/pop-components/pop-field/PopFieldComponent.tsx b/frontend/lib/registry/pop-components/pop-field/PopFieldComponent.tsx index 0438df90..9a65e0fb 100644 --- a/frontend/lib/registry/pop-components/pop-field/PopFieldComponent.tsx +++ b/frontend/lib/registry/pop-components/pop-field/PopFieldComponent.tsx @@ -95,6 +95,7 @@ export function PopFieldComponent({ const row = res.data[0] as Record; const extracted: Record = {}; + const lookupQueue: { fieldId: string; codeValue: string; table: string; codeCol: string; displayCol: string }[] = []; for (const mapping of readSource.fieldMappings || []) { if (mapping.valueSource === "json_extract" && mapping.columnName && mapping.jsonKey) { const raw = row[mapping.columnName]; @@ -105,11 +106,48 @@ export function PopFieldComponent({ parsed = raw as Record; } extracted[mapping.fieldId] = parsed[mapping.jsonKey] ?? ""; + } else if (mapping.valueSource === "json_extract_lookup" && mapping.columnName && mapping.jsonKey && mapping.lookupTable && mapping.lookupCodeColumn && mapping.lookupDisplayColumn) { + const raw = row[mapping.columnName]; + let parsed: Record = {}; + if (typeof raw === "string") { + try { parsed = JSON.parse(raw); } catch { /* ignore */ } + } else if (typeof raw === "object" && raw !== null) { + parsed = raw as Record; + } + const codeValue = String(parsed[mapping.jsonKey] ?? ""); + if (codeValue) { + lookupQueue.push({ fieldId: mapping.fieldId, codeValue, table: mapping.lookupTable, codeCol: mapping.lookupCodeColumn, displayCol: mapping.lookupDisplayColumn }); + } else { + extracted[mapping.fieldId] = ""; + } } else if (mapping.valueSource === "db_column" && mapping.columnName) { extracted[mapping.fieldId] = row[mapping.columnName] ?? ""; } } + // json_extract_lookup: 코드 값으로 참조 테이블 조회하여 표시명 획득 + if (lookupQueue.length > 0) { + const lookupResults = await Promise.allSettled( + lookupQueue.map(async (lq) => { + const lookupRes = await dataApi.getTableData(lq.table, { + page: 1, + size: 1, + filters: { [lq.codeCol]: lq.codeValue }, + }); + if (Array.isArray(lookupRes.data) && lookupRes.data.length > 0) { + const lookupRow = lookupRes.data[0] as Record; + return { fieldId: lq.fieldId, value: lookupRow[lq.displayCol] ?? lq.codeValue }; + } + return { fieldId: lq.fieldId, value: lq.codeValue }; + }), + ); + for (const result of lookupResults) { + if (result.status === "fulfilled") { + extracted[result.value.fieldId] = result.value.value; + } + } + } + const allFieldsInConfig = cfg.sections.flatMap((s) => s.fields || []); const valuesUpdate: Record = {}; for (const [fieldId, val] of Object.entries(extracted)) { diff --git a/frontend/lib/registry/pop-components/pop-field/types.ts b/frontend/lib/registry/pop-components/pop-field/types.ts index f0813e6c..a2ddae0c 100644 --- a/frontend/lib/registry/pop-components/pop-field/types.ts +++ b/frontend/lib/registry/pop-components/pop-field/types.ts @@ -110,12 +110,13 @@ export interface PopFieldSection { // ===== 저장 설정: 값 소스 타입 ===== -export type FieldValueSource = "direct" | "json_extract" | "db_column"; +export type FieldValueSource = "direct" | "json_extract" | "db_column" | "json_extract_lookup"; export const FIELD_VALUE_SOURCE_LABELS: Record = { direct: "직접 입력", json_extract: "JSON 추출", db_column: "DB 컬럼", + json_extract_lookup: "JSON 추출 + 조회", }; // ===== 저장 설정: 필드-컬럼 매핑 ===== @@ -170,6 +171,12 @@ export interface PopFieldReadMapping { valueSource: FieldValueSource; columnName: string; jsonKey?: string; + /** json_extract_lookup 전용: 조회할 테이블명 */ + lookupTable?: string; + /** json_extract_lookup 전용: JSON에서 추출한 코드 값과 매칭할 컬럼 */ + lookupCodeColumn?: string; + /** json_extract_lookup 전용: 화면에 표시할 컬럼 */ + lookupDisplayColumn?: string; } export interface PopFieldReadSource {