feat(UniversalFormModal): 전용 API 저장 기능 및 사원+부서 통합 저장 API 구현
- CustomApiSaveConfig 타입 정의 (apiType, mainDeptFields, subDeptFields) - saveWithCustomApi() 함수 추가로 테이블 직접 저장 대신 전용 API 호출 - adminController에 saveUserWithDept(), getUserWithDept() API 추가 - user_info + user_dept 트랜잭션 저장, 메인 부서 변경 시 자동 겸직 전환 - ConfigPanel에 전용 API 저장 설정 UI 추가 - SplitPanelLayout2: getColumnValue()로 조인 테이블 컬럼 값 추출 개선 - 검색 컬럼 선택 시 표시 컬럼 기반으로 변경
This commit is contained in:
@@ -200,7 +200,11 @@ export const SplitPanelLayout2Component: React.FC<SplitPanelLayout2ComponentProp
|
||||
// 선택된 컬럼만 병합
|
||||
const mergedItem = { ...item };
|
||||
joinConfig.selectColumns.forEach((col) => {
|
||||
// alias가 있으면 alias_컬럼명, 없으면 그냥 컬럼명
|
||||
// 조인 테이블명.컬럼명 형식으로 저장 (sourceTable 참조용)
|
||||
const tableColumnKey = `${joinConfig.joinTable}.${col}`;
|
||||
mergedItem[tableColumnKey] = joinRow[col];
|
||||
|
||||
// alias가 있으면 alias_컬럼명, 없으면 그냥 컬럼명으로도 저장 (하위 호환성)
|
||||
const targetKey = joinConfig.alias ? `${joinConfig.alias}_${col}` : col;
|
||||
// 메인 테이블에 같은 컬럼이 없으면 추가
|
||||
if (!(col in mergedItem)) {
|
||||
@@ -210,6 +214,7 @@ export const SplitPanelLayout2Component: React.FC<SplitPanelLayout2ComponentProp
|
||||
mergedItem[targetKey] = joinRow[col];
|
||||
}
|
||||
});
|
||||
console.log(`[SplitPanelLayout2] 조인 데이터 병합:`, { mainKey: joinKey, mergedKeys: Object.keys(mergedItem) });
|
||||
return mergedItem;
|
||||
}
|
||||
|
||||
@@ -738,6 +743,37 @@ export const SplitPanelLayout2Component: React.FC<SplitPanelLayout2ComponentProp
|
||||
};
|
||||
}, [screenContext, component.id]);
|
||||
|
||||
// 컬럼 값 가져오기 (sourceTable 고려)
|
||||
const getColumnValue = useCallback((item: any, col: ColumnConfig): any => {
|
||||
// col.name이 "테이블명.컬럼명" 형식인 경우 처리
|
||||
const actualColName = col.name.includes(".") ? col.name.split(".")[1] : col.name;
|
||||
const tableFromName = col.name.includes(".") ? col.name.split(".")[0] : null;
|
||||
const effectiveSourceTable = col.sourceTable || tableFromName;
|
||||
|
||||
// sourceTable이 설정되어 있고, 메인 테이블이 아닌 경우
|
||||
if (effectiveSourceTable && effectiveSourceTable !== config.rightPanel?.tableName) {
|
||||
// 1. 테이블명.컬럼명 형식으로 먼저 시도 (mergeJoinData에서 저장한 형식)
|
||||
const tableColumnKey = `${effectiveSourceTable}.${actualColName}`;
|
||||
if (item[tableColumnKey] !== undefined) {
|
||||
return item[tableColumnKey];
|
||||
}
|
||||
// 2. 조인 테이블의 alias가 설정된 경우 alias_컬럼명으로 시도
|
||||
const joinTable = config.rightPanel?.joinTables?.find(jt => jt.joinTable === effectiveSourceTable);
|
||||
if (joinTable?.alias) {
|
||||
const aliasKey = `${joinTable.alias}_${actualColName}`;
|
||||
if (item[aliasKey] !== undefined) {
|
||||
return item[aliasKey];
|
||||
}
|
||||
}
|
||||
// 3. 그냥 컬럼명으로 시도 (메인 테이블에 없는 경우 조인 데이터가 직접 들어감)
|
||||
if (item[actualColName] !== undefined) {
|
||||
return item[actualColName];
|
||||
}
|
||||
}
|
||||
// 4. 기본: 컬럼명으로 직접 접근
|
||||
return item[actualColName];
|
||||
}, [config.rightPanel?.tableName, config.rightPanel?.joinTables]);
|
||||
|
||||
// 값 포맷팅
|
||||
const formatValue = (value: any, format?: ColumnConfig["format"]): string => {
|
||||
if (value === null || value === undefined) return "-";
|
||||
@@ -916,7 +952,7 @@ export const SplitPanelLayout2Component: React.FC<SplitPanelLayout2ComponentProp
|
||||
{nameRowColumns.length > 0 && (
|
||||
<div className="flex flex-wrap items-center gap-x-4 gap-y-1">
|
||||
{nameRowColumns.map((col, idx) => {
|
||||
const value = item[col.name];
|
||||
const value = getColumnValue(item, col);
|
||||
if (value === null || value === undefined) return null;
|
||||
return (
|
||||
<span key={idx} className="flex items-center gap-1">
|
||||
@@ -931,7 +967,7 @@ export const SplitPanelLayout2Component: React.FC<SplitPanelLayout2ComponentProp
|
||||
{infoRowColumns.length > 0 && (
|
||||
<div className="flex flex-wrap items-center gap-x-4 gap-y-1 text-muted-foreground">
|
||||
{infoRowColumns.map((col, idx) => {
|
||||
const value = item[col.name];
|
||||
const value = getColumnValue(item, col);
|
||||
if (value === null || value === undefined) return null;
|
||||
return (
|
||||
<span key={idx} className="flex items-center gap-1">
|
||||
@@ -950,7 +986,7 @@ export const SplitPanelLayout2Component: React.FC<SplitPanelLayout2ComponentProp
|
||||
{nameRowColumns.length > 0 && (
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
{nameRowColumns.map((col, idx) => {
|
||||
const value = item[col.name];
|
||||
const value = getColumnValue(item, col);
|
||||
if (value === null || value === undefined) return null;
|
||||
if (idx === 0) {
|
||||
return (
|
||||
@@ -971,7 +1007,7 @@ export const SplitPanelLayout2Component: React.FC<SplitPanelLayout2ComponentProp
|
||||
{infoRowColumns.length > 0 && (
|
||||
<div className="flex flex-wrap items-center gap-x-4 gap-y-1 text-muted-foreground">
|
||||
{infoRowColumns.map((col, idx) => {
|
||||
const value = item[col.name];
|
||||
const value = getColumnValue(item, col);
|
||||
if (value === null || value === undefined) return null;
|
||||
return (
|
||||
<span key={idx} className="text-sm">
|
||||
@@ -1079,7 +1115,7 @@ export const SplitPanelLayout2Component: React.FC<SplitPanelLayout2ComponentProp
|
||||
)}
|
||||
{displayColumns.map((col, colIdx) => (
|
||||
<TableCell key={colIdx}>
|
||||
{formatValue(item[col.name], col.format)}
|
||||
{formatValue(getColumnValue(item, col), col.format)}
|
||||
</TableCell>
|
||||
))}
|
||||
{(config.rightPanel?.showEditButton || config.rightPanel?.showDeleteButton) && (
|
||||
|
||||
Reference in New Issue
Block a user