diff --git a/frontend/components/common/ScreenModal.tsx b/frontend/components/common/ScreenModal.tsx index 53fd0852..0713c1c3 100644 --- a/frontend/components/common/ScreenModal.tsx +++ b/frontend/components/common/ScreenModal.tsx @@ -17,6 +17,7 @@ import { toast } from "sonner"; import { useAuth } from "@/hooks/useAuth"; import { TableOptionsProvider } from "@/contexts/TableOptionsContext"; import { TableSearchWidgetHeightProvider } from "@/contexts/TableSearchWidgetHeightContext"; +import { useSplitPanelContext } from "@/contexts/SplitPanelContext"; interface ScreenModalState { isOpen: boolean; @@ -32,6 +33,7 @@ interface ScreenModalProps { export const ScreenModal: React.FC = ({ className }) => { const { userId, userName, user } = useAuth(); + const splitPanelContext = useSplitPanelContext(); const [modalState, setModalState] = useState({ isOpen: false, @@ -152,6 +154,14 @@ export const ScreenModal: React.FC = ({ className }) => { setFormData(editData); setOriginalData(editData); // ๐Ÿ†• ์›๋ณธ ๋ฐ์ดํ„ฐ ์ €์žฅ (UPDATE ํŒ๋‹จ์šฉ) } else { + // ๐Ÿ†• ์‹ ๊ทœ ๋“ฑ๋ก ๋ชจ๋“œ: ๋ถ„ํ•  ํŒจ๋„ ๋ถ€๋ชจ ๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ์œผ๋ฉด ๋ฏธ๋ฆฌ ์„ค์ • + const parentData = splitPanelContext?.getMappedParentData() || {}; + if (Object.keys(parentData).length > 0) { + console.log("๐Ÿ”— [ScreenModal] ๋ถ„ํ•  ํŒจ๋„ ๋ถ€๋ชจ ๋ฐ์ดํ„ฐ ์ดˆ๊ธฐ๊ฐ’ ์„ค์ •:", parentData); + setFormData(parentData); + } else { + setFormData({}); + } setOriginalData(null); // ์‹ ๊ทœ ๋“ฑ๋ก ๋ชจ๋“œ } diff --git a/frontend/components/screen-embedding/ScreenSplitPanel.tsx b/frontend/components/screen-embedding/ScreenSplitPanel.tsx index 2e43fcc6..4eba4f9b 100644 --- a/frontend/components/screen-embedding/ScreenSplitPanel.tsx +++ b/frontend/components/screen-embedding/ScreenSplitPanel.tsx @@ -33,6 +33,7 @@ export function ScreenSplitPanel({ screenId, config, initialFormData }: ScreenSp leftScreenId: config?.leftScreenId, rightScreenId: config?.rightScreenId, configSplitRatio, + parentDataMapping: config?.parentDataMapping, configKeys: config ? Object.keys(config) : [], }); @@ -125,6 +126,7 @@ export function ScreenSplitPanel({ screenId, config, initialFormData }: ScreenSp splitPanelId={splitPanelId} leftScreenId={config?.leftScreenId || null} rightScreenId={config?.rightScreenId || null} + parentDataMapping={config?.parentDataMapping || []} >
{/* ์ขŒ์ธก ํŒจ๋„ */} diff --git a/frontend/contexts/SplitPanelContext.tsx b/frontend/contexts/SplitPanelContext.tsx index bfb9610b..15f3e1f5 100644 --- a/frontend/contexts/SplitPanelContext.tsx +++ b/frontend/contexts/SplitPanelContext.tsx @@ -17,6 +17,15 @@ export interface SplitPanelDataReceiver { receiveData: (data: any[], mode: "append" | "replace" | "merge") => Promise; } +/** + * ๋ถ€๋ชจ ๋ฐ์ดํ„ฐ ๋งคํ•‘ ์„ค์ • + * ์ขŒ์ธก ํ™”๋ฉด์—์„œ ์„ ํƒํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์šฐ์ธก ํ™”๋ฉด ์ €์žฅ ์‹œ ์ž๋™์œผ๋กœ ํฌํ•จ + */ +export interface ParentDataMapping { + sourceColumn: string; // ์ขŒ์ธก ํ™”๋ฉด์˜ ์ปฌ๋Ÿผ๋ช… (์˜ˆ: equipment_code) + targetColumn: string; // ์šฐ์ธก ํ™”๋ฉด ์ €์žฅ ์‹œ ์‚ฌ์šฉํ•  ์ปฌ๋Ÿผ๋ช… (์˜ˆ: equipment_code) +} + /** * ๋ถ„ํ•  ํŒจ๋„ ์ปจํ…์ŠคํŠธ ๊ฐ’ */ @@ -54,6 +63,16 @@ interface SplitPanelContextValue { addItemIds: (ids: string[]) => void; removeItemIds: (ids: string[]) => void; clearItemIds: () => void; + + // ๐Ÿ†• ์ขŒ์ธก ์„ ํƒ ๋ฐ์ดํ„ฐ ๊ด€๋ฆฌ (์šฐ์ธก ํ™”๋ฉด ์ €์žฅ ์‹œ ๋ถ€๋ชจ ํ‚ค ์ „๋‹ฌ์šฉ) + selectedLeftData: Record | null; + setSelectedLeftData: (data: Record | null) => void; + + // ๐Ÿ†• ๋ถ€๋ชจ ๋ฐ์ดํ„ฐ ๋งคํ•‘ ์„ค์ • + parentDataMapping: ParentDataMapping[]; + + // ๐Ÿ†• ๋งคํ•‘๋œ ๋ถ€๋ชจ ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ (์šฐ์ธก ํ™”๋ฉด ์ €์žฅ ์‹œ ์‚ฌ์šฉ) + getMappedParentData: () => Record; } const SplitPanelContext = createContext(null); @@ -62,6 +81,7 @@ interface SplitPanelProviderProps { splitPanelId: string; leftScreenId: number | null; rightScreenId: number | null; + parentDataMapping?: ParentDataMapping[]; // ๐Ÿ†• ๋ถ€๋ชจ ๋ฐ์ดํ„ฐ ๋งคํ•‘ ์„ค์ • children: React.ReactNode; } @@ -72,6 +92,7 @@ export function SplitPanelProvider({ splitPanelId, leftScreenId, rightScreenId, + parentDataMapping = [], children, }: SplitPanelProviderProps) { // ์ขŒ์ธก/์šฐ์ธก ํ™”๋ฉด์˜ ๋ฐ์ดํ„ฐ ์ˆ˜์‹ ์ž ๋งต @@ -83,6 +104,9 @@ export function SplitPanelProvider({ // ๐Ÿ†• ์šฐ์ธก์— ์ถ”๊ฐ€๋œ ํ•ญ๋ชฉ ID ์ƒํƒœ const [addedItemIds, setAddedItemIds] = useState>(new Set()); + + // ๐Ÿ†• ์ขŒ์ธก์—์„œ ์„ ํƒ๋œ ๋ฐ์ดํ„ฐ ์ƒํƒœ + const [selectedLeftData, setSelectedLeftData] = useState | null>(null); /** * ๋ฐ์ดํ„ฐ ์ˆ˜์‹ ์ž ๋“ฑ๋ก @@ -232,6 +256,40 @@ export function SplitPanelProvider({ logger.debug(`[SplitPanelContext] ํ•ญ๋ชฉ ID ์ดˆ๊ธฐํ™”`); }, []); + /** + * ๐Ÿ†• ์ขŒ์ธก ์„ ํƒ ๋ฐ์ดํ„ฐ ์„ค์ • + */ + const handleSetSelectedLeftData = useCallback((data: Record | null) => { + logger.info(`[SplitPanelContext] ์ขŒ์ธก ์„ ํƒ ๋ฐ์ดํ„ฐ ์„ค์ •:`, { + hasData: !!data, + dataKeys: data ? Object.keys(data) : [], + }); + setSelectedLeftData(data); + }, []); + + /** + * ๐Ÿ†• ๋งคํ•‘๋œ ๋ถ€๋ชจ ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ + * ์šฐ์ธก ํ™”๋ฉด์—์„œ ์ €์žฅ ์‹œ ์ด ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ๋ถ€๋ชจ ํ‚ค ๊ฐ’์„ ๊ฐ€์ ธ์˜ด + */ + const getMappedParentData = useCallback((): Record => { + if (!selectedLeftData || parentDataMapping.length === 0) { + return {}; + } + + const mappedData: Record = {}; + + for (const mapping of parentDataMapping) { + const value = selectedLeftData[mapping.sourceColumn]; + if (value !== undefined && value !== null) { + mappedData[mapping.targetColumn] = value; + logger.debug(`[SplitPanelContext] ๋ถ€๋ชจ ๋ฐ์ดํ„ฐ ๋งคํ•‘: ${mapping.sourceColumn} โ†’ ${mapping.targetColumn} = ${value}`); + } + } + + logger.info(`[SplitPanelContext] ๋งคํ•‘๋œ ๋ถ€๋ชจ ๋ฐ์ดํ„ฐ:`, mappedData); + return mappedData; + }, [selectedLeftData, parentDataMapping]); + // ๐Ÿ†• useMemo๋กœ value ๊ฐ์ฒด ๋ฉ”๋ชจ์ด์ œ์ด์…˜ (๋ฌดํ•œ ๋ฃจํ”„ ๋ฐฉ์ง€) const value = React.useMemo(() => ({ splitPanelId, @@ -247,6 +305,11 @@ export function SplitPanelProvider({ addItemIds, removeItemIds, clearItemIds, + // ๐Ÿ†• ์ขŒ์ธก ์„ ํƒ ๋ฐ์ดํ„ฐ ๊ด€๋ จ + selectedLeftData, + setSelectedLeftData: handleSetSelectedLeftData, + parentDataMapping, + getMappedParentData, }), [ splitPanelId, leftScreenId, @@ -260,6 +323,10 @@ export function SplitPanelProvider({ addItemIds, removeItemIds, clearItemIds, + selectedLeftData, + handleSetSelectedLeftData, + parentDataMapping, + getMappedParentData, ]); return ( diff --git a/frontend/lib/registry/components/button-primary/ButtonPrimaryComponent.tsx b/frontend/lib/registry/components/button-primary/ButtonPrimaryComponent.tsx index 180dacaa..564eed1d 100644 --- a/frontend/lib/registry/components/button-primary/ButtonPrimaryComponent.tsx +++ b/frontend/lib/registry/components/button-primary/ButtonPrimaryComponent.tsx @@ -692,6 +692,15 @@ export const ButtonPrimaryComponent: React.FC = ({ effectiveScreenId, }); + // ๐Ÿ†• ๋ถ„ํ•  ํŒจ๋„ ๋ถ€๋ชจ ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ (์šฐ์ธก ํ™”๋ฉด์—์„œ ์ €์žฅ ์‹œ ์ขŒ์ธก ์„ ํƒ ๋ฐ์ดํ„ฐ ํฌํ•จ) + let splitPanelParentData: Record | undefined; + if (splitPanelContext && splitPanelPosition === "right") { + splitPanelParentData = splitPanelContext.getMappedParentData(); + if (Object.keys(splitPanelParentData).length > 0) { + console.log("๐Ÿ”— [ButtonPrimaryComponent] ๋ถ„ํ•  ํŒจ๋„ ๋ถ€๋ชจ ๋ฐ์ดํ„ฐ ํฌํ•จ:", splitPanelParentData); + } + } + const context: ButtonActionContext = { formData: formData || {}, originalData: originalData, // ๐Ÿ”ง ๋นˆ ๊ฐ์ฒด ๋Œ€์‹  undefined ์œ ์ง€ (UPDATE ํŒ๋‹จ์— ์‚ฌ์šฉ) @@ -720,6 +729,8 @@ export const ButtonPrimaryComponent: React.FC = ({ flowSelectedStepId, // ๐Ÿ†• ์ปดํฌ๋„ŒํŠธ๋ณ„ ์„ค์ • (parentDataMapping ๋“ฑ) componentConfigs, + // ๐Ÿ†• ๋ถ„ํ•  ํŒจ๋„ ๋ถ€๋ชจ ๋ฐ์ดํ„ฐ (์ขŒ์ธก ํ™”๋ฉด์—์„œ ์„ ํƒ๋œ ๋ฐ์ดํ„ฐ) + splitPanelParentData, } as ButtonActionContext; // ํ™•์ธ์ด ํ•„์š”ํ•œ ์•ก์…˜์ธ์ง€ ํ™•์ธ diff --git a/frontend/lib/registry/components/card-display/CardDisplayComponent.tsx b/frontend/lib/registry/components/card-display/CardDisplayComponent.tsx index 0912afd7..094ddf70 100644 --- a/frontend/lib/registry/components/card-display/CardDisplayComponent.tsx +++ b/frontend/lib/registry/components/card-display/CardDisplayComponent.tsx @@ -43,6 +43,9 @@ export const CardDisplayComponent: React.FC = ({ const [loadedTableColumns, setLoadedTableColumns] = useState([]); const [loading, setLoading] = useState(false); + // ์„ ํƒ๋œ ์นด๋“œ ์ƒํƒœ + const [selectedCardId, setSelectedCardId] = useState(null); + // ์ƒ์„ธ๋ณด๊ธฐ ๋ชจ๋‹ฌ ์ƒํƒœ const [viewModalOpen, setViewModalOpen] = useState(false); const [selectedData, setSelectedData] = useState(null); @@ -261,26 +264,19 @@ export const CardDisplayComponent: React.FC = ({ borderRadius: "12px", // ์ปจํ…Œ์ด๋„ˆ ์ž์ฒด๋„ ๋ผ์šด๋“œ ์ฒ˜๋ฆฌ }; - // ์นด๋“œ ์Šคํƒ€์ผ - ํ†ต์ผ๋œ ๋””์ž์ธ ์‹œ์Šคํ…œ ์ ์šฉ + // ์นด๋“œ ์Šคํƒ€์ผ - ์ปดํŒฉํŠธํ•œ ๋””์ž์ธ const cardStyle: React.CSSProperties = { backgroundColor: "white", - border: "2px solid #e5e7eb", // ๋” ๋ช…ํ™•ํ•œ ํ…Œ๋‘๋ฆฌ - borderRadius: "12px", // ํ†ต์ผ๋œ ๋ผ์šด๋“œ ์ฒ˜๋ฆฌ - padding: "24px", // ๋” ์—ฌ์œ ๋กœ์šด ํŒจ๋”ฉ - boxShadow: "0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)", // ๋” ๊นŠ์€ ๊ทธ๋ฆผ์ž - transition: "all 0.3s cubic-bezier(0.4, 0, 0.2, 1)", // ๋ถ€๋“œ๋Ÿฌ์šด ํŠธ๋žœ์ง€์…˜ + border: "1px solid #e5e7eb", + borderRadius: "8px", + padding: "16px", + boxShadow: "0 1px 3px rgba(0, 0, 0, 0.08)", + transition: "all 0.2s ease", overflow: "hidden", display: "flex", flexDirection: "column", position: "relative", - minHeight: "240px", // ์ตœ์†Œ ๋†’์ด ๋” ์ฆ๊ฐ€ cursor: isDesignMode ? "pointer" : "default", - // ํ˜ธ๋ฒ„ ํšจ๊ณผ๋ฅผ ์œ„ํ•œ ์ถ”๊ฐ€ ์Šคํƒ€์ผ - "&:hover": { - transform: "translateY(-2px)", - boxShadow: "0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)", - borderColor: "#f59e0b", // ํ˜ธ๋ฒ„ ์‹œ ์˜ค๋ Œ์ง€ ํ…Œ๋‘๋ฆฌ - } }; // ํ…์ŠคํŠธ ์ž๋ฅด๊ธฐ ํ•จ์ˆ˜ @@ -328,6 +324,14 @@ export const CardDisplayComponent: React.FC = ({ }; const handleCardClick = (data: any) => { + const cardId = data.id || data.objid || data.ID; + // ์ด๋ฏธ ์„ ํƒ๋œ ์นด๋“œ๋ฅผ ๋‹ค์‹œ ํด๋ฆญํ•˜๋ฉด ์„ ํƒ ํ•ด์ œ + if (selectedCardId === cardId) { + setSelectedCardId(null); + } else { + setSelectedCardId(cardId); + } + if (componentConfig.onCardClick) { componentConfig.onCardClick(data); } @@ -421,67 +425,75 @@ export const CardDisplayComponent: React.FC = ({ ? getColumnValue(data, componentConfig.columnMapping.imageColumn) : data.avatar || data.image || ""; + const cardId = data.id || data.objid || data.ID || index; + const isCardSelected = selectedCardId === cardId; + return (
handleCardClick(data)} > - {/* ์นด๋“œ ์ด๋ฏธ์ง€ - ํ†ต์ผ๋œ ๋””์ž์ธ */} + {/* ์นด๋“œ ์ด๋ฏธ์ง€ */} {componentConfig.cardStyle?.showImage && componentConfig.columnMapping?.imageColumn && ( -
-
- ๐Ÿ‘ค +
+
+ ๐Ÿ‘ค
)} - {/* ์นด๋“œ ํƒ€์ดํ‹€ - ํ†ต์ผ๋œ ๋””์ž์ธ */} - {componentConfig.cardStyle?.showTitle && ( -
-

{titleValue}

+ {/* ์นด๋“œ ํƒ€์ดํ‹€ + ์„œ๋ธŒํƒ€์ดํ‹€ (๊ฐ€๋กœ ๋ฐฐ์น˜) */} + {(componentConfig.cardStyle?.showTitle || componentConfig.cardStyle?.showSubtitle) && ( +
+ {componentConfig.cardStyle?.showTitle && ( +

{titleValue}

+ )} + {componentConfig.cardStyle?.showSubtitle && subtitleValue && ( + {subtitleValue} + )}
)} - {/* ์นด๋“œ ์„œ๋ธŒํƒ€์ดํ‹€ - ํ†ต์ผ๋œ ๋””์ž์ธ */} - {componentConfig.cardStyle?.showSubtitle && ( -
-

{subtitleValue}

-
- )} - - {/* ์นด๋“œ ์„ค๋ช… - ํ†ต์ผ๋œ ๋””์ž์ธ */} + {/* ์นด๋“œ ์„ค๋ช… */} {componentConfig.cardStyle?.showDescription && ( -
-

+

+

{truncateText(descriptionValue, componentConfig.cardStyle?.maxDescriptionLength || 100)}

)} - {/* ์ถ”๊ฐ€ ํ‘œ์‹œ ์ปฌ๋Ÿผ๋“ค - ํ†ต์ผ๋œ ๋””์ž์ธ */} + {/* ์ถ”๊ฐ€ ํ‘œ์‹œ ์ปฌ๋Ÿผ๋“ค - ๊ฐ€๋กœ ๋ฐฐ์น˜ */} {componentConfig.columnMapping?.displayColumns && componentConfig.columnMapping.displayColumns.length > 0 && ( -
+
{componentConfig.columnMapping.displayColumns.map((columnName, idx) => { const value = getColumnValue(data, columnName); if (!value) return null; return ( -
- {getColumnLabel(columnName)}: - {value} +
+ {getColumnLabel(columnName)}: + {value}
); })}
)} - {/* ์นด๋“œ ์•ก์…˜ (์„ ํƒ์‚ฌํ•ญ) */} -
+ {/* ์นด๋“œ ์•ก์…˜ */} +
+
+ ))} +
+ + {/* ๋งคํ•‘ ์ถ”๊ฐ€ ๋ฒ„ํŠผ */} + + + {/* ์•ˆ๋‚ด ๋ฉ”์‹œ์ง€ */} +
+

+ ์‚ฌ์šฉ ์˜ˆ์‹œ: +
+ ์ขŒ์ธก: ์„ค๋น„ ๋ชฉ๋ก (equipment_mng) +
+ ์šฐ์ธก: ์ ๊ฒ€ํ•ญ๋ชฉ ์ถ”๊ฐ€ ํ™”๋ฉด +
+
+ ๋งคํ•‘ ์„ค์ •: +
+ - ์†Œ์Šค: equipment_code โ†’ ํƒ€๊ฒŸ: equipment_code +
+
+ ์ขŒ์ธก์—์„œ ์„ค๋น„๋ฅผ ์„ ํƒํ•˜๊ณ  ์šฐ์ธก์—์„œ ์ ๊ฒ€ํ•ญ๋ชฉ์„ ์ถ”๊ฐ€ํ•˜๋ฉด, + ์„ ํƒํ•œ ์„ค๋น„์˜ equipment_code๊ฐ€ ์ž๋™์œผ๋กœ ์ €์žฅ๋ฉ๋‹ˆ๋‹ค. +

+
+ + )} + + + {/* ์„ค์ • ์š”์•ฝ */} @@ -343,6 +534,14 @@ export function ScreenSplitPanelConfigPanel({ config = {}, onChange }: ScreenSpl ํฌ๊ธฐ ์กฐ์ ˆ: {localConfig.resizable ? "๊ฐ€๋Šฅ" : "๋ถˆ๊ฐ€๋Šฅ"}
+
+ ๋ฐ์ดํ„ฐ ๋งคํ•‘: + + {(localConfig.parentDataMapping || []).length > 0 + ? `${localConfig.parentDataMapping.length}๊ฐœ ์„ค์ •` + : "๋ฏธ์„ค์ •"} + +
diff --git a/frontend/lib/registry/components/table-list/TableListComponent.tsx b/frontend/lib/registry/components/table-list/TableListComponent.tsx index 841e6f0a..a643e3a9 100644 --- a/frontend/lib/registry/components/table-list/TableListComponent.tsx +++ b/frontend/lib/registry/components/table-list/TableListComponent.tsx @@ -1466,6 +1466,22 @@ export const TableListComponent: React.FC = ({ handleRowSelection(rowKey, !isCurrentlySelected); + // ๐Ÿ†• ๋ถ„ํ•  ํŒจ๋„ ์ปจํ…์ŠคํŠธ์— ์„ ํƒ๋œ ๋ฐ์ดํ„ฐ ์ €์žฅ (์ขŒ์ธก ํ™”๋ฉด์ธ ๊ฒฝ์šฐ) + if (splitPanelContext && splitPanelPosition === "left") { + if (!isCurrentlySelected) { + // ์„ ํƒ๋œ ๊ฒฝ์šฐ: ๋ฐ์ดํ„ฐ ์ €์žฅ + splitPanelContext.setSelectedLeftData(row); + console.log("๐Ÿ”— [TableList] ๋ถ„ํ•  ํŒจ๋„ ์ขŒ์ธก ๋ฐ์ดํ„ฐ ์ €์žฅ:", { + row, + parentDataMapping: splitPanelContext.parentDataMapping, + }); + } else { + // ์„ ํƒ ํ•ด์ œ๋œ ๊ฒฝ์šฐ: ๋ฐ์ดํ„ฐ ์ดˆ๊ธฐํ™” + splitPanelContext.setSelectedLeftData(null); + console.log("๐Ÿ”— [TableList] ๋ถ„ํ•  ํŒจ๋„ ์ขŒ์ธก ๋ฐ์ดํ„ฐ ์ดˆ๊ธฐํ™”"); + } + } + console.log("ํ–‰ ํด๋ฆญ:", { row, index, isSelected: !isCurrentlySelected }); }; diff --git a/frontend/lib/utils/buttonActions.ts b/frontend/lib/utils/buttonActions.ts index ad441754..2b8864d8 100644 --- a/frontend/lib/utils/buttonActions.ts +++ b/frontend/lib/utils/buttonActions.ts @@ -215,6 +215,9 @@ export interface ButtonActionContext { // ๐Ÿ†• ์ปดํฌ๋„ŒํŠธ๋ณ„ ์„ค์ • (parentDataMapping ๋“ฑ) componentConfigs?: Record; // ์ปดํฌ๋„ŒํŠธ ID โ†’ ์ปดํฌ๋„ŒํŠธ ์„ค์ • + + // ๐Ÿ†• ๋ถ„ํ•  ํŒจ๋„ ๋ถ€๋ชจ ๋ฐ์ดํ„ฐ (์ขŒ์ธก ํ™”๋ฉด์—์„œ ์„ ํƒ๋œ ๋ฐ์ดํ„ฐ) + splitPanelParentData?: Record; } /** @@ -502,8 +505,15 @@ export class ButtonActionExecutor { // console.log("โœ… ์ฑ„๋ฒˆ ๊ทœ์น™ ํ• ๋‹น ์™„๋ฃŒ"); // console.log("๐Ÿ“ฆ ์ตœ์ข… formData:", JSON.stringify(formData, null, 2)); + // ๐Ÿ†• ๋ถ„ํ•  ํŒจ๋„ ๋ถ€๋ชจ ๋ฐ์ดํ„ฐ ๋ณ‘ํ•ฉ (์ขŒ์ธก ํ™”๋ฉด์—์„œ ์„ ํƒ๋œ ๋ฐ์ดํ„ฐ) + const splitPanelData = context.splitPanelParentData || {}; + if (Object.keys(splitPanelData).length > 0) { + console.log("๐Ÿ”— [handleSave] ๋ถ„ํ•  ํŒจ๋„ ๋ถ€๋ชจ ๋ฐ์ดํ„ฐ ๋ณ‘ํ•ฉ:", splitPanelData); + } + const dataWithUserInfo = { - ...formData, + ...splitPanelData, // ๋ถ„ํ•  ํŒจ๋„ ๋ถ€๋ชจ ๋ฐ์ดํ„ฐ ๋จผ์ € ์ ์šฉ + ...formData, // ํผ ๋ฐ์ดํ„ฐ๊ฐ€ ์šฐ์„  (๋ฎ์–ด์“ฐ๊ธฐ ๊ฐ€๋Šฅ) writer: formData.writer || writerValue, // โœ… ์ž…๋ ฅ๊ฐ’ ์šฐ์„ , ์—†์œผ๋ฉด userId created_by: writerValue, // created_by๋Š” ํ•ญ์ƒ ๋กœ๊ทธ์ธํ•œ ์‚ฌ๋žŒ updated_by: writerValue, // updated_by๋Š” ํ•ญ์ƒ ๋กœ๊ทธ์ธํ•œ ์‚ฌ๋žŒ