feature/screen-management #55
|
|
@ -74,7 +74,10 @@ export class EntityJoinController {
|
|||
typeof screenEntityConfigs === "string"
|
||||
? JSON.parse(screenEntityConfigs)
|
||||
: screenEntityConfigs;
|
||||
logger.info("화면별 엔티티 설정 파싱 완료:", parsedScreenEntityConfigs);
|
||||
logger.info(
|
||||
"화면별 엔티티 설정 파싱 완료:",
|
||||
parsedScreenEntityConfigs
|
||||
);
|
||||
} catch (error) {
|
||||
logger.warn("화면별 엔티티 설정 파싱 오류:", error);
|
||||
parsedScreenEntityConfigs = {};
|
||||
|
|
@ -365,14 +368,16 @@ export class EntityJoinController {
|
|||
);
|
||||
|
||||
// 현재 display_column으로 사용 중인 컬럼 제외
|
||||
const currentDisplayColumn =
|
||||
config.displayColumn || config.displayColumns[0];
|
||||
const availableColumns = columns.filter(
|
||||
(col) => col.columnName !== config.displayColumn
|
||||
(col) => col.columnName !== currentDisplayColumn
|
||||
);
|
||||
|
||||
return {
|
||||
joinConfig: config,
|
||||
tableName: config.referenceTable,
|
||||
currentDisplayColumn: config.displayColumn,
|
||||
currentDisplayColumn: currentDisplayColumn,
|
||||
availableColumns: availableColumns.map((col) => ({
|
||||
columnName: col.columnName,
|
||||
columnLabel: col.displayName || col.columnName,
|
||||
|
|
@ -390,7 +395,8 @@ export class EntityJoinController {
|
|||
return {
|
||||
joinConfig: config,
|
||||
tableName: config.referenceTable,
|
||||
currentDisplayColumn: config.displayColumn,
|
||||
currentDisplayColumn:
|
||||
config.displayColumn || config.displayColumns[0],
|
||||
availableColumns: [],
|
||||
error: error instanceof Error ? error.message : "Unknown error",
|
||||
};
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ export class EntityJoinService {
|
|||
* @param screenEntityConfigs 화면별 엔티티 설정 (선택사항)
|
||||
*/
|
||||
async detectEntityJoins(
|
||||
tableName: string,
|
||||
tableName: string,
|
||||
screenEntityConfigs?: Record<string, any>
|
||||
): Promise<EntityJoinConfig[]> {
|
||||
try {
|
||||
|
|
@ -57,7 +57,7 @@ export class EntityJoinService {
|
|||
const screenConfig = screenEntityConfigs?.[column.column_name];
|
||||
let displayColumns: string[] = [];
|
||||
let separator = " - ";
|
||||
|
||||
|
||||
if (screenConfig && screenConfig.displayColumns) {
|
||||
// 화면에서 설정된 표시 컬럼들 사용
|
||||
displayColumns = screenConfig.displayColumns;
|
||||
|
|
@ -66,8 +66,11 @@ export class EntityJoinService {
|
|||
// 기존 설정된 단일 표시 컬럼 사용
|
||||
displayColumns = [column.display_column];
|
||||
} else {
|
||||
// 기본값: reference_column 사용
|
||||
displayColumns = [column.reference_column];
|
||||
// 화면에서 설정하도록 빈 배열로 초기화 (테이블 타입 관리에서 표시 컬럼 설정 제거)
|
||||
displayColumns = [];
|
||||
console.log(
|
||||
`🎯 표시 컬럼을 화면에서 설정하도록 초기화: ${column.column_name} (테이블 타입 관리에서 표시 컬럼 설정 제거됨)`
|
||||
);
|
||||
}
|
||||
|
||||
// 별칭 컬럼명 생성 (writer -> writer_name)
|
||||
|
|
@ -153,16 +156,18 @@ export class EntityJoinService {
|
|||
const joinColumns = joinConfigs
|
||||
.map((config) => {
|
||||
const alias = aliasMap.get(config.referenceTable);
|
||||
const displayColumns = config.displayColumns || [config.displayColumn];
|
||||
const displayColumns = config.displayColumns || [
|
||||
config.displayColumn,
|
||||
];
|
||||
const separator = config.separator || " - ";
|
||||
|
||||
|
||||
if (displayColumns.length === 1) {
|
||||
// 단일 컬럼인 경우
|
||||
return `COALESCE(${alias}.${displayColumns[0]}, '') AS ${config.aliasColumn}`;
|
||||
} else {
|
||||
// 여러 컬럼인 경우 CONCAT으로 연결
|
||||
const concatParts = displayColumns
|
||||
.map(col => `COALESCE(${alias}.${col}, '')`)
|
||||
.map((col) => `COALESCE(${alias}.${col}, '')`)
|
||||
.join(`, '${separator}', `);
|
||||
return `CONCAT(${concatParts}) AS ${config.aliasColumn}`;
|
||||
}
|
||||
|
|
@ -236,7 +241,7 @@ export class EntityJoinService {
|
|||
const cachedData = await referenceCacheService.getCachedReference(
|
||||
config.referenceTable,
|
||||
config.referenceColumn,
|
||||
config.displayColumn
|
||||
config.displayColumn || config.displayColumns[0]
|
||||
);
|
||||
|
||||
return cachedData ? "cache" : "join";
|
||||
|
|
|
|||
|
|
@ -2044,7 +2044,10 @@ export class TableManagementService {
|
|||
}
|
||||
|
||||
// Entity 조인 설정 감지 (화면별 엔티티 설정 전달)
|
||||
let joinConfigs = await entityJoinService.detectEntityJoins(tableName, options.screenEntityConfigs);
|
||||
let joinConfigs = await entityJoinService.detectEntityJoins(
|
||||
tableName,
|
||||
options.screenEntityConfigs
|
||||
);
|
||||
|
||||
// 추가 조인 컬럼 정보가 있으면 조인 설정에 추가
|
||||
if (
|
||||
|
|
@ -2068,8 +2071,10 @@ export class TableManagementService {
|
|||
sourceColumn: baseJoinConfig.sourceColumn, // 원본 컬럼 (writer)
|
||||
referenceTable: additionalColumn.sourceTable, // 참조 테이블 (user_info)
|
||||
referenceColumn: baseJoinConfig.referenceColumn, // 참조 키 (user_id)
|
||||
displayColumn: additionalColumn.sourceColumn, // 표시할 컬럼 (email)
|
||||
displayColumns: [additionalColumn.sourceColumn], // 표시할 컬럼들 (email)
|
||||
displayColumn: additionalColumn.sourceColumn, // 하위 호환성
|
||||
aliasColumn: additionalColumn.joinAlias, // 별칭 (writer_email)
|
||||
separator: " - ", // 기본 구분자
|
||||
};
|
||||
|
||||
joinConfigs.push(additionalJoinConfig);
|
||||
|
|
@ -2243,7 +2248,7 @@ export class TableManagementService {
|
|||
await referenceCacheService.getCachedReference(
|
||||
config.referenceTable,
|
||||
config.referenceColumn,
|
||||
config.displayColumn
|
||||
config.displayColumn || config.displayColumns[0]
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -2430,7 +2435,7 @@ export class TableManagementService {
|
|||
const lookupValue = referenceCacheService.getLookupValue(
|
||||
config.referenceTable,
|
||||
config.referenceColumn,
|
||||
config.displayColumn,
|
||||
config.displayColumn || config.displayColumns[0],
|
||||
String(sourceValue)
|
||||
);
|
||||
|
||||
|
|
@ -2724,7 +2729,7 @@ export class TableManagementService {
|
|||
const cachedData = await referenceCacheService.getCachedReference(
|
||||
config.referenceTable,
|
||||
config.referenceColumn,
|
||||
config.displayColumn
|
||||
config.displayColumn || config.displayColumns[0]
|
||||
);
|
||||
|
||||
if (cachedData && cachedData.size > 0) {
|
||||
|
|
@ -2808,7 +2813,7 @@ export class TableManagementService {
|
|||
const cachedData = await referenceCacheService.getCachedReference(
|
||||
config.referenceTable,
|
||||
config.referenceColumn,
|
||||
config.displayColumn
|
||||
config.displayColumn || config.displayColumns[0]
|
||||
);
|
||||
|
||||
if (cachedData) {
|
||||
|
|
@ -2847,7 +2852,7 @@ export class TableManagementService {
|
|||
const hitRate = referenceCacheService.getCacheHitRate(
|
||||
config.referenceTable,
|
||||
config.referenceColumn,
|
||||
config.displayColumn
|
||||
config.displayColumn || config.displayColumns[0]
|
||||
);
|
||||
totalHitRate += hitRate;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -171,7 +171,7 @@ export const EntityTypeConfigPanel: React.FC<EntityTypeConfigPanelProps> = ({ co
|
|||
{/* 표시 컬럼들 (다중 선택) */}
|
||||
<div className="space-y-3">
|
||||
<Label className="text-sm font-medium">표시 컬럼들</Label>
|
||||
|
||||
|
||||
{/* 현재 선택된 표시 컬럼들 */}
|
||||
<div className="space-y-2">
|
||||
{localValues.displayColumns.map((column, index) => (
|
||||
|
|
@ -183,7 +183,7 @@ export const EntityTypeConfigPanel: React.FC<EntityTypeConfigPanelProps> = ({ co
|
|||
</Button>
|
||||
</div>
|
||||
))}
|
||||
|
||||
|
||||
{localValues.displayColumns.length === 0 && (
|
||||
<div className="text-sm text-gray-500 italic">표시할 컬럼을 추가해주세요</div>
|
||||
)}
|
||||
|
|
@ -197,20 +197,19 @@ export const EntityTypeConfigPanel: React.FC<EntityTypeConfigPanelProps> = ({ co
|
|||
placeholder="컬럼명 입력 (예: user_name, dept_name)"
|
||||
className="flex-1"
|
||||
/>
|
||||
<Button
|
||||
size="sm"
|
||||
onClick={addDisplayColumn}
|
||||
<Button
|
||||
size="sm"
|
||||
onClick={addDisplayColumn}
|
||||
disabled={!newDisplayColumn.trim() || localValues.displayColumns.includes(newDisplayColumn.trim())}
|
||||
>
|
||||
<Plus className="h-3 w-3 mr-1" />
|
||||
<Plus className="mr-1 h-3 w-3" />
|
||||
추가
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
|
||||
<div className="text-xs text-gray-500">
|
||||
• 여러 컬럼을 선택하면 "{localValues.separator || ' - '}"로 구분하여 표시됩니다
|
||||
<br />
|
||||
• 예: 이름{localValues.separator || ' - '}부서명
|
||||
• 여러 컬럼을 선택하면 "{localValues.separator || " - "}"로 구분하여 표시됩니다
|
||||
<br />• 예: 이름{localValues.separator || " - "}부서명
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -261,7 +260,6 @@ export const EntityTypeConfigPanel: React.FC<EntityTypeConfigPanelProps> = ({ co
|
|||
/>
|
||||
</div>
|
||||
|
||||
|
||||
{/* 필터 관리 */}
|
||||
<div className="space-y-3">
|
||||
<Label className="text-sm font-medium">데이터 필터</Label>
|
||||
|
|
@ -328,7 +326,10 @@ export const EntityTypeConfigPanel: React.FC<EntityTypeConfigPanelProps> = ({ co
|
|||
<div className="mt-2 text-xs text-gray-500">
|
||||
참조테이블: {localValues.referenceTable || "없음"}, 조인컬럼: {localValues.referenceColumn}
|
||||
<br />
|
||||
표시컬럼: {localValues.displayColumns.length > 0 ? localValues.displayColumns.join(localValues.separator || ' - ') : "없음"}
|
||||
표시컬럼:{" "}
|
||||
{localValues.displayColumns.length > 0
|
||||
? localValues.displayColumns.join(localValues.separator || " - ")
|
||||
: "없음"}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -337,14 +338,11 @@ export const EntityTypeConfigPanel: React.FC<EntityTypeConfigPanelProps> = ({ co
|
|||
<div className="text-sm font-medium text-blue-900">엔터티 타입 설정 가이드</div>
|
||||
<div className="mt-1 text-xs text-blue-800">
|
||||
• <strong>참조 테이블</strong>: 데이터를 가져올 다른 테이블 이름
|
||||
<br />
|
||||
• <strong>조인 컬럼</strong>: 테이블 간 연결에 사용할 기준 컬럼 (보통 ID)
|
||||
<br />
|
||||
• <strong>표시 컬럼</strong>: 사용자에게 보여질 컬럼들 (여러 개 가능)
|
||||
<br />• <strong>조인 컬럼</strong>: 테이블 간 연결에 사용할 기준 컬럼 (보통 ID)
|
||||
<br />• <strong>표시 컬럼</strong>: 사용자에게 보여질 컬럼들 (여러 개 가능)
|
||||
<br />
|
||||
• 여러 표시 컬럼 설정 시 화면마다 다르게 표시할 수 있습니다
|
||||
<br />
|
||||
• 예: 사용자 선택 시 "이름"만 보이거나 "이름 - 부서명" 형태로 표시
|
||||
<br />• 예: 사용자 선택 시 "이름"만 보이거나 "이름 - 부서명" 형태로 표시
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ export const entityJoinApi = {
|
|||
sourceColumn: string;
|
||||
joinAlias: string;
|
||||
}>;
|
||||
screenEntityConfigs?: Record<string, any>; // 🎯 화면별 엔티티 설정
|
||||
} = {},
|
||||
): Promise<EntityJoinResponse> => {
|
||||
const searchParams = new URLSearchParams();
|
||||
|
|
@ -93,6 +94,7 @@ export const entityJoinApi = {
|
|||
...params,
|
||||
search: params.search ? JSON.stringify(params.search) : undefined,
|
||||
additionalJoinColumns: params.additionalJoinColumns ? JSON.stringify(params.additionalJoinColumns) : undefined,
|
||||
screenEntityConfigs: params.screenEntityConfigs ? JSON.stringify(params.screenEntityConfigs) : undefined, // 🎯 화면별 엔티티 설정
|
||||
},
|
||||
});
|
||||
return response.data.data;
|
||||
|
|
|
|||
|
|
@ -192,12 +192,12 @@ export const TableListComponent: React.FC<TableListComponentProps> = ({
|
|||
// 🎯 Entity 조인된 컬럼의 경우 표시 컬럼명 사용
|
||||
let displayLabel = column.displayName || column.columnName;
|
||||
|
||||
// Entity 타입이고 display_column이 있는 경우
|
||||
if (column.webType === "entity" && column.displayColumn) {
|
||||
// 백엔드에서 받은 displayColumnLabel을 사용하거나, 없으면 displayColumn 사용
|
||||
displayLabel = column.displayColumnLabel || column.displayColumn;
|
||||
// Entity 타입인 경우
|
||||
if (column.webType === "entity") {
|
||||
// 백엔드에서 받은 displayColumnLabel을 사용하거나, 없으면 기본값 사용
|
||||
displayLabel = column.displayColumnLabel || column.displayColumn || `${column.columnName}_name`;
|
||||
console.log(
|
||||
`🎯 Entity 조인 컬럼 라벨 설정: ${column.columnName} → "${displayLabel}" (${column.displayColumn})`,
|
||||
`🎯 Entity 조인 컬럼 라벨 설정: ${column.columnName} → "${displayLabel}" (${column.displayColumn || "기본값"})`,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -260,7 +260,20 @@ export const TableListComponent: React.FC<TableListComponentProps> = ({
|
|||
joinAlias: col.entityJoinInfo!.joinAlias,
|
||||
}));
|
||||
|
||||
// 🎯 화면별 엔티티 표시 설정 생성
|
||||
const screenEntityConfigs: Record<string, any> = {};
|
||||
entityJoinColumns.forEach((col) => {
|
||||
if (col.entityDisplayConfig) {
|
||||
const sourceColumn = col.entityJoinInfo!.sourceColumn;
|
||||
screenEntityConfigs[sourceColumn] = {
|
||||
displayColumns: col.entityDisplayConfig.displayColumns,
|
||||
separator: col.entityDisplayConfig.separator || " - ",
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
console.log("🔗 추가 Entity 조인 컬럼:", additionalJoinColumns);
|
||||
console.log("🎯 화면별 엔티티 설정:", screenEntityConfigs);
|
||||
|
||||
const result = await entityJoinApi.getTableDataWithJoins(tableConfig.selectedTable, {
|
||||
page: currentPage,
|
||||
|
|
@ -329,6 +342,7 @@ export const TableListComponent: React.FC<TableListComponentProps> = ({
|
|||
sortOrder: sortDirection,
|
||||
enableEntityJoin: true, // 🎯 Entity 조인 활성화
|
||||
additionalJoinColumns: additionalJoinColumns.length > 0 ? additionalJoinColumns : undefined, // 추가 조인 컬럼
|
||||
screenEntityConfigs: Object.keys(screenEntityConfigs).length > 0 ? screenEntityConfigs : undefined, // 🎯 화면별 엔티티 설정
|
||||
});
|
||||
|
||||
if (result) {
|
||||
|
|
|
|||
|
|
@ -58,8 +58,17 @@ export const TableListConfigPanel: React.FC<TableListConfigPanelProps> = ({
|
|||
}>;
|
||||
}>;
|
||||
}>({ availableColumns: [], joinTables: [] });
|
||||
|
||||
const [loadingEntityJoins, setLoadingEntityJoins] = useState(false);
|
||||
|
||||
// 🎯 엔티티 컬럼 표시 설정을 위한 상태
|
||||
const [entityDisplayConfigs, setEntityDisplayConfigs] = useState<Record<string, {
|
||||
sourceColumns: Array<{ columnName: string; displayName: string; dataType: string }>;
|
||||
joinColumns: Array<{ columnName: string; displayName: string; dataType: string }>;
|
||||
selectedColumns: string[];
|
||||
separator: string;
|
||||
}>>({});
|
||||
|
||||
// 화면 테이블명이 있으면 자동으로 설정
|
||||
useEffect(() => {
|
||||
if (screenTableName && (!config.selectedTable || config.selectedTable !== screenTableName)) {
|
||||
|
|
@ -228,30 +237,38 @@ export const TableListConfigPanel: React.FC<TableListConfigPanelProps> = ({
|
|||
handleChange("columns", [...(config.columns || []), newColumn]);
|
||||
};
|
||||
|
||||
// Entity 조인 컬럼 추가
|
||||
const addEntityJoinColumn = (joinColumn: (typeof entityJoinColumns.availableColumns)[0]) => {
|
||||
// 🎯 엔티티 컬럼 추가 (컬럼 설정 패널에서 표시 컬럼 선택)
|
||||
const addEntityColumn = (joinColumn: (typeof entityJoinColumns.availableColumns)[0]) => {
|
||||
const existingColumn = config.columns?.find((col) => col.columnName === joinColumn.joinAlias);
|
||||
if (existingColumn) return;
|
||||
|
||||
// 기본 표시명으로 엔티티 컬럼 추가 (컬럼 설정 패널에서 나중에 표시 컬럼 조합 선택)
|
||||
const newColumn: ColumnConfig = {
|
||||
columnName: joinColumn.joinAlias,
|
||||
displayName: joinColumn.columnLabel, // 라벨명만 사용
|
||||
displayName: joinColumn.columnLabel,
|
||||
visible: true,
|
||||
sortable: true,
|
||||
searchable: true,
|
||||
align: "left",
|
||||
format: "text",
|
||||
order: config.columns?.length || 0,
|
||||
isEntityJoin: true, // Entity 조인 컬럼임을 표시
|
||||
isEntityJoin: true,
|
||||
entityJoinInfo: {
|
||||
sourceTable: joinColumn.tableName,
|
||||
sourceTable: config.selectedTable || "",
|
||||
sourceColumn: joinColumn.columnName,
|
||||
joinAlias: joinColumn.joinAlias,
|
||||
},
|
||||
// 🎯 엔티티 표시 설정 (기본값으로 초기화, 컬럼 설정에서 수정 가능)
|
||||
entityDisplayConfig: {
|
||||
displayColumns: [], // 빈 배열로 초기화
|
||||
separator: " - ",
|
||||
sourceTable: config.selectedTable || "",
|
||||
joinTable: joinColumn.tableName,
|
||||
},
|
||||
};
|
||||
|
||||
handleChange("columns", [...(config.columns || []), newColumn]);
|
||||
console.log("🔗 Entity 조인 컬럼 추가됨:", newColumn);
|
||||
console.log("🔗 엔티티 컬럼 추가됨 (표시 컬럼은 컬럼 설정에서 선택):", newColumn);
|
||||
};
|
||||
|
||||
// 컬럼 제거
|
||||
|
|
@ -267,6 +284,90 @@ export const TableListConfigPanel: React.FC<TableListConfigPanelProps> = ({
|
|||
handleChange("columns", updatedColumns);
|
||||
};
|
||||
|
||||
// 🎯 엔티티 컬럼의 표시 컬럼 정보 로드
|
||||
const loadEntityDisplayConfig = async (column: ColumnConfig) => {
|
||||
if (!column.isEntityJoin || !column.entityJoinInfo || !column.entityDisplayConfig) return;
|
||||
|
||||
const { sourceTable, joinTable } = column.entityDisplayConfig;
|
||||
const configKey = `${column.columnName}`;
|
||||
|
||||
// 이미 로드된 경우 스킵
|
||||
if (entityDisplayConfigs[configKey]) return;
|
||||
|
||||
try {
|
||||
// 기본 테이블과 조인 테이블의 컬럼 정보를 병렬로 로드
|
||||
const [sourceResult, joinResult] = await Promise.all([
|
||||
entityJoinApi.getReferenceTableColumns(sourceTable),
|
||||
entityJoinApi.getReferenceTableColumns(joinTable),
|
||||
]);
|
||||
|
||||
const sourceColumns = sourceResult.columns || [];
|
||||
const joinColumns = joinResult.columns || [];
|
||||
|
||||
setEntityDisplayConfigs(prev => ({
|
||||
...prev,
|
||||
[configKey]: {
|
||||
sourceColumns,
|
||||
joinColumns,
|
||||
selectedColumns: column.entityDisplayConfig?.displayColumns || [],
|
||||
separator: column.entityDisplayConfig?.separator || " - ",
|
||||
},
|
||||
}));
|
||||
} catch (error) {
|
||||
console.error("엔티티 표시 컬럼 정보 로드 실패:", error);
|
||||
}
|
||||
};
|
||||
|
||||
// 🎯 엔티티 표시 컬럼 선택 토글
|
||||
const toggleEntityDisplayColumn = (columnName: string, selectedColumn: string) => {
|
||||
const configKey = `${columnName}`;
|
||||
const config = entityDisplayConfigs[configKey];
|
||||
if (!config) return;
|
||||
|
||||
const newSelectedColumns = config.selectedColumns.includes(selectedColumn)
|
||||
? config.selectedColumns.filter(col => col !== selectedColumn)
|
||||
: [...config.selectedColumns, selectedColumn];
|
||||
|
||||
setEntityDisplayConfigs(prev => ({
|
||||
...prev,
|
||||
[configKey]: {
|
||||
...prev[configKey],
|
||||
selectedColumns: newSelectedColumns,
|
||||
},
|
||||
}));
|
||||
|
||||
// 컬럼 설정 업데이트
|
||||
updateColumn(columnName, {
|
||||
entityDisplayConfig: {
|
||||
...config.entityDisplayConfig,
|
||||
displayColumns: newSelectedColumns,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
// 🎯 엔티티 표시 구분자 업데이트
|
||||
const updateEntityDisplaySeparator = (columnName: string, separator: string) => {
|
||||
const configKey = `${columnName}`;
|
||||
const config = entityDisplayConfigs[configKey];
|
||||
if (!config) return;
|
||||
|
||||
setEntityDisplayConfigs(prev => ({
|
||||
...prev,
|
||||
[configKey]: {
|
||||
...prev[configKey],
|
||||
separator,
|
||||
},
|
||||
}));
|
||||
|
||||
// 컬럼 설정 업데이트
|
||||
updateColumn(columnName, {
|
||||
entityDisplayConfig: {
|
||||
...config.entityDisplayConfig,
|
||||
separator,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
// 컬럼 순서 변경
|
||||
const moveColumn = (columnName: string, direction: "up" | "down") => {
|
||||
const columns = [...(config.columns || [])];
|
||||
|
|
@ -820,6 +921,108 @@ export const TableListConfigPanel: React.FC<TableListConfigPanelProps> = ({
|
|||
/>
|
||||
</div>
|
||||
|
||||
{/* 🎯 엔티티 타입 컬럼일 때 표시 컬럼 선택 UI */}
|
||||
{column.isEntityJoin && column.entityDisplayConfig && (
|
||||
<div className="col-span-2 space-y-2">
|
||||
<div className="flex items-center justify-between">
|
||||
<Label className="text-xs font-medium">표시 컬럼 조합</Label>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => loadEntityDisplayConfig(column)}
|
||||
className="h-6 text-xs"
|
||||
>
|
||||
<Plus className="h-3 w-3 mr-1" />
|
||||
컬럼 로드
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{entityDisplayConfigs[column.columnName] && (
|
||||
<div className="space-y-3">
|
||||
{/* 구분자 설정 */}
|
||||
<div className="space-y-1">
|
||||
<Label className="text-xs">구분자</Label>
|
||||
<Input
|
||||
value={entityDisplayConfigs[column.columnName].separator}
|
||||
onChange={(e) => updateEntityDisplaySeparator(column.columnName, e.target.value)}
|
||||
className="h-7 text-xs"
|
||||
placeholder=" - "
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* 기본 테이블 컬럼 */}
|
||||
<div className="space-y-1">
|
||||
<Label className="text-xs text-blue-600">
|
||||
기본 테이블: {column.entityDisplayConfig.sourceTable}
|
||||
</Label>
|
||||
<div className="grid grid-cols-2 gap-1 max-h-20 overflow-y-auto">
|
||||
{entityDisplayConfigs[column.columnName].sourceColumns.map((col) => (
|
||||
<div key={col.columnName} className="flex items-center space-x-1">
|
||||
<Checkbox
|
||||
id={`source-${column.columnName}-${col.columnName}`}
|
||||
checked={entityDisplayConfigs[column.columnName].selectedColumns.includes(col.columnName)}
|
||||
onCheckedChange={() => toggleEntityDisplayColumn(column.columnName, col.columnName)}
|
||||
className="h-3 w-3"
|
||||
/>
|
||||
<Label
|
||||
htmlFor={`source-${column.columnName}-${col.columnName}`}
|
||||
className="text-xs cursor-pointer flex-1"
|
||||
>
|
||||
{col.displayName}
|
||||
</Label>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 조인 테이블 컬럼 */}
|
||||
<div className="space-y-1">
|
||||
<Label className="text-xs text-green-600">
|
||||
조인 테이블: {column.entityDisplayConfig.joinTable}
|
||||
</Label>
|
||||
<div className="grid grid-cols-2 gap-1 max-h-20 overflow-y-auto">
|
||||
{entityDisplayConfigs[column.columnName].joinColumns.map((col) => (
|
||||
<div key={col.columnName} className="flex items-center space-x-1">
|
||||
<Checkbox
|
||||
id={`join-${column.columnName}-${col.columnName}`}
|
||||
checked={entityDisplayConfigs[column.columnName].selectedColumns.includes(col.columnName)}
|
||||
onCheckedChange={() => toggleEntityDisplayColumn(column.columnName, col.columnName)}
|
||||
className="h-3 w-3"
|
||||
/>
|
||||
<Label
|
||||
htmlFor={`join-${column.columnName}-${col.columnName}`}
|
||||
className="text-xs cursor-pointer flex-1"
|
||||
>
|
||||
{col.displayName}
|
||||
</Label>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 선택된 컬럼 미리보기 */}
|
||||
{entityDisplayConfigs[column.columnName].selectedColumns.length > 0 && (
|
||||
<div className="space-y-1">
|
||||
<Label className="text-xs">미리보기</Label>
|
||||
<div className="flex flex-wrap gap-1 rounded bg-gray-50 p-2 text-xs">
|
||||
{entityDisplayConfigs[column.columnName].selectedColumns.map((colName, idx) => (
|
||||
<React.Fragment key={colName}>
|
||||
<Badge variant="secondary" className="text-xs">
|
||||
{colName}
|
||||
</Badge>
|
||||
{idx < entityDisplayConfigs[column.columnName].selectedColumns.length - 1 && (
|
||||
<span className="text-gray-400">{entityDisplayConfigs[column.columnName].separator}</span>
|
||||
)}
|
||||
</React.Fragment>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="space-y-1">
|
||||
<Label className="text-xs">정렬</Label>
|
||||
<Select
|
||||
|
|
@ -1018,7 +1221,7 @@ export const TableListConfigPanel: React.FC<TableListConfigPanelProps> = ({
|
|||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
onClick={() => addEntityJoinColumn(matchingJoinColumn)}
|
||||
onClick={() => addEntityColumn(matchingJoinColumn)}
|
||||
className="text-xs"
|
||||
>
|
||||
<Plus className="mr-1 h-3 w-3" />
|
||||
|
|
@ -1057,7 +1260,7 @@ export const TableListConfigPanel: React.FC<TableListConfigPanelProps> = ({
|
|||
key={index}
|
||||
variant={isAlreadyAdded ? "secondary" : "outline"}
|
||||
className="cursor-pointer text-xs"
|
||||
onClick={() => !isAlreadyAdded && addEntityJoinColumn(column)}
|
||||
onClick={() => !isAlreadyAdded && addEntityColumn(column)}
|
||||
>
|
||||
{column.columnLabel}
|
||||
{!isAlreadyAdded && <Plus className="ml-1 h-2 w-2" />}
|
||||
|
|
@ -1325,6 +1528,7 @@ export const TableListConfigPanel: React.FC<TableListConfigPanelProps> = ({
|
|||
</ScrollArea>
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -57,6 +57,14 @@ export interface ColumnConfig {
|
|||
isEntityJoin?: boolean; // Entity 조인된 컬럼인지 여부
|
||||
entityJoinInfo?: EntityJoinInfo; // Entity 조인 상세 정보
|
||||
|
||||
// 🎯 엔티티 컬럼 표시 설정 (화면별 동적 설정)
|
||||
entityDisplayConfig?: {
|
||||
displayColumns: string[]; // 표시할 컬럼들 (기본 테이블 + 조인 테이블)
|
||||
separator?: string; // 구분자 (기본: " - ")
|
||||
sourceTable?: string; // 기본 테이블명
|
||||
joinTable?: string; // 조인 테이블명
|
||||
};
|
||||
|
||||
// 컬럼 고정 관련 속성
|
||||
fixed?: "left" | "right" | false; // 컬럼 고정 위치 (왼쪽, 오른쪽, 고정 안함)
|
||||
fixedOrder?: number; // 고정된 컬럼들 내에서의 순서
|
||||
|
|
|
|||
|
|
@ -197,7 +197,7 @@ export interface EntityTypeConfig {
|
|||
searchColumns?: string[];
|
||||
filters?: Record<string, unknown>;
|
||||
placeholder?: string;
|
||||
displayFormat?: 'simple' | 'detailed' | 'custom'; // 표시 형식
|
||||
displayFormat?: "simple" | "detailed" | "custom"; // 표시 형식
|
||||
separator?: string; // 여러 컬럼 표시 시 구분자 (기본: ' - ')
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue