diff --git a/backend-node/src/controllers/numberingRuleController.ts b/backend-node/src/controllers/numberingRuleController.ts index d00db2c4..55c19353 100644 --- a/backend-node/src/controllers/numberingRuleController.ts +++ b/backend-node/src/controllers/numberingRuleController.ts @@ -27,7 +27,7 @@ router.get("/available/:menuObjid?", authenticateToken, async (req: Authenticate const companyCode = req.user!.companyCode; const menuObjid = req.params.menuObjid ? parseInt(req.params.menuObjid) : undefined; - logger.info("๐Ÿ“ฅ ๋ฉ”๋‰ด๋ณ„ ์ฑ„๋ฒˆ ๊ทœ์น™ ์กฐํšŒ ์š”์ฒญ", { companyCode, menuObjid }); + logger.info("๋ฉ”๋‰ด๋ณ„ ์ฑ„๋ฒˆ ๊ทœ์น™ ์กฐํšŒ ์š”์ฒญ", { menuObjid, companyCode }); try { const rules = await numberingRuleService.getAvailableRulesForMenu(companyCode, menuObjid); diff --git a/backend-node/src/services/menuService.ts b/backend-node/src/services/menuService.ts index 9a9be99c..b22beb88 100644 --- a/backend-node/src/services/menuService.ts +++ b/backend-node/src/services/menuService.ts @@ -8,71 +8,59 @@ import { logger } from "../utils/logger"; */ /** - * ๋ฉ”๋‰ด์˜ ํ˜•์ œ ๋ฉ”๋‰ด OBJID ๋ชฉ๋ก ์กฐํšŒ - * (๊ฐ™์€ ๋ถ€๋ชจ๋ฅผ ๊ฐ€์ง„ ๋ฉ”๋‰ด๋“ค) + * ๋ฉ”๋‰ด์˜ ํ˜•์ œ ๋ฉ”๋‰ด ๋ฐ ์ž์‹ ๋ฉ”๋‰ด OBJID ๋ชฉ๋ก ์กฐํšŒ + * (๊ฐ™์€ ๋ถ€๋ชจ๋ฅผ ๊ฐ€์ง„ ๋ฉ”๋‰ด๋“ค + ์ž์‹ ๋ฉ”๋‰ด๋“ค) * * ๋ฉ”๋‰ด ์Šค์ฝ”ํ”„ ๊ทœ์น™: * - ๊ฐ™์€ ๋ถ€๋ชจ๋ฅผ ๊ฐ€์ง„ ํ˜•์ œ ๋ฉ”๋‰ด๋“ค์€ ์นดํ…Œ๊ณ ๋ฆฌ/์ฑ„๋ฒˆ๊ทœ์น™์„ ๊ณต์œ  + * - ์ž์‹ ๋ฉ”๋‰ด์˜ ๋ฐ์ดํ„ฐ๋„ ๋ถ€๋ชจ ๋ฉ”๋‰ด์—์„œ ์กฐํšŒ ๊ฐ€๋Šฅ (3๋ ˆ๋ฒจ๊นŒ์ง€๋งŒ ์กด์žฌ) * - ์ตœ์ƒ์œ„ ๋ฉ”๋‰ด(parent_obj_id = 0)๋Š” ์ž๊ธฐ ์ž์‹ ๋งŒ ๋ฐ˜ํ™˜ * - ๋ฉ”๋‰ด๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์œผ๋ฉด ์•ˆ์ „ํ•˜๊ฒŒ ์ž๊ธฐ ์ž์‹ ๋งŒ ๋ฐ˜ํ™˜ * * @param menuObjid ํ˜„์žฌ ๋ฉ”๋‰ด์˜ OBJID - * @returns ํ˜•์ œ ๋ฉ”๋‰ด OBJID ๋ฐฐ์—ด (์ž๊ธฐ ์ž์‹  ํฌํ•จ, ์ •๋ ฌ๋จ) + * @returns ํ˜•์ œ ๋ฉ”๋‰ด + ์ž์‹ ๋ฉ”๋‰ด OBJID ๋ฐฐ์—ด (์ž๊ธฐ ์ž์‹  ํฌํ•จ, ์ •๋ ฌ๋จ) * * @example * // ์˜์—…๊ด€๋ฆฌ (200) * // โ”œโ”€โ”€ ๊ณ ๊ฐ๊ด€๋ฆฌ (201) + * // โ”‚ โ””โ”€โ”€ ๊ณ ๊ฐ๋“ฑ๋ก (211) * // โ”œโ”€โ”€ ๊ณ„์•ฝ๊ด€๋ฆฌ (202) * // โ””โ”€โ”€ ์ฃผ๋ฌธ๊ด€๋ฆฌ (203) * * await getSiblingMenuObjids(201); - * // ๊ฒฐ๊ณผ: [201, 202, 203] - ๋ชจ๋‘ ๊ฐ™์€ ๋ถ€๋ชจ(200)๋ฅผ ๊ฐ€์ง„ ํ˜•์ œ + * // ๊ฒฐ๊ณผ: [201, 202, 203, 211] - ํ˜•์ œ(202, 203) + ์ž์‹(211) */ export async function getSiblingMenuObjids(menuObjid: number): Promise { const pool = getPool(); try { - logger.info("ํ˜•์ œ ๋ฉ”๋‰ด ์กฐํšŒ ์‹œ์ž‘", { menuObjid }); + logger.debug("๋ฉ”๋‰ด ์Šค์ฝ”ํ”„ ์กฐํšŒ ์‹œ์ž‘", { menuObjid }); - // 1. ํ˜„์žฌ ๋ฉ”๋‰ด์˜ ๋ถ€๋ชจ ์ฐพ๊ธฐ - const parentQuery = ` - SELECT parent_obj_id FROM menu_info WHERE objid = $1 - `; - const parentResult = await pool.query(parentQuery, [menuObjid]); + // 1. ํ˜„์žฌ ๋ฉ”๋‰ด ์ž์‹ ์„ ํฌํ•จ + const menuObjids = [menuObjid]; - if (parentResult.rows.length === 0) { - logger.warn("๋ฉ”๋‰ด๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Œ, ์ž๊ธฐ ์ž์‹ ๋งŒ ๋ฐ˜ํ™˜", { menuObjid }); - return [menuObjid]; // ๋ฉ”๋‰ด๊ฐ€ ์—†์œผ๋ฉด ์•ˆ์ „ํ•˜๊ฒŒ ์ž๊ธฐ ์ž์‹ ๋งŒ ๋ฐ˜ํ™˜ - } - - const parentObjId = parentResult.rows[0].parent_obj_id; - - if (!parentObjId || parentObjId === 0) { - // ์ตœ์ƒ์œ„ ๋ฉ”๋‰ด์ธ ๊ฒฝ์šฐ ์ž๊ธฐ ์ž์‹ ๋งŒ ๋ฐ˜ํ™˜ - logger.info("์ตœ์ƒ์œ„ ๋ฉ”๋‰ด (ํ˜•์ œ ์—†์Œ)", { menuObjid, parentObjId }); - return [menuObjid]; - } - - // 2. ๊ฐ™์€ ๋ถ€๋ชจ๋ฅผ ๊ฐ€์ง„ ํ˜•์ œ ๋ฉ”๋‰ด๋“ค ์กฐํšŒ - const siblingsQuery = ` + // 2. ํ˜„์žฌ ๋ฉ”๋‰ด์˜ ์ž์‹ ๋ฉ”๋‰ด๋“ค ์กฐํšŒ + const childrenQuery = ` SELECT objid FROM menu_info - WHERE parent_obj_id = $1 + WHERE parent_obj_id = $1 ORDER BY objid `; - const siblingsResult = await pool.query(siblingsQuery, [parentObjId]); + const childrenResult = await pool.query(childrenQuery, [menuObjid]); - const siblingObjids = siblingsResult.rows.map((row) => Number(row.objid)); + const childObjids = childrenResult.rows.map((row) => Number(row.objid)); - logger.info("ํ˜•์ œ ๋ฉ”๋‰ด ์กฐํšŒ ์™„๋ฃŒ", { - menuObjid, - parentObjId, - siblingCount: siblingObjids.length, - siblings: siblingObjids, + // 3. ์ž์‹  + ์ž์‹์„ ํ•ฉ์ณ์„œ ์ •๋ ฌ + const allObjids = Array.from(new Set([...menuObjids, ...childObjids])).sort((a, b) => a - b); + + logger.debug("๋ฉ”๋‰ด ์Šค์ฝ”ํ”„ ์กฐํšŒ ์™„๋ฃŒ", { + menuObjid, + childCount: childObjids.length, + totalCount: allObjids.length }); - return siblingObjids; + return allObjids; } catch (error: any) { - logger.error("ํ˜•์ œ ๋ฉ”๋‰ด ์กฐํšŒ ์‹คํŒจ", { + logger.error("๋ฉ”๋‰ด ์Šค์ฝ”ํ”„ ์กฐํšŒ ์‹คํŒจ", { menuObjid, error: error.message, stack: error.stack diff --git a/backend-node/src/services/numberingRuleService.ts b/backend-node/src/services/numberingRuleService.ts index 4fb27e52..db76bbee 100644 --- a/backend-node/src/services/numberingRuleService.ts +++ b/backend-node/src/services/numberingRuleService.ts @@ -360,7 +360,7 @@ class NumberingRuleService { const result = await pool.query(query, params); - logger.info("โœ… ์ฑ„๋ฒˆ ๊ทœ์น™ ์ฟผ๋ฆฌ ์„ฑ๊ณต", { rowCount: result.rows.length }); + logger.debug("์ฑ„๋ฒˆ ๊ทœ์น™ ์ฟผ๋ฆฌ ์„ฑ๊ณต", { ruleCount: result.rows.length }); // ํŒŒํŠธ ์ •๋ณด ์ถ”๊ฐ€ for (const rule of result.rows) { diff --git a/backend-node/src/services/screenManagementService.ts b/backend-node/src/services/screenManagementService.ts index 50e62420..85081cd3 100644 --- a/backend-node/src/services/screenManagementService.ts +++ b/backend-node/src/services/screenManagementService.ts @@ -1565,7 +1565,7 @@ export class ScreenManagementService { WHERE sma.screen_id = $1 AND sma.company_code = $2 AND sma.is_active = 'Y' - ORDER BY sma.created_at ASC + ORDER BY sma.created_date ASC LIMIT 1`, [screenId, companyCode] ); diff --git a/frontend/lib/registry/components/text-input/TextInputConfigPanel.tsx b/frontend/lib/registry/components/text-input/TextInputConfigPanel.tsx index 817baf57..69088e96 100644 --- a/frontend/lib/registry/components/text-input/TextInputConfigPanel.tsx +++ b/frontend/lib/registry/components/text-input/TextInputConfigPanel.tsx @@ -29,7 +29,12 @@ export const TextInputConfigPanel: React.FC = ({ conf // ๋ถ€๋ชจ ๋ฉ”๋‰ด ๋ชฉ๋ก ์ƒํƒœ (์ฑ„๋ฒˆ๊ทœ์น™ ์‚ฌ์šฉ์„ ์œ„ํ•œ ์„ ํƒ) const [parentMenus, setParentMenus] = useState([]); - const [selectedMenuObjid, setSelectedMenuObjid] = useState(menuObjid); + + // useState ์ดˆ๊ธฐ๊ฐ’์—์„œ ์ €์žฅ๋œ ๊ฐ’ ๋ณต์› (์šฐ์„ ์ˆœ์œ„: ์ €์žฅ๋œ ๊ฐ’ > menuObjid prop) + const [selectedMenuObjid, setSelectedMenuObjid] = useState(() => { + return config.autoGeneration?.selectedMenuObjid || menuObjid; + }); + const [loadingMenus, setLoadingMenus] = useState(false); // ๋ถ€๋ชจ ๋ฉ”๋‰ด ๋ชฉ๋ก ๋กœ๋“œ (์‚ฌ์šฉ์ž ๋ฉ”๋‰ด์˜ ๋ ˆ๋ฒจ 2๋งŒ) @@ -49,7 +54,6 @@ export const TextInputConfigPanel: React.FC = ({ conf ); setParentMenus(level2UserMenus); - console.log("โœ… ๋ถ€๋ชจ ๋ฉ”๋‰ด ๋กœ๋“œ ์™„๋ฃŒ:", level2UserMenus.length, "๊ฐœ", level2UserMenus); } } catch (error) { console.error("๋ถ€๋ชจ ๋ฉ”๋‰ด ๋กœ๋“œ ์‹คํŒจ:", error); @@ -63,21 +67,23 @@ export const TextInputConfigPanel: React.FC = ({ conf // ์ฑ„๋ฒˆ ๊ทœ์น™ ๋ชฉ๋ก ๋กœ๋“œ (์„ ํƒ๋œ ๋ฉ”๋‰ด ๊ธฐ์ค€) useEffect(() => { const loadRules = async () => { + // autoGeneration.type์ด numbering_rule์ด ์•„๋‹ˆ๋ฉด ๋กœ๋“œํ•˜์ง€ ์•Š์Œ + if (config.autoGeneration?.type !== "numbering_rule") { + return; + } + // ๋ฉ”๋‰ด๊ฐ€ ์„ ํƒ๋˜์ง€ ์•Š์•˜์œผ๋ฉด ๋กœ๋“œํ•˜์ง€ ์•Š์Œ if (!selectedMenuObjid) { - console.log("โš ๏ธ ๋ฉ”๋‰ด๊ฐ€ ์„ ํƒ๋˜์ง€ ์•Š์•„ ์ฑ„๋ฒˆ ๊ทœ์น™์„ ๋กœ๋“œํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค"); setNumberingRules([]); return; } setLoadingRules(true); try { - console.log("๐Ÿ” ์„ ํƒ๋œ ๋ฉ”๋‰ด ๊ธฐ๋ฐ˜ ์ฑ„๋ฒˆ ๊ทœ์น™ ๋กœ๋“œ", { selectedMenuObjid }); const response = await getAvailableNumberingRules(selectedMenuObjid); if (response.success && response.data) { setNumberingRules(response.data); - console.log("โœ… ์ฑ„๋ฒˆ ๊ทœ์น™ ๋กœ๋“œ ์™„๋ฃŒ:", response.data.length, "๊ฐœ"); } } catch (error) { console.error("์ฑ„๋ฒˆ ๊ทœ์น™ ๋ชฉ๋ก ๋กœ๋“œ ์‹คํŒจ:", error); @@ -87,11 +93,8 @@ export const TextInputConfigPanel: React.FC = ({ conf } }; - // autoGeneration.type์ด numbering_rule์ผ ๋•Œ๋งŒ ๋กœ๋“œ - if (config.autoGeneration?.type === "numbering_rule") { - loadRules(); - } - }, [config.autoGeneration?.type, selectedMenuObjid]); + loadRules(); + }, [selectedMenuObjid, config.autoGeneration?.type]); const handleChange = (key: keyof TextInputConfig, value: any) => { onChange({ [key]: value }); @@ -202,7 +205,12 @@ export const TextInputConfigPanel: React.FC = ({ conf onValueChange={(value) => { const menuObjid = parseInt(value); setSelectedMenuObjid(menuObjid); - console.log("โœ… ๋ฉ”๋‰ด ์„ ํƒ๋จ:", menuObjid); + + // ์ปดํฌ๋„ŒํŠธ ์„ค์ •์— ์ €์žฅํ•˜์—ฌ ์–ธ๋งˆ์šดํŠธ ์‹œ์—๋„ ์œ ์ง€ + handleChange("autoGeneration", { + ...config.autoGeneration, + selectedMenuObjid: menuObjid, + }); }} disabled={loadingMenus} > diff --git a/frontend/lib/utils/getComponentConfigPanel.tsx b/frontend/lib/utils/getComponentConfigPanel.tsx index 9093a480..b4af1632 100644 --- a/frontend/lib/utils/getComponentConfigPanel.tsx +++ b/frontend/lib/utils/getComponentConfigPanel.tsx @@ -107,6 +107,7 @@ export interface ComponentConfigPanelProps { screenTableName?: string; // ํ™”๋ฉด์—์„œ ์ง€์ •ํ•œ ํ…Œ์ด๋ธ”๋ช… tableColumns?: any[]; // ํ…Œ์ด๋ธ” ์ปฌ๋Ÿผ ์ •๋ณด tables?: any[]; // ์ „์ฒด ํ…Œ์ด๋ธ” ๋ชฉ๋ก + menuObjid?: number; // ๐Ÿ†• ๋ฉ”๋‰ด OBJID (์ฝ”๋“œ/์นดํ…Œ๊ณ ๋ฆฌ/์ฑ„๋ฒˆ๊ทœ์น™ ์Šค์ฝ”ํ”„์šฉ) } export const DynamicComponentConfigPanel: React.FC = ({ @@ -116,6 +117,7 @@ export const DynamicComponentConfigPanel: React.FC = screenTableName, tableColumns, tables, + menuObjid, }) => { // ๋ชจ๋“  useState๋ฅผ ์ตœ์ƒ๋‹จ์— ์„ ์–ธ (Hooks ๊ทœ์น™) const [ConfigPanelComponent, setConfigPanelComponent] = React.useState | null>(null); @@ -259,6 +261,7 @@ export const DynamicComponentConfigPanel: React.FC = tables={tables} // ๊ธฐ๋ณธ ํ…Œ์ด๋ธ” ๋ชฉ๋ก (ํ˜„์žฌ ํ™”๋ฉด์˜ ํ…Œ์ด๋ธ”๋งŒ) allTables={componentId === "repeater-field-group" ? allTablesList : tables} // RepeaterConfigPanel๋งŒ ์ „์ฒด ํ…Œ์ด๋ธ” onTableChange={handleTableChange} // ํ…Œ์ด๋ธ” ๋ณ€๊ฒฝ ํ•ธ๋“ค๋Ÿฌ ์ „๋‹ฌ + menuObjid={menuObjid} // ๐Ÿ†• ๋ฉ”๋‰ด OBJID ์ „๋‹ฌ /> ); };