테이블 컬럼추가 오류 수정
This commit is contained in:
parent
77faba7e77
commit
214bd829e9
|
|
@ -104,7 +104,7 @@ export class DDLExecutionService {
|
|||
await this.saveTableMetadata(client, tableName, description);
|
||||
|
||||
// 5-3. 컬럼 메타데이터 저장
|
||||
await this.saveColumnMetadata(client, tableName, columns);
|
||||
await this.saveColumnMetadata(client, tableName, columns, userCompanyCode);
|
||||
});
|
||||
|
||||
// 6. 성공 로그 기록
|
||||
|
|
@ -272,7 +272,7 @@ export class DDLExecutionService {
|
|||
await client.query(ddlQuery);
|
||||
|
||||
// 6-2. 컬럼 메타데이터 저장
|
||||
await this.saveColumnMetadata(client, tableName, [column]);
|
||||
await this.saveColumnMetadata(client, tableName, [column], userCompanyCode);
|
||||
});
|
||||
|
||||
// 7. 성공 로그 기록
|
||||
|
|
@ -446,7 +446,8 @@ CREATE TABLE "${tableName}" (${baseColumns},
|
|||
private async saveColumnMetadata(
|
||||
client: any,
|
||||
tableName: string,
|
||||
columns: CreateColumnDefinition[]
|
||||
columns: CreateColumnDefinition[],
|
||||
companyCode: string
|
||||
): Promise<void> {
|
||||
// 먼저 table_labels에 테이블 정보가 있는지 확인하고 없으면 생성
|
||||
await client.query(
|
||||
|
|
@ -508,19 +509,19 @@ CREATE TABLE "${tableName}" (${baseColumns},
|
|||
await client.query(
|
||||
`
|
||||
INSERT INTO table_type_columns (
|
||||
table_name, column_name, input_type, detail_settings,
|
||||
table_name, column_name, company_code, input_type, detail_settings,
|
||||
is_nullable, display_order, created_date, updated_date
|
||||
) VALUES (
|
||||
$1, $2, $3, '{}',
|
||||
'Y', $4, now(), now()
|
||||
$1, $2, $3, $4, '{}',
|
||||
'Y', $5, now(), now()
|
||||
)
|
||||
ON CONFLICT (table_name, column_name)
|
||||
ON CONFLICT (table_name, column_name, company_code)
|
||||
DO UPDATE SET
|
||||
input_type = $3,
|
||||
display_order = $4,
|
||||
input_type = $4,
|
||||
display_order = $5,
|
||||
updated_date = now()
|
||||
`,
|
||||
[tableName, defaultCol.name, defaultCol.inputType, defaultCol.order]
|
||||
[tableName, defaultCol.name, companyCode, defaultCol.inputType, defaultCol.order]
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -535,20 +536,20 @@ CREATE TABLE "${tableName}" (${baseColumns},
|
|||
await client.query(
|
||||
`
|
||||
INSERT INTO table_type_columns (
|
||||
table_name, column_name, input_type, detail_settings,
|
||||
table_name, column_name, company_code, input_type, detail_settings,
|
||||
is_nullable, display_order, created_date, updated_date
|
||||
) VALUES (
|
||||
$1, $2, $3, $4,
|
||||
'Y', $5, now(), now()
|
||||
$1, $2, $3, $4, $5,
|
||||
'Y', $6, now(), now()
|
||||
)
|
||||
ON CONFLICT (table_name, column_name)
|
||||
ON CONFLICT (table_name, column_name, company_code)
|
||||
DO UPDATE SET
|
||||
input_type = $3,
|
||||
detail_settings = $4,
|
||||
display_order = $5,
|
||||
input_type = $4,
|
||||
detail_settings = $5,
|
||||
display_order = $6,
|
||||
updated_date = now()
|
||||
`,
|
||||
[tableName, column.name, inputType, detailSettings, i]
|
||||
[tableName, column.name, companyCode, inputType, detailSettings, i]
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -36,29 +36,61 @@ export async function getSiblingMenuObjids(menuObjid: number): Promise<number[]>
|
|||
try {
|
||||
logger.debug("메뉴 스코프 조회 시작", { menuObjid });
|
||||
|
||||
// 1. 현재 메뉴 자신을 포함
|
||||
const menuObjids = [menuObjid];
|
||||
// 1. 현재 메뉴 정보 조회 (부모 ID 확인)
|
||||
const currentMenuQuery = `
|
||||
SELECT parent_obj_id FROM menu_info
|
||||
WHERE objid = $1
|
||||
`;
|
||||
const currentMenuResult = await pool.query(currentMenuQuery, [menuObjid]);
|
||||
|
||||
// 2. 현재 메뉴의 자식 메뉴들 조회
|
||||
const childrenQuery = `
|
||||
if (currentMenuResult.rows.length === 0) {
|
||||
logger.warn("메뉴를 찾을 수 없음, 자기 자신만 반환", { menuObjid });
|
||||
return [menuObjid];
|
||||
}
|
||||
|
||||
const parentObjId = Number(currentMenuResult.rows[0].parent_obj_id);
|
||||
|
||||
// 2. 최상위 메뉴(parent_obj_id = 0)는 자기 자신만 반환
|
||||
if (parentObjId === 0) {
|
||||
logger.debug("최상위 메뉴, 자기 자신만 반환", { menuObjid });
|
||||
return [menuObjid];
|
||||
}
|
||||
|
||||
// 3. 형제 메뉴들 조회 (같은 부모를 가진 메뉴들)
|
||||
const siblingsQuery = `
|
||||
SELECT objid FROM menu_info
|
||||
WHERE parent_obj_id = $1
|
||||
ORDER BY objid
|
||||
`;
|
||||
const childrenResult = await pool.query(childrenQuery, [menuObjid]);
|
||||
const siblingsResult = await pool.query(siblingsQuery, [parentObjId]);
|
||||
|
||||
const childObjids = childrenResult.rows.map((row) => Number(row.objid));
|
||||
const siblingObjids = siblingsResult.rows.map((row) => Number(row.objid));
|
||||
|
||||
// 3. 자신 + 자식을 합쳐서 정렬
|
||||
const allObjids = Array.from(new Set([...menuObjids, ...childObjids])).sort((a, b) => a - b);
|
||||
// 4. 각 형제 메뉴(자기 자신 포함)의 자식 메뉴들도 조회
|
||||
const allObjids = [...siblingObjids];
|
||||
|
||||
for (const siblingObjid of siblingObjids) {
|
||||
const childrenQuery = `
|
||||
SELECT objid FROM menu_info
|
||||
WHERE parent_obj_id = $1
|
||||
ORDER BY objid
|
||||
`;
|
||||
const childrenResult = await pool.query(childrenQuery, [siblingObjid]);
|
||||
const childObjids = childrenResult.rows.map((row) => Number(row.objid));
|
||||
allObjids.push(...childObjids);
|
||||
}
|
||||
|
||||
// 5. 중복 제거 및 정렬
|
||||
const uniqueObjids = Array.from(new Set(allObjids)).sort((a, b) => a - b);
|
||||
|
||||
logger.debug("메뉴 스코프 조회 완료", {
|
||||
menuObjid,
|
||||
childCount: childObjids.length,
|
||||
totalCount: allObjids.length
|
||||
menuObjid,
|
||||
parentObjId,
|
||||
siblingCount: siblingObjids.length,
|
||||
totalCount: uniqueObjids.length
|
||||
});
|
||||
|
||||
return allObjids;
|
||||
return uniqueObjids;
|
||||
} catch (error: any) {
|
||||
logger.error("메뉴 스코프 조회 실패", {
|
||||
menuObjid,
|
||||
|
|
|
|||
|
|
@ -179,7 +179,8 @@ class TableCategoryValueService {
|
|||
} else {
|
||||
// 일반 회사: 자신의 카테고리 값만 조회
|
||||
if (menuObjid && siblingObjids.length > 0) {
|
||||
// 메뉴 스코프 적용
|
||||
// 메뉴 스코프 적용 + created_menu_objid 필터링
|
||||
// 현재 메뉴 스코프(형제 메뉴)에서 생성된 값만 표시
|
||||
query = `
|
||||
SELECT
|
||||
value_id AS "valueId",
|
||||
|
|
@ -197,6 +198,7 @@ class TableCategoryValueService {
|
|||
is_default AS "isDefault",
|
||||
company_code AS "companyCode",
|
||||
menu_objid AS "menuObjid",
|
||||
created_menu_objid AS "createdMenuObjid",
|
||||
created_at AS "createdAt",
|
||||
updated_at AS "updatedAt",
|
||||
created_by AS "createdBy",
|
||||
|
|
@ -206,6 +208,10 @@ class TableCategoryValueService {
|
|||
AND column_name = $2
|
||||
AND menu_objid = ANY($3)
|
||||
AND company_code = $4
|
||||
AND (
|
||||
created_menu_objid = ANY($3) -- 형제 메뉴에서 생성된 값만
|
||||
OR created_menu_objid IS NULL -- 레거시 데이터 (모든 메뉴에서 보임)
|
||||
)
|
||||
`;
|
||||
params = [tableName, columnName, siblingObjids, companyCode];
|
||||
} else {
|
||||
|
|
@ -331,8 +337,8 @@ class TableCategoryValueService {
|
|||
INSERT INTO table_column_category_values (
|
||||
table_name, column_name, value_code, value_label, value_order,
|
||||
parent_value_id, depth, description, color, icon,
|
||||
is_active, is_default, company_code, menu_objid, created_by
|
||||
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15)
|
||||
is_active, is_default, company_code, menu_objid, created_menu_objid, created_by
|
||||
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16)
|
||||
RETURNING
|
||||
value_id AS "valueId",
|
||||
table_name AS "tableName",
|
||||
|
|
@ -349,6 +355,7 @@ class TableCategoryValueService {
|
|||
is_default AS "isDefault",
|
||||
company_code AS "companyCode",
|
||||
menu_objid AS "menuObjid",
|
||||
created_menu_objid AS "createdMenuObjid",
|
||||
created_at AS "createdAt",
|
||||
created_by AS "createdBy"
|
||||
`;
|
||||
|
|
@ -368,6 +375,7 @@ class TableCategoryValueService {
|
|||
value.isDefault || false,
|
||||
companyCode,
|
||||
menuObjid, // ← 메뉴 OBJID 저장
|
||||
menuObjid, // ← 🆕 생성 메뉴 OBJID 저장 (같은 값)
|
||||
userId,
|
||||
]);
|
||||
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ export function CategoryWidget({ widgetId, tableName, menuObjid, component, ...p
|
|||
const effectiveMenuObjid = menuObjid || props.menuObjid;
|
||||
|
||||
const [selectedColumn, setSelectedColumn] = useState<{
|
||||
uniqueKey: string; // 테이블명.컬럼명 형식
|
||||
columnName: string;
|
||||
columnLabel: string;
|
||||
tableName: string;
|
||||
|
|
@ -98,10 +99,12 @@ export function CategoryWidget({ widgetId, tableName, menuObjid, component, ...p
|
|||
<div style={{ width: `${leftWidth}%` }} className="pr-3">
|
||||
<CategoryColumnList
|
||||
tableName={tableName}
|
||||
selectedColumn={selectedColumn?.columnName || null}
|
||||
onColumnSelect={(columnName, columnLabel, tableName) =>
|
||||
setSelectedColumn({ columnName, columnLabel, tableName })
|
||||
}
|
||||
selectedColumn={selectedColumn?.uniqueKey || null}
|
||||
onColumnSelect={(uniqueKey, columnLabel, tableName) => {
|
||||
// uniqueKey는 "테이블명.컬럼명" 형식
|
||||
const columnName = uniqueKey.split('.')[1];
|
||||
setSelectedColumn({ uniqueKey, columnName, columnLabel, tableName });
|
||||
}}
|
||||
menuObjid={effectiveMenuObjid}
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -118,6 +121,7 @@ export function CategoryWidget({ widgetId, tableName, menuObjid, component, ...p
|
|||
<div style={{ width: `${100 - leftWidth - 1}%` }} className="pl-3">
|
||||
{selectedColumn ? (
|
||||
<CategoryValueManager
|
||||
key={selectedColumn.uniqueKey} // 테이블명.컬럼명으로 컴포넌트 재생성
|
||||
tableName={selectedColumn.tableName}
|
||||
columnName={selectedColumn.columnName}
|
||||
columnLabel={selectedColumn.columnLabel}
|
||||
|
|
|
|||
|
|
@ -147,17 +147,18 @@ export function CategoryColumnList({ tableName, selectedColumn, onColumnSelect,
|
|||
<div className="space-y-2">
|
||||
{columns.map((column) => {
|
||||
const uniqueKey = `${column.tableName}.${column.columnName}`;
|
||||
const isSelected = selectedColumn === uniqueKey; // 테이블명.컬럼명으로 비교
|
||||
return (
|
||||
<div
|
||||
key={uniqueKey}
|
||||
onClick={() => onColumnSelect(column.columnName, column.columnLabel || column.columnName, column.tableName)}
|
||||
onClick={() => onColumnSelect(uniqueKey, column.columnLabel || column.columnName, column.tableName)}
|
||||
className={`cursor-pointer rounded-lg border px-4 py-2 transition-all ${
|
||||
selectedColumn === column.columnName ? "border-primary bg-primary/10 shadow-sm" : "hover:bg-muted/50"
|
||||
isSelected ? "border-primary bg-primary/10 shadow-sm" : "hover:bg-muted/50"
|
||||
}`}
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
<FolderTree
|
||||
className={`h-4 w-4 ${selectedColumn === column.columnName ? "text-primary" : "text-muted-foreground"}`}
|
||||
className={`h-4 w-4 ${isSelected ? "text-primary" : "text-muted-foreground"}`}
|
||||
/>
|
||||
<div className="flex-1">
|
||||
<h4 className="text-sm font-semibold">{column.columnLabel || column.columnName}</h4>
|
||||
|
|
|
|||
Loading…
Reference in New Issue