diff --git a/frontend/components/screen/EditModal.tsx b/frontend/components/screen/EditModal.tsx index b3c94ade..7c722ad6 100644 --- a/frontend/components/screen/EditModal.tsx +++ b/frontend/components/screen/EditModal.tsx @@ -309,17 +309,10 @@ export const EditModal: React.FC = ({ className }) => { // ๐Ÿ†• ๊ทธ๋ฃน ๋ฐ์ดํ„ฐ ์กฐํšŒ ํ•จ์ˆ˜ const loadGroupData = async () => { if (!modalState.tableName || !modalState.groupByColumns || modalState.groupByColumns.length === 0) { - // console.warn("ํ…Œ์ด๋ธ”๋ช… ๋˜๋Š” ๊ทธ๋ฃนํ•‘ ์ปฌ๋Ÿผ์ด ์—†์Šต๋‹ˆ๋‹ค."); return; } try { - // console.log("๐Ÿ” ๊ทธ๋ฃน ๋ฐ์ดํ„ฐ ์กฐํšŒ ์‹œ์ž‘:", { - // tableName: modalState.tableName, - // groupByColumns: modalState.groupByColumns, - // editData: modalState.editData, - // }); - // ๊ทธ๋ฃนํ•‘ ์ปฌ๋Ÿผ ๊ฐ’ ์ถ”์ถœ (์˜ˆ: order_no = "ORD-20251124-001") const groupValues: Record = {}; modalState.groupByColumns.forEach((column) => { @@ -329,15 +322,9 @@ export const EditModal: React.FC = ({ className }) => { }); if (Object.keys(groupValues).length === 0) { - // console.warn("๊ทธ๋ฃนํ•‘ ์ปฌ๋Ÿผ ๊ฐ’์ด ์—†์Šต๋‹ˆ๋‹ค:", modalState.groupByColumns); return; } - // console.log("๐Ÿ” ๊ทธ๋ฃน ์กฐํšŒ ์š”์ฒญ:", { - // tableName: modalState.tableName, - // groupValues, - // }); - // ๊ฐ™์€ ๊ทธ๋ฃน์˜ ๋ชจ๋“  ๋ ˆ์ฝ”๋“œ ์กฐํšŒ (entityJoinApi ์‚ฌ์šฉ) const { entityJoinApi } = await import("@/lib/api/entityJoin"); const response = await entityJoinApi.getTableDataWithJoins(modalState.tableName, { @@ -347,23 +334,19 @@ export const EditModal: React.FC = ({ className }) => { enableEntityJoin: true, }); - // console.log("๐Ÿ” ๊ทธ๋ฃน ์กฐํšŒ ์‘๋‹ต:", response); - // entityJoinApi๋Š” ๋ฐฐ์—ด ๋˜๋Š” { data: [] } ํ˜•์‹์œผ๋กœ ๋ฐ˜ํ™˜ const dataArray = Array.isArray(response) ? response : response?.data || []; if (dataArray.length > 0) { - // console.log("โœ… ๊ทธ๋ฃน ๋ฐ์ดํ„ฐ ์กฐํšŒ ์„ฑ๊ณต:", dataArray.length, "๊ฑด"); setGroupData(dataArray); setOriginalGroupData(JSON.parse(JSON.stringify(dataArray))); // Deep copy toast.info(`${dataArray.length}๊ฐœ์˜ ๊ด€๋ จ ํ’ˆ๋ชฉ์„ ๋ถˆ๋Ÿฌ์™”์Šต๋‹ˆ๋‹ค.`); } else { - console.warn("๊ทธ๋ฃน ๋ฐ์ดํ„ฐ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค:", response); setGroupData([modalState.editData]); // ๊ธฐ๋ณธ๊ฐ’: ์„ ํƒ๋œ ํ–‰๋งŒ setOriginalGroupData([JSON.parse(JSON.stringify(modalState.editData))]); } } catch (error: any) { - console.error("โŒ ๊ทธ๋ฃน ๋ฐ์ดํ„ฐ ์กฐํšŒ ์˜ค๋ฅ˜:", error); + console.error("๊ทธ๋ฃน ๋ฐ์ดํ„ฐ ์กฐํšŒ ์˜ค๋ฅ˜:", error); toast.error("๊ด€๋ จ ๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๋Š” ์ค‘ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค."); setGroupData([modalState.editData]); // ๊ธฐ๋ณธ๊ฐ’: ์„ ํƒ๋œ ํ–‰๋งŒ setOriginalGroupData([JSON.parse(JSON.stringify(modalState.editData))]); @@ -1043,17 +1026,18 @@ export const EditModal: React.FC = ({ className }) => { const groupedDataProp = groupData.length > 0 ? groupData : undefined; // ๐Ÿ†• UniversalFormModal์ด ์žˆ๋Š”์ง€ ํ™•์ธ (์ž์ฒด ์ €์žฅ ๋กœ์ง ์‚ฌ์šฉ) - // ์ตœ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ ๋˜๋Š” ์กฐ๊ฑด๋ถ€ ์ปจํ…Œ์ด๋„ˆ ๋‚ด๋ถ€ ํ™”๋ฉด์— universal-form-modal์ด ์žˆ๋Š”์ง€ ํ™•์ธ + // ์ตœ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ์— universal-form-modal์ด ์žˆ๋Š”์ง€ ํ™•์ธ + // โš ๏ธ ์ˆ˜์ •: conditional-container๋Š” ์ œ์™ธ (groupData๊ฐ€ ์žˆ์œผ๋ฉด EditModal.handleSave ์‚ฌ์šฉ) const hasUniversalFormModal = screenData.components.some( (c) => { - // ์ตœ์ƒ์œ„์— universal-form-modal์ด ์žˆ๋Š” ๊ฒฝ์šฐ + // ์ตœ์ƒ์œ„์— universal-form-modal์ด ์žˆ๋Š” ๊ฒฝ์šฐ๋งŒ ์ž์ฒด ์ €์žฅ ๋กœ์ง ์‚ฌ์šฉ if (c.componentType === "universal-form-modal") return true; - // ์กฐ๊ฑด๋ถ€ ์ปจํ…Œ์ด๋„ˆ ๋‚ด๋ถ€์— universal-form-modal์ด ์žˆ๋Š” ๊ฒฝ์šฐ - // (์กฐ๊ฑด๋ถ€ ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์žˆ์œผ๋ฉด ๋‚ด๋ถ€ ํ™”๋ฉด์—์„œ universal-form-modal์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์œผ๋กœ ๊ฐ€์ •) - if (c.componentType === "conditional-container") return true; return false; } ); + + // ๐Ÿ†• ๊ทธ๋ฃน ๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ์œผ๋ฉด EditModal.handleSave ์‚ฌ์šฉ (์ผ๊ด„ ์ €์žฅ) + const shouldUseEditModalSave = groupData.length > 0 || !hasUniversalFormModal; // ๐Ÿ”‘ ์ฒจ๋ถ€ํŒŒ์ผ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ํ–‰(๋ ˆ์ฝ”๋“œ) ๋‹จ์œ„๋กœ ํŒŒ์ผ์„ ์ €์žฅํ•  ์ˆ˜ ์žˆ๋„๋ก tableName ์ถ”๊ฐ€ const enrichedFormData = { @@ -1095,9 +1079,9 @@ export const EditModal: React.FC = ({ className }) => { id: modalState.screenId!, tableName: screenData.screenInfo?.tableName, }} - // ๐Ÿ†• UniversalFormModal์ด ์žˆ์œผ๋ฉด onSave ์ „๋‹ฌ ์•ˆ ํ•จ (์ž์ฒด ์ €์žฅ ๋กœ์ง ์‚ฌ์šฉ) - // ModalRepeaterTable๋งŒ ์žˆ์œผ๋ฉด ๊ธฐ์กด๋Œ€๋กœ onSave ์ „๋‹ฌ (ํ˜ธํ™˜์„ฑ ์œ ์ง€) - onSave={hasUniversalFormModal ? undefined : handleSave} + // ๐Ÿ†• ๊ทธ๋ฃน ๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ๊ฑฐ๋‚˜ UniversalFormModal์ด ์—†์œผ๋ฉด EditModal.handleSave ์‚ฌ์šฉ + // groupData๊ฐ€ ์žˆ์œผ๋ฉด ์ผ๊ด„ ์ €์žฅ์„ ์œ„ํ•ด ๋ฐ˜๋“œ์‹œ EditModal.handleSave ์‚ฌ์šฉ + onSave={shouldUseEditModalSave ? handleSave : undefined} isInModal={true} // ๐Ÿ†• ๊ทธ๋ฃน ๋ฐ์ดํ„ฐ๋ฅผ ModalRepeaterTable์— ์ „๋‹ฌ groupedData={groupedDataProp} diff --git a/frontend/lib/registry/components/modal-repeater-table/ModalRepeaterTableComponent.tsx b/frontend/lib/registry/components/modal-repeater-table/ModalRepeaterTableComponent.tsx index 2caf1332..153cebdf 100644 --- a/frontend/lib/registry/components/modal-repeater-table/ModalRepeaterTableComponent.tsx +++ b/frontend/lib/registry/components/modal-repeater-table/ModalRepeaterTableComponent.tsx @@ -180,8 +180,11 @@ export function ModalRepeaterTableComponent({ filterCondition: propFilterCondition, companyCode: propCompanyCode, + // ๐Ÿ†• ๊ทธ๋ฃน ๋ฐ์ดํ„ฐ (EditModal์—์„œ ์ „๋‹ฌ, ๊ฐ™์€ ๊ทธ๋ฃน์˜ ์—ฌ๋Ÿฌ ํ’ˆ๋ชฉ) + groupedData, + ...props -}: ModalRepeaterTableComponentProps) { +}: ModalRepeaterTableComponentProps & { groupedData?: Record[] }) { // โœ… config ๋˜๋Š” component.config ๋˜๋Š” ๊ฐœ๋ณ„ prop ์šฐ์„ ์ˆœ์œ„๋กœ ๋ณ‘ํ•ฉ const componentConfig = { ...config, @@ -208,9 +211,16 @@ export function ModalRepeaterTableComponent({ // ๋ชจ๋‹ฌ ํ•„ํ„ฐ ์„ค์ • const modalFilters = componentConfig?.modalFilters || []; - // โœ… value๋Š” formData[columnName] ์šฐ์„ , ์—†์œผ๋ฉด prop ์‚ฌ์šฉ + // โœ… value๋Š” groupedData ์šฐ์„ , ์—†์œผ๋ฉด formData[columnName], ์—†์œผ๋ฉด prop ์‚ฌ์šฉ const columnName = component?.columnName; - const externalValue = (columnName && formData?.[columnName]) || componentConfig?.value || propValue || []; + + // ๐Ÿ†• groupedData๊ฐ€ ์ „๋‹ฌ๋˜๋ฉด (EditModal์—์„œ ๊ทธ๋ฃน ์กฐํšŒ ๊ฒฐ๊ณผ) ์šฐ์„  ์‚ฌ์šฉ + const externalValue = (() => { + if (groupedData && groupedData.length > 0) { + return groupedData; + } + return (columnName && formData?.[columnName]) || componentConfig?.value || propValue || []; + })(); // ๋นˆ ๊ฐ์ฒด ํŒ๋‹จ ํ•จ์ˆ˜ (์ˆ˜์ • ๋ชจ๋‹ฌ์˜ ์‹ค์ œ ๋ฐ์ดํ„ฐ๋Š” ์œ ์ง€) const isEmptyRow = (item: any): boolean => { diff --git a/frontend/lib/registry/components/split-panel-layout/SplitPanelLayoutComponent.tsx b/frontend/lib/registry/components/split-panel-layout/SplitPanelLayoutComponent.tsx index cbc7ea4f..50f7c41b 100644 --- a/frontend/lib/registry/components/split-panel-layout/SplitPanelLayoutComponent.tsx +++ b/frontend/lib/registry/components/split-panel-layout/SplitPanelLayoutComponent.tsx @@ -80,7 +80,14 @@ export const SplitPanelLayoutComponent: React.FC // "ํ…Œ์ด๋ธ”๋ช….์ปฌ๋Ÿผ๋ช…" ํ˜•์‹์„ "์›๋ณธ์ปฌ๋Ÿผ_์กฐ์ธ์ปฌ๋Ÿผ๋ช…" ํ˜•์‹์œผ๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ๋ฐ์ดํ„ฐ ์ ‘๊ทผ const getEntityJoinValue = useCallback( (item: any, columnName: string, entityColumnMap?: Record): any => { - // ์ง์ ‘ ๋งค์นญ ์‹œ๋„ + // ๐Ÿ†• ๋ฐฑ์—”๋“œ๊ฐ€ ์ œ๊ณตํ•˜๋Š” _label ํ•„๋“œ ์šฐ์„  ์‚ฌ์šฉ + // ๋ฐฑ์—”๋“œ๋Š” "ํ‘œ์‹œ ์ปฌ๋Ÿผ"์ด ์„ค์ •๋œ ๊ฒฝ์šฐ columnName_label์„ ์ž๋™ ์ƒ์„ฑ + const labelKey = `${columnName}_label`; + if (item[labelKey] !== undefined && item[labelKey] !== "" && item[labelKey] !== null) { + return item[labelKey]; + } + + // ์ง์ ‘ ๋งค์นญ ์‹œ๋„ (JOIN๋œ ๊ฐ’์ด ์—†์œผ๋ฉด ์›๋ณธ ๊ฐ’ ๋ฐ˜ํ™˜) if (item[columnName] !== undefined) { return item[columnName]; } diff --git a/frontend/lib/utils/buttonActions.ts b/frontend/lib/utils/buttonActions.ts index a54850ee..debf58b2 100644 --- a/frontend/lib/utils/buttonActions.ts +++ b/frontend/lib/utils/buttonActions.ts @@ -708,6 +708,47 @@ export class ButtonActionExecutor { if (repeaterJsonKeys.length > 0) { console.log("๐Ÿ”„ [handleSave] RepeaterFieldGroup JSON ๋ฌธ์ž์—ด ๊ฐ์ง€:", repeaterJsonKeys); + // ๐ŸŽฏ ์ฑ„๋ฒˆ ๊ทœ์น™ ํ• ๋‹น ์ฒ˜๋ฆฌ (RepeaterFieldGroup ์ €์žฅ ์ „์— ์‹คํ–‰) + console.log("๐Ÿ” [handleSave-RepeaterFieldGroup] ์ฑ„๋ฒˆ ๊ทœ์น™ ํ• ๋‹น ์ฒดํฌ ์‹œ์ž‘"); + + const fieldsWithNumberingRepeater: Record = {}; + + // formData์—์„œ ์ฑ„๋ฒˆ ๊ทœ์น™์ด ์„ค์ •๋œ ํ•„๋“œ ์ฐพ๊ธฐ + for (const [key, value] of Object.entries(context.formData)) { + if (key.endsWith("_numberingRuleId") && value) { + const fieldName = key.replace("_numberingRuleId", ""); + fieldsWithNumberingRepeater[fieldName] = value as string; + console.log(`๐ŸŽฏ [handleSave-RepeaterFieldGroup] ์ฑ„๋ฒˆ ํ•„๋“œ ๋ฐœ๊ฒฌ: ${fieldName} โ†’ ๊ทœ์น™ ${value}`); + } + } + + console.log("๐Ÿ“‹ [handleSave-RepeaterFieldGroup] ์ฑ„๋ฒˆ ๊ทœ์น™์ด ์„ค์ •๋œ ํ•„๋“œ:", fieldsWithNumberingRepeater); + + // ์ฑ„๋ฒˆ ๊ทœ์น™์ด ์žˆ๋Š” ํ•„๋“œ์— ๋Œ€ํ•ด allocateCode ํ˜ธ์ถœ + if (Object.keys(fieldsWithNumberingRepeater).length > 0) { + console.log("๐ŸŽฏ [handleSave-RepeaterFieldGroup] ์ฑ„๋ฒˆ ๊ทœ์น™ ํ• ๋‹น ์‹œ์ž‘ (allocateCode ํ˜ธ์ถœ)"); + const { allocateNumberingCode } = await import("@/lib/api/numberingRule"); + + for (const [fieldName, ruleId] of Object.entries(fieldsWithNumberingRepeater)) { + try { + console.log(`๐Ÿ”„ [handleSave-RepeaterFieldGroup] ${fieldName} ํ•„๋“œ์— ๋Œ€ํ•ด allocateCode ํ˜ธ์ถœ: ${ruleId}`); + const allocateResult = await allocateNumberingCode(ruleId); + + if (allocateResult.success && allocateResult.data?.generatedCode) { + const newCode = allocateResult.data.generatedCode; + console.log(`โœ… [handleSave-RepeaterFieldGroup] ${fieldName} ์ƒˆ ์ฝ”๋“œ ํ• ๋‹น: ${context.formData[fieldName]} โ†’ ${newCode}`); + context.formData[fieldName] = newCode; + } else { + console.warn(`โš ๏ธ [handleSave-RepeaterFieldGroup] ${fieldName} ์ฝ”๋“œ ํ• ๋‹น ์‹คํŒจ:`, allocateResult.error); + } + } catch (allocateError) { + console.error(`โŒ [handleSave-RepeaterFieldGroup] ${fieldName} ์ฝ”๋“œ ํ• ๋‹น ์˜ค๋ฅ˜:`, allocateError); + } + } + } + + console.log("โœ… [handleSave-RepeaterFieldGroup] ์ฑ„๋ฒˆ ๊ทœ์น™ ํ• ๋‹น ์™„๋ฃŒ"); + // ๐Ÿ†• ์ƒ๋‹จ ํผ ๋ฐ์ดํ„ฐ(๋งˆ์Šคํ„ฐ ์ •๋ณด) ์ถ”์ถœ // RepeaterFieldGroup JSON๊ณผ ์ปดํฌ๋„ŒํŠธ ํ‚ค๋ฅผ ์ œ์™ธํ•œ ๋‚˜๋จธ์ง€๊ฐ€ ๋งˆ์Šคํ„ฐ ์ •๋ณด const masterFields: Record = {};