From a6c0ab566431514bb1e31915bfc8cc27fdc099df Mon Sep 17 00:00:00 2001 From: SeongHyun Kim Date: Wed, 4 Mar 2026 19:12:22 +0900 Subject: [PATCH] =?UTF-8?q?feat(pop):=20=EC=9E=85=EA=B3=A0=20=ED=99=95?= =?UTF-8?q?=EC=A0=95=20=EC=8B=9C=20=EC=9E=90=EB=8F=99=20=EC=B1=84=EB=B2=88?= =?UTF-8?q?=20=EC=8B=A4=ED=96=89=20+=20=EA=B2=B0=EA=B3=BC=20=EB=AA=A8?= =?UTF-8?q?=EB=8B=AC=20UX=20+=20=EC=85=80=EB=A0=89=ED=8A=B8=20=EB=86=92?= =?UTF-8?q?=EC=9D=B4=20=ED=86=B5=EC=9D=BC=20=EC=9E=85=EA=B3=A0=20=ED=99=95?= =?UTF-8?q?=EC=A0=95(inbound-confirm)=20=EC=8B=A4=ED=96=89=20=EC=8B=9C=20?= =?UTF-8?q?=EC=B1=84=EB=B2=88=20=EA=B7=9C=EC=B9=99=EC=9D=B4=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95=EB=90=98=EC=96=B4=20=EC=9E=88=EC=96=B4=EB=8F=84=20inb?= =?UTF-8?q?ound=5Fnumber=EA=B0=80=20null=EB=A1=9C=20=EC=A0=80=EC=9E=A5?= =?UTF-8?q?=EB=90=98=EB=8D=98=20=EB=AC=B8=EC=A0=9C=EB=A5=BC=20=ED=95=B4?= =?UTF-8?q?=EA=B2=B0=ED=95=9C=EB=8B=A4.=20[=EC=B1=84=EB=B2=88=20=EC=8B=A4?= =?UTF-8?q?=ED=96=89=20(FIX-1)]=20-=20types.ts:=20SaveMapping=EC=97=90=20a?= =?UTF-8?q?utoGenMappings=20=ED=95=84=EB=93=9C=20=EC=B6=94=EA=B0=80=20(num?= =?UTF-8?q?beringRuleId,=20=20=20targetColumn,=20showResultModal)=20-=20Po?= =?UTF-8?q?pFieldComponent:=20collect=5Fdata=20=EC=9D=91=EB=8B=B5=EC=97=90?= =?UTF-8?q?=20autoGenMappings=20=ED=8F=AC=ED=95=A8=ED=95=98=EC=97=AC=20=20?= =?UTF-8?q?=20=EB=B0=B1=EC=97=94=EB=93=9C=EC=97=90=20=EC=B1=84=EB=B2=88=20?= =?UTF-8?q?=EA=B7=9C=EC=B9=99=20=EC=A0=95=EB=B3=B4=20=EC=A0=84=EB=8B=AC=20?= =?UTF-8?q?-=20popActionRoutes:=20INSERT=20=EC=A0=84=20numberingRuleServic?= =?UTF-8?q?e.allocateCode()=20=ED=98=B8=EC=B6=9C,=20=20=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1=EB=90=9C=20=EC=BD=94=EB=93=9C=EB=A5=BC=20generatedCod?= =?UTF-8?q?es=20=EB=B0=B0=EC=97=B4=EB=A1=9C=20=EC=9D=91=EB=8B=B5=EC=97=90?= =?UTF-8?q?=20=ED=8F=AC=ED=95=A8=20[=EA=B2=B0=EA=B3=BC=20=EB=AA=A8?= =?UTF-8?q?=EB=8B=AC=20UX]=20-=20pop-button:=20showResultModal=20=ED=86=A0?= =?UTF-8?q?=EA=B8=80=EC=97=90=20=EB=94=B0=EB=9D=BC=20=EC=B1=84=EB=B2=88=20?= =?UTF-8?q?=EA=B2=B0=EA=B3=BC=20=EB=AA=A8=EB=8B=AC=20=ED=91=9C=EC=8B=9C=20?= =?UTF-8?q?=EB=B6=84=EA=B8=B0=20-=20=EB=AA=A8=EB=8B=AC=EC=9D=B4=20?= =?UTF-8?q?=EC=97=B4=EB=A0=A4=20=EC=9E=88=EB=8A=94=20=EB=8F=99=EC=95=88=20?= =?UTF-8?q?followUpActions(refresh/navigate)=20=EC=A7=80=EC=97=B0=ED=95=98?= =?UTF-8?q?=EC=97=AC=20=20=20=EC=82=AC=EC=9A=A9=EC=9E=90=EA=B0=80=20?= =?UTF-8?q?=ED=99=95=EC=9D=B8=20=EB=B2=84=ED=8A=BC=EC=9D=84=20=EB=88=8C?= =?UTF-8?q?=EB=9F=AC=EC=95=BC=20=ED=9B=84=EC=86=8D=20=EC=95=A1=EC=85=98=20?= =?UTF-8?q?=EC=8B=A4=ED=96=89=20[=EC=85=80=EB=A0=89=ED=8A=B8=20=EB=86=92?= =?UTF-8?q?=EC=9D=B4=20=EC=9D=BC=EA=B4=80=EC=84=B1]=20-=20SelectTrigger=20?= =?UTF-8?q?hasCustomHeight=EC=97=90=20/\bh-\d/=20=ED=8C=A8=ED=84=B4=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=ED=95=98=EC=97=AC=20=20=20className=EC=9D=98?= =?UTF-8?q?=20h-9=20=EB=93=B1=EC=9D=B4=20=EA=B8=B0=EB=B3=B8=20data-size=3D?= =?UTF-8?q?"xs"(h-6)=EC=99=80=20=EC=B6=A9=EB=8F=8C=ED=95=98=EC=A7=80=20?= =?UTF-8?q?=EC=95=8A=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95=20[=EA=B8=B0?= =?UTF-8?q?=ED=83=80=20=EC=88=98=EC=A0=95]=20-=20SelectFieldInput:=20Set?= =?UTF-8?q?=20=EA=B8=B0=EB=B0=98=20dedup=EC=9C=BC=EB=A1=9C=20React=20key?= =?UTF-8?q?=20=EC=A4=91=EB=B3=B5=20=EB=B0=A9=EC=A7=80=20-=20PopFieldConfig?= =?UTF-8?q?:=20AutoNumberEditor=20=EC=A0=9C=EA=B1=B0,=20=EC=B1=84=EB=B2=88?= =?UTF-8?q?=20=EA=B7=9C=EC=B9=99=EC=9D=84=20=EC=A0=80=EC=9E=A5=20=ED=83=AD?= =?UTF-8?q?=EC=97=90=EC=84=9C=20=EA=B4=80=EB=A6=AC=20-=20PopFieldConfig:?= =?UTF-8?q?=20=EC=A0=84=EC=B2=B4=20=EC=B1=84=EB=B2=88=20=EA=B7=9C=EC=B9=99?= =?UTF-8?q?=20=EB=B3=B4=EA=B8=B0=20=ED=86=A0=EA=B8=80=20=EC=B6=94=EA=B0=80?= =?UTF-8?q?=20-=20PopCardListComponent:=20=EC=9E=A5=EB=B0=94=EA=B5=AC?= =?UTF-8?q?=EB=8B=88=20=EB=AA=A9=EB=A1=9D=20=EB=AA=A8=EB=93=9C=EC=97=90?= =?UTF-8?q?=EC=84=9C=20=EC=88=98=EB=9F=89=20=EC=9E=90=EB=8F=99=20=EC=B4=88?= =?UTF-8?q?=EA=B8=B0=ED=99=94=20=EB=B0=A9=EC=A7=80=20-=20PopCardListConfig?= =?UTF-8?q?:=20=EC=88=98=EC=8B=9D=20=ED=95=84=EB=93=9C=20=EB=A7=A4?= =?UTF-8?q?=ED=95=91=20=EB=85=B8=EC=B6=9C=20+=20=EB=88=84=EB=9D=BD=20?= =?UTF-8?q?=ED=95=84=EB=93=9C=20=EC=9E=90=EB=8F=99=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend-node/src/routes/popActionRoutes.ts | 42 ++++- frontend/components/ui/select.tsx | 2 +- .../registry/pop-components/pop-button.tsx | 104 ++++++++--- .../pop-card-list/PopCardListComponent.tsx | 5 +- .../pop-card-list/PopCardListConfig.tsx | 24 ++- .../pop-field/PopFieldComponent.tsx | 30 ++-- .../pop-field/PopFieldConfig.tsx | 170 ++++++------------ frontend/lib/registry/pop-components/types.ts | 5 + 8 files changed, 230 insertions(+), 152 deletions(-) diff --git a/backend-node/src/routes/popActionRoutes.ts b/backend-node/src/routes/popActionRoutes.ts index 24ef3af0..f71c4495 100644 --- a/backend-node/src/routes/popActionRoutes.ts +++ b/backend-node/src/routes/popActionRoutes.ts @@ -2,6 +2,7 @@ import { Router, Request, Response } from "express"; import { getPool } from "../database/db"; import logger from "../utils/logger"; import { authenticateToken } from "../middleware/authMiddleware"; +import { numberingRuleService } from "../services/numberingRuleService"; const router = Router(); @@ -12,9 +13,16 @@ function isSafeIdentifier(name: string): boolean { return SAFE_IDENTIFIER.test(name); } +interface AutoGenMappingInfo { + numberingRuleId: string; + targetColumn: string; + showResultModal?: boolean; +} + interface MappingInfo { targetTable: string; columnMapping: Record; + autoGenMappings?: AutoGenMappingInfo[]; } interface StatusConditionRule { @@ -114,6 +122,7 @@ router.post("/execute-action", authenticateToken, async (req: Request, res: Resp let processedCount = 0; let insertedCount = 0; + const generatedCodes: Array<{ targetColumn: string; code: string }> = []; if (action === "inbound-confirm") { // 1. 매핑 기반 INSERT (장바구니 데이터 -> 대상 테이블) @@ -144,6 +153,37 @@ router.post("/execute-action", authenticateToken, async (req: Request, res: Resp } } + // 채번 규칙 실행: field + cardList의 autoGenMappings에서 코드 발급 + const allAutoGen = [ + ...(fieldMapping?.autoGenMappings ?? []), + ...(cardMapping?.autoGenMappings ?? []), + ]; + for (const ag of allAutoGen) { + if (!ag.numberingRuleId || !ag.targetColumn) continue; + if (!isSafeIdentifier(ag.targetColumn)) continue; + if (columns.includes(`"${ag.targetColumn}"`)) continue; + try { + const generatedCode = await numberingRuleService.allocateCode( + ag.numberingRuleId, + companyCode, + { ...fieldValues, ...item }, + ); + columns.push(`"${ag.targetColumn}"`); + values.push(generatedCode); + generatedCodes.push({ targetColumn: ag.targetColumn, code: generatedCode, showResultModal: ag.showResultModal ?? false }); + logger.info("[pop/execute-action] 채번 완료", { + ruleId: ag.numberingRuleId, + targetColumn: ag.targetColumn, + generatedCode, + }); + } catch (err: any) { + logger.error("[pop/execute-action] 채번 실패", { + ruleId: ag.numberingRuleId, + error: err.message, + }); + } + } + if (columns.length > 1) { const placeholders = values.map((_, i) => `$${i + 1}`).join(", "); const sql = `INSERT INTO "${cardMapping.targetTable}" (${columns.join(", ")}) VALUES (${placeholders})`; @@ -263,7 +303,7 @@ router.post("/execute-action", authenticateToken, async (req: Request, res: Resp return res.json({ success: true, message: `${processedCount}건 처리 완료${insertedCount > 0 ? `, ${insertedCount}건 생성` : ""}`, - data: { processedCount, insertedCount }, + data: { processedCount, insertedCount, generatedCodes }, }); } catch (error: any) { await client.query("ROLLBACK"); diff --git a/frontend/components/ui/select.tsx b/frontend/components/ui/select.tsx index 64fef9c4..1ebfdfed 100644 --- a/frontend/components/ui/select.tsx +++ b/frontend/components/ui/select.tsx @@ -28,7 +28,7 @@ function SelectTrigger({ size?: "xs" | "sm" | "default"; }) { // className에 h-full/h-[ 또는 style.height가 있으면 data-size 높이를 무시 - const hasCustomHeight = className?.includes("h-full") || className?.includes("h-[") || !!style?.height; + const hasCustomHeight = className?.includes("h-full") || className?.includes("h-[") || /\bh-\d/.test(className ?? "") || !!style?.height; return ( >([]); + + const handleCloseGeneratedCodesModal = useCallback(() => { + setGeneratedCodesResult([]); + toast.success("입고 확정 완료"); + publish(`__comp_output__${componentId}__action_completed`, { + action: "inbound-confirm", + success: true, + }); + const followUps = config?.followUpActions ?? []; + for (const fa of followUps) { + switch (fa.type) { + case "navigate": + if (fa.targetScreenId) { + publish("__pop_navigate__", { screenId: fa.targetScreenId, params: fa.params }); + } + break; + case "refresh": + publish("__pop_refresh__"); + break; + case "event": + if (fa.eventName) publish(fa.eventName, fa.eventPayload); + break; + } + } + }, [componentId, publish, config?.followUpActions]); // 입고 확정 모드: 선택 항목 수 수신 useEffect(() => { @@ -576,28 +602,32 @@ export function PopButtonComponent({ }); if (result.data?.success) { - toast.success(`${selectedItems.length}건 입고 확정 완료`); - publish(`__comp_output__${componentId}__action_completed`, { - action: "inbound-confirm", - success: true, - count: selectedItems.length, - }); - - // 후속 액션 실행 (navigate, refresh 등) - const followUps = config?.followUpActions ?? []; - for (const fa of followUps) { - switch (fa.type) { - case "navigate": - if (fa.targetScreenId) { - publish("__pop_navigate__", { screenId: fa.targetScreenId, params: fa.params }); - } - break; - case "refresh": - publish("__pop_refresh__"); - break; - case "event": - if (fa.eventName) publish(fa.eventName, fa.eventPayload); - break; + const codes: Array<{ targetColumn: string; code: string; showResultModal?: boolean }> = result.data.data?.generatedCodes ?? []; + const modalCodes = codes.filter((c) => c.showResultModal); + if (modalCodes.length > 0) { + setGeneratedCodesResult(modalCodes); + } else { + toast.success(`${selectedItems.length}건 입고 확정 완료`); + publish(`__comp_output__${componentId}__action_completed`, { + action: "inbound-confirm", + success: true, + count: selectedItems.length, + }); + const followUps = config?.followUpActions ?? []; + for (const fa of followUps) { + switch (fa.type) { + case "navigate": + if (fa.targetScreenId) { + publish("__pop_navigate__", { screenId: fa.targetScreenId, params: fa.params }); + } + break; + case "refresh": + publish("__pop_refresh__"); + break; + case "event": + if (fa.eventName) publish(fa.eventName, fa.eventPayload); + break; + } } } } else { @@ -811,6 +841,36 @@ export function PopButtonComponent({ + {/* 채번 결과 다이얼로그 - 사용자가 확인 누를 때까지 유지 */} + 0} onOpenChange={(open) => { if (!open) handleCloseGeneratedCodesModal(); }}> + + + + 자동 생성 완료 + + +
+

다음 번호가 자동 생성되었습니다.

+ {generatedCodesResult.map((c, i) => ( +
+ {c.targetColumn} + {c.code} +
+ ))} +
+
+
+ + + 확인 + + +
+
+ {/* 일반 확인 다이얼로그 */} { if (!open) cancelConfirm(); }}> diff --git a/frontend/lib/registry/pop-components/pop-card-list/PopCardListComponent.tsx b/frontend/lib/registry/pop-components/pop-card-list/PopCardListComponent.tsx index 4ba1abc1..0c599aab 100644 --- a/frontend/lib/registry/pop-components/pop-card-list/PopCardListComponent.tsx +++ b/frontend/lib/registry/pop-components/pop-card-list/PopCardListComponent.tsx @@ -998,12 +998,13 @@ function Card({ return 999999; }, [limitCol, row]); - // 제한 컬럼이 있으면 최대값으로 자동 초기화 + // 제한 컬럼이 있으면 최대값으로 자동 초기화 (장바구니 목록 모드에서는 cart 수량 유지) useEffect(() => { + if (isCartListMode) return; if (inputField?.enabled && limitCol && effectiveMax > 0 && effectiveMax < 999999) { setInputValue(effectiveMax); } - }, [effectiveMax, inputField?.enabled, limitCol]); + }, [effectiveMax, inputField?.enabled, limitCol, isCartListMode]); const cardStyle: React.CSSProperties = { height: `${scaled.cardHeight}px`, diff --git a/frontend/lib/registry/pop-components/pop-card-list/PopCardListConfig.tsx b/frontend/lib/registry/pop-components/pop-card-list/PopCardListConfig.tsx index 0e868711..106ad796 100644 --- a/frontend/lib/registry/pop-components/pop-card-list/PopCardListConfig.tsx +++ b/frontend/lib/registry/pop-components/pop-card-list/PopCardListConfig.tsx @@ -2784,6 +2784,13 @@ function SaveMappingSection({ label: f.label || f.columnName, badge: "본문", }); + } else if (f.valueType === "formula" && f.label) { + const formulaKey = `__formula_${f.id || f.label}`; + displayed.push({ + sourceField: formulaKey, + label: f.label, + badge: "수식", + }); } } if (inputFieldConfig?.enabled) { @@ -2855,6 +2862,21 @@ function SaveMappingSection({ [mapping.mappings] ); + // 카드에 표시된 필드가 로드되면 매핑에 누락된 필드를 자동 추가 (매핑 안함으로) + useEffect(() => { + if (!mapping.targetTable || cardDisplayedFields.length === 0) return; + const existing = new Set(mapping.mappings.map((m) => m.sourceField)); + const missing = cardDisplayedFields.filter((f) => !existing.has(f.sourceField)); + if (missing.length === 0) return; + onUpdate({ + ...mapping, + mappings: [ + ...mapping.mappings, + ...missing.map((f) => ({ sourceField: f.sourceField, targetColumn: "" })), + ], + }); + }, [cardDisplayedFields]); // eslint-disable-line react-hooks/exhaustive-deps + // 카드에 표시된 필드 중 아직 매핑되지 않은 것 const unmappedCardFields = useMemo( () => cardDisplayedFields.filter((f) => !mappedSourceFields.has(f.sourceField)), @@ -2937,7 +2959,7 @@ function SaveMappingSection({ {isCartMeta(entry.sourceField) ? ( !badge && 장바구니 - ) : ( + ) : entry.sourceField.startsWith("__formula_") ? null : ( {entry.sourceField} diff --git a/frontend/lib/registry/pop-components/pop-field/PopFieldComponent.tsx b/frontend/lib/registry/pop-components/pop-field/PopFieldComponent.tsx index c646dfd6..0fbcf6f1 100644 --- a/frontend/lib/registry/pop-components/pop-field/PopFieldComponent.tsx +++ b/frontend/lib/registry/pop-components/pop-field/PopFieldComponent.tsx @@ -211,6 +211,13 @@ export function PopFieldComponent({ columnMapping: Object.fromEntries( (cfg.saveConfig.fieldMappings || []).map((m) => [m.fieldId, m.targetColumn]) ), + autoGenMappings: (cfg.saveConfig.autoGenMappings || []) + .filter((m) => m.numberingRuleId) + .map((m) => ({ + numberingRuleId: m.numberingRuleId!, + targetColumn: m.targetColumn, + showResultModal: m.showResultModal, + })), } : null, }; @@ -585,18 +592,21 @@ function SelectFieldInput({ dataApi .getTableData(source.tableName, { page: 1, - pageSize: 500, - sortColumn: source.labelColumn, - sortDirection: "asc", + size: 500, + sortBy: source.labelColumn, + sortOrder: "asc", }) .then((res) => { - if (res.data?.success && Array.isArray(res.data.data?.data)) { - setOptions( - res.data.data.data.map((row: Record) => ({ - value: String(row[source.valueColumn!] ?? ""), - label: String(row[source.labelColumn!] ?? ""), - })) - ); + if (Array.isArray(res.data)) { + const seen = new Set(); + const deduped: { value: string; label: string }[] = []; + for (const row of res.data) { + const v = String(row[source.valueColumn!] ?? ""); + if (!v || seen.has(v)) continue; + seen.add(v); + deduped.push({ value: v, label: String(row[source.labelColumn!] ?? "") }); + } + setOptions(deduped); } }) .catch(() => { diff --git a/frontend/lib/registry/pop-components/pop-field/PopFieldConfig.tsx b/frontend/lib/registry/pop-components/pop-field/PopFieldConfig.tsx index 4a285f20..41b5ad65 100644 --- a/frontend/lib/registry/pop-components/pop-field/PopFieldConfig.tsx +++ b/frontend/lib/registry/pop-components/pop-field/PopFieldConfig.tsx @@ -74,7 +74,7 @@ import { type ColumnInfo, } from "../pop-dashboard/utils/dataFetcher"; import { dataApi } from "@/lib/api/data"; -import { getAvailableNumberingRulesForScreen } from "@/lib/api/numberingRule"; +import { getAvailableNumberingRulesForScreen, getNumberingRules } from "@/lib/api/numberingRule"; // ======================================== // Props @@ -462,6 +462,8 @@ function SaveTabContent({ // --- 자동생성 필드 로직 --- const autoGenMappings = cfg.saveConfig?.autoGenMappings ?? []; const [numberingRules, setNumberingRules] = useState<{ ruleId: string; ruleName: string }[]>([]); + const [allNumberingRules, setAllNumberingRules] = useState<{ ruleId: string; ruleName: string; tableName: string }[]>([]); + const [showAllRules, setShowAllRules] = useState(false); // 레이아웃 auto 필드 → autoGenMappings 자동 동기화 const autoFieldIdsKey = autoInputFields.map(({ field }) => field.id).join(","); @@ -478,7 +480,7 @@ function SaveTabContent({ label: field.labelText || "", targetColumn: "", numberingRuleId: field.autoNumber?.numberingRuleId ?? "", - showInForm: true, + showInForm: false, showResultModal: true, }); } @@ -513,6 +515,24 @@ function SaveTabContent({ } }, [saveTableName]); + useEffect(() => { + if (!showAllRules) return; + if (allNumberingRules.length > 0) return; + getNumberingRules() + .then((res) => { + if (res.success && Array.isArray(res.data)) { + setAllNumberingRules( + res.data.map((r: any) => ({ + ruleId: String(r.ruleId ?? r.rule_id ?? ""), + ruleName: String(r.ruleName ?? r.rule_name ?? ""), + tableName: String(r.tableName ?? r.table_name ?? ""), + })) + ); + } + }) + .catch(() => setAllNumberingRules([])); + }, [showAllRules, allNumberingRules.length]); + const addAutoGenMapping = useCallback(() => { const newMapping: PopFieldAutoGenMapping = { id: `autogen_${Date.now()}`, @@ -1248,7 +1268,19 @@ function SaveTabContent({
- +
+ +
+ + +
+
@@ -1690,12 +1730,13 @@ function FieldItemEditor({ /> )} - {/* auto 전용: 채번 설정 */} + {/* auto 전용: 저장 탭에서 채번 규칙을 연결하라는 안내 */} {field.inputType === "auto" && ( - onUpdate({ autoNumber })} - /> +
+

+ 채번 규칙은 [저장] 탭 > 자동생성 필드에서 설정합니다. +

+
)} )} @@ -1948,108 +1989,7 @@ function TableSourceEditor({ ); } -// ======================================== -// AutoNumberEditor: 자동 채번 설정 -// ======================================== - -function AutoNumberEditor({ - config, - onUpdate, -}: { - config?: AutoNumberConfig; - onUpdate: (config: AutoNumberConfig) => void; -}) { - const current: AutoNumberConfig = config || { - prefix: "", - dateFormat: "YYYYMMDD", - separator: "-", - sequenceDigits: 3, - }; - - return ( -
- - -
-
- - onUpdate({ ...current, prefix: e.target.value })} - placeholder="IN-" - className="mt-0.5 h-7 text-xs" - /> -
-
- - -
-
- -
-
- - onUpdate({ ...current, separator: e.target.value })} - placeholder="-" - className="mt-0.5 h-7 text-xs" - /> -
-
- - - onUpdate({ - ...current, - sequenceDigits: Number(e.target.value) || 3, - }) - } - min={1} - max={10} - className="mt-0.5 h-7 text-xs" - /> -
-
- - {/* 미리보기 */} -
- 미리보기:{" "} - - {current.prefix || ""} - {current.separator || ""} - {current.dateFormat === "YYMM" - ? "2602" - : current.dateFormat === "YYMMDD" - ? "260226" - : "20260226"} - {current.separator || ""} - {"0".repeat(current.sequenceDigits || 3).slice(0, -1)}1 - -
-
- ); -} +// AutoNumberEditor 삭제됨: 채번 규칙은 저장 탭 > 자동생성 필드에서 관리 // ======================================== // JsonKeySelect: JSON 키 드롭다운 (자동 추출) diff --git a/frontend/lib/registry/pop-components/types.ts b/frontend/lib/registry/pop-components/types.ts index 9dc54978..172acecd 100644 --- a/frontend/lib/registry/pop-components/types.ts +++ b/frontend/lib/registry/pop-components/types.ts @@ -638,6 +638,11 @@ export interface CollectedDataResponse { export interface SaveMapping { targetTable: string; columnMapping: Record; + autoGenMappings?: Array<{ + numberingRuleId: string; + targetColumn: string; + showResultModal?: boolean; + }>; } export interface StatusChangeRule {