feature/screen-management #306
|
|
@ -76,7 +76,9 @@ export const getCategoryValueCascadingGroups = async (
|
|||
data: result.rows,
|
||||
});
|
||||
} catch (error: any) {
|
||||
logger.error("카테고리 값 연쇄관계 그룹 목록 조회 실패", { error: error.message });
|
||||
logger.error("카테고리 값 연쇄관계 그룹 목록 조회 실패", {
|
||||
error: error.message,
|
||||
});
|
||||
return res.status(500).json({
|
||||
success: false,
|
||||
message: "카테고리 값 연쇄관계 그룹 목록 조회에 실패했습니다.",
|
||||
|
|
@ -175,7 +177,9 @@ export const getCategoryValueCascadingGroupById = async (
|
|||
},
|
||||
});
|
||||
} catch (error: any) {
|
||||
logger.error("카테고리 값 연쇄관계 그룹 상세 조회 실패", { error: error.message });
|
||||
logger.error("카테고리 값 연쇄관계 그룹 상세 조회 실패", {
|
||||
error: error.message,
|
||||
});
|
||||
return res.status(500).json({
|
||||
success: false,
|
||||
message: "카테고리 값 연쇄관계 그룹 조회에 실패했습니다.",
|
||||
|
|
@ -240,7 +244,9 @@ export const getCategoryValueCascadingByCode = async (
|
|||
data: result.rows[0],
|
||||
});
|
||||
} catch (error: any) {
|
||||
logger.error("카테고리 값 연쇄관계 코드 조회 실패", { error: error.message });
|
||||
logger.error("카테고리 값 연쇄관계 코드 조회 실패", {
|
||||
error: error.message,
|
||||
});
|
||||
return res.status(500).json({
|
||||
success: false,
|
||||
message: "카테고리 값 연쇄관계 조회에 실패했습니다.",
|
||||
|
|
@ -277,7 +283,14 @@ export const createCategoryValueCascadingGroup = async (
|
|||
} = req.body;
|
||||
|
||||
// 필수 필드 검증
|
||||
if (!relationCode || !relationName || !parentTableName || !parentColumnName || !childTableName || !childColumnName) {
|
||||
if (
|
||||
!relationCode ||
|
||||
!relationName ||
|
||||
!parentTableName ||
|
||||
!parentColumnName ||
|
||||
!childTableName ||
|
||||
!childColumnName
|
||||
) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: "필수 필드가 누락되었습니다.",
|
||||
|
|
@ -352,7 +365,9 @@ export const createCategoryValueCascadingGroup = async (
|
|||
message: "카테고리 값 연쇄관계 그룹이 생성되었습니다.",
|
||||
});
|
||||
} catch (error: any) {
|
||||
logger.error("카테고리 값 연쇄관계 그룹 생성 실패", { error: error.message });
|
||||
logger.error("카테고리 값 연쇄관계 그룹 생성 실패", {
|
||||
error: error.message,
|
||||
});
|
||||
return res.status(500).json({
|
||||
success: false,
|
||||
message: "카테고리 값 연쇄관계 그룹 생성에 실패했습니다.",
|
||||
|
|
@ -403,7 +418,11 @@ export const updateCategoryValueCascadingGroup = async (
|
|||
}
|
||||
|
||||
const existingCompanyCode = existingCheck.rows[0].company_code;
|
||||
if (companyCode !== "*" && existingCompanyCode !== companyCode && existingCompanyCode !== "*") {
|
||||
if (
|
||||
companyCode !== "*" &&
|
||||
existingCompanyCode !== companyCode &&
|
||||
existingCompanyCode !== "*"
|
||||
) {
|
||||
return res.status(403).json({
|
||||
success: false,
|
||||
message: "수정 권한이 없습니다.",
|
||||
|
|
@ -440,7 +459,11 @@ export const updateCategoryValueCascadingGroup = async (
|
|||
childTableName,
|
||||
childColumnName,
|
||||
childMenuObjid,
|
||||
clearOnParentChange !== undefined ? (clearOnParentChange ? "Y" : "N") : null,
|
||||
clearOnParentChange !== undefined
|
||||
? clearOnParentChange
|
||||
? "Y"
|
||||
: "N"
|
||||
: null,
|
||||
showGroupLabel !== undefined ? (showGroupLabel ? "Y" : "N") : null,
|
||||
emptyParentMessage,
|
||||
noOptionsMessage,
|
||||
|
|
@ -461,7 +484,9 @@ export const updateCategoryValueCascadingGroup = async (
|
|||
message: "카테고리 값 연쇄관계 그룹이 수정되었습니다.",
|
||||
});
|
||||
} catch (error: any) {
|
||||
logger.error("카테고리 값 연쇄관계 그룹 수정 실패", { error: error.message });
|
||||
logger.error("카테고리 값 연쇄관계 그룹 수정 실패", {
|
||||
error: error.message,
|
||||
});
|
||||
return res.status(500).json({
|
||||
success: false,
|
||||
message: "카테고리 값 연쇄관계 그룹 수정에 실패했습니다.",
|
||||
|
|
@ -496,7 +521,11 @@ export const deleteCategoryValueCascadingGroup = async (
|
|||
}
|
||||
|
||||
const existingCompanyCode = existingCheck.rows[0].company_code;
|
||||
if (companyCode !== "*" && existingCompanyCode !== companyCode && existingCompanyCode !== "*") {
|
||||
if (
|
||||
companyCode !== "*" &&
|
||||
existingCompanyCode !== companyCode &&
|
||||
existingCompanyCode !== "*"
|
||||
) {
|
||||
return res.status(403).json({
|
||||
success: false,
|
||||
message: "삭제 권한이 없습니다.",
|
||||
|
|
@ -522,7 +551,9 @@ export const deleteCategoryValueCascadingGroup = async (
|
|||
message: "카테고리 값 연쇄관계 그룹이 삭제되었습니다.",
|
||||
});
|
||||
} catch (error: any) {
|
||||
logger.error("카테고리 값 연쇄관계 그룹 삭제 실패", { error: error.message });
|
||||
logger.error("카테고리 값 연쇄관계 그룹 삭제 실패", {
|
||||
error: error.message,
|
||||
});
|
||||
return res.status(500).json({
|
||||
success: false,
|
||||
message: "카테고리 값 연쇄관계 그룹 삭제에 실패했습니다.",
|
||||
|
|
@ -620,7 +651,9 @@ export const saveCategoryValueCascadingMappings = async (
|
|||
client.release();
|
||||
}
|
||||
} catch (error: any) {
|
||||
logger.error("카테고리 값 연쇄관계 매핑 저장 실패", { error: error.message });
|
||||
logger.error("카테고리 값 연쇄관계 매핑 저장 실패", {
|
||||
error: error.message,
|
||||
});
|
||||
return res.status(500).json({
|
||||
success: false,
|
||||
message: "카테고리 값 연쇄관계 매핑 저장에 실패했습니다.",
|
||||
|
|
@ -649,12 +682,15 @@ export const getCategoryValueCascadingOptions = async (
|
|||
|
||||
// 다중 부모값 파싱
|
||||
let parentValueArray: string[] = [];
|
||||
|
||||
|
||||
if (parentValues) {
|
||||
if (Array.isArray(parentValues)) {
|
||||
parentValueArray = parentValues.map(v => String(v));
|
||||
parentValueArray = parentValues.map((v) => String(v));
|
||||
} else {
|
||||
parentValueArray = String(parentValues).split(',').map(v => v.trim()).filter(v => v);
|
||||
parentValueArray = String(parentValues)
|
||||
.split(",")
|
||||
.map((v) => v.trim())
|
||||
.filter((v) => v);
|
||||
}
|
||||
} else if (parentValue) {
|
||||
parentValueArray = [String(parentValue)];
|
||||
|
|
@ -696,8 +732,10 @@ export const getCategoryValueCascadingOptions = async (
|
|||
const group = groupResult.rows[0];
|
||||
|
||||
// 매핑된 자식 값 조회 (다중 부모값에 대해 IN 절 사용)
|
||||
const placeholders = parentValueArray.map((_, idx) => `$${idx + 2}`).join(', ');
|
||||
|
||||
const placeholders = parentValueArray
|
||||
.map((_, idx) => `$${idx + 2}`)
|
||||
.join(", ");
|
||||
|
||||
const optionsQuery = `
|
||||
SELECT DISTINCT
|
||||
child_value_code as value,
|
||||
|
|
@ -712,7 +750,10 @@ export const getCategoryValueCascadingOptions = async (
|
|||
ORDER BY parent_value_code, display_order, child_value_label
|
||||
`;
|
||||
|
||||
const optionsResult = await pool.query(optionsQuery, [group.group_id, ...parentValueArray]);
|
||||
const optionsResult = await pool.query(optionsQuery, [
|
||||
group.group_id,
|
||||
...parentValueArray,
|
||||
]);
|
||||
|
||||
logger.info("카테고리 값 연쇄 옵션 조회", {
|
||||
relationCode: code,
|
||||
|
|
@ -723,7 +764,7 @@ export const getCategoryValueCascadingOptions = async (
|
|||
return res.json({
|
||||
success: true,
|
||||
data: optionsResult.rows,
|
||||
showGroupLabel: group.show_group_label === 'Y',
|
||||
showGroupLabel: group.show_group_label === "Y",
|
||||
});
|
||||
} catch (error: any) {
|
||||
logger.error("카테고리 값 연쇄 옵션 조회 실패", { error: error.message });
|
||||
|
|
@ -789,7 +830,10 @@ export const getCategoryValueCascadingParentOptions = async (
|
|||
AND is_active = true
|
||||
`;
|
||||
|
||||
const optionsParams: any[] = [group.parent_table_name, group.parent_column_name];
|
||||
const optionsParams: any[] = [
|
||||
group.parent_table_name,
|
||||
group.parent_column_name,
|
||||
];
|
||||
let paramIndex = 3;
|
||||
|
||||
// 메뉴 스코프 적용
|
||||
|
|
@ -884,7 +928,10 @@ export const getCategoryValueCascadingChildOptions = async (
|
|||
AND is_active = true
|
||||
`;
|
||||
|
||||
const optionsParams: any[] = [group.child_table_name, group.child_column_name];
|
||||
const optionsParams: any[] = [
|
||||
group.child_table_name,
|
||||
group.child_column_name,
|
||||
];
|
||||
let paramIndex = 3;
|
||||
|
||||
// 메뉴 스코프 적용
|
||||
|
|
@ -925,3 +972,91 @@ export const getCategoryValueCascadingChildOptions = async (
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 테이블명으로 해당 테이블의 모든 연쇄관계 매핑 조회
|
||||
* (테이블 목록에서 코드→라벨 변환에 사용)
|
||||
*/
|
||||
export const getCategoryValueCascadingMappingsByTable = async (
|
||||
req: AuthenticatedRequest,
|
||||
res: Response
|
||||
) => {
|
||||
try {
|
||||
const { tableName } = req.params;
|
||||
const companyCode = req.user?.companyCode || "*";
|
||||
|
||||
if (!tableName) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: "테이블명이 필요합니다.",
|
||||
});
|
||||
}
|
||||
|
||||
// 해당 테이블이 자식 테이블인 연쇄관계 그룹 찾기
|
||||
let groupQuery = `
|
||||
SELECT
|
||||
group_id,
|
||||
relation_code,
|
||||
child_column_name
|
||||
FROM category_value_cascading_group
|
||||
WHERE child_table_name = $1
|
||||
AND is_active = 'Y'
|
||||
`;
|
||||
const groupParams: any[] = [tableName];
|
||||
let paramIndex = 2;
|
||||
|
||||
// 멀티테넌시 적용
|
||||
if (companyCode !== "*") {
|
||||
groupQuery += ` AND (company_code = $${paramIndex} OR company_code = '*')`;
|
||||
groupParams.push(companyCode);
|
||||
}
|
||||
|
||||
const groupResult = await pool.query(groupQuery, groupParams);
|
||||
|
||||
if (groupResult.rowCount === 0) {
|
||||
// 연쇄관계가 없으면 빈 객체 반환
|
||||
return res.json({
|
||||
success: true,
|
||||
data: {},
|
||||
});
|
||||
}
|
||||
|
||||
// 각 그룹의 매핑 조회
|
||||
const mappings: Record<string, Array<{ code: string; label: string }>> = {};
|
||||
|
||||
for (const group of groupResult.rows) {
|
||||
const mappingQuery = `
|
||||
SELECT DISTINCT
|
||||
child_value_code as code,
|
||||
child_value_label as label
|
||||
FROM category_value_cascading_mapping
|
||||
WHERE group_id = $1
|
||||
AND is_active = 'Y'
|
||||
ORDER BY child_value_label
|
||||
`;
|
||||
|
||||
const mappingResult = await pool.query(mappingQuery, [group.group_id]);
|
||||
|
||||
if (mappingResult.rowCount && mappingResult.rowCount > 0) {
|
||||
mappings[group.child_column_name] = mappingResult.rows;
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("테이블별 연쇄관계 매핑 조회", {
|
||||
tableName,
|
||||
groupCount: groupResult.rowCount,
|
||||
columnMappings: Object.keys(mappings),
|
||||
});
|
||||
|
||||
return res.json({
|
||||
success: true,
|
||||
data: mappings,
|
||||
});
|
||||
} catch (error: any) {
|
||||
logger.error("테이블별 연쇄관계 매핑 조회 실패", { error: error.message });
|
||||
return res.status(500).json({
|
||||
success: false,
|
||||
message: "연쇄관계 매핑 조회에 실패했습니다.",
|
||||
error: error.message,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import {
|
|||
getCategoryValueCascadingOptions,
|
||||
getCategoryValueCascadingParentOptions,
|
||||
getCategoryValueCascadingChildOptions,
|
||||
getCategoryValueCascadingMappingsByTable,
|
||||
} from "../controllers/categoryValueCascadingController";
|
||||
import { authenticateToken } from "../middleware/authMiddleware";
|
||||
|
||||
|
|
@ -60,5 +61,14 @@ router.get("/child-options/:code", getCategoryValueCascadingChildOptions);
|
|||
// 연쇄 옵션 조회 (부모 값 기반 자식 옵션)
|
||||
router.get("/options/:code", getCategoryValueCascadingOptions);
|
||||
|
||||
export default router;
|
||||
// ============================================
|
||||
// 테이블별 매핑 조회 (테이블 목록 표시용)
|
||||
// ============================================
|
||||
|
||||
// 테이블명으로 해당 테이블의 모든 연쇄관계 매핑 조회
|
||||
router.get(
|
||||
"/table/:tableName/mappings",
|
||||
getCategoryValueCascadingMappingsByTable
|
||||
);
|
||||
|
||||
export default router;
|
||||
|
|
|
|||
|
|
@ -209,7 +209,7 @@ export interface TableListComponentProps {
|
|||
onConfigChange?: (config: any) => void;
|
||||
refreshKey?: number;
|
||||
// 탭 관련 정보 (탭 내부의 테이블에서 사용)
|
||||
parentTabId?: string; // 부모 탭 ID
|
||||
parentTabId?: string; // 부모 탭 ID
|
||||
parentTabsComponentId?: string; // 부모 탭 컴포넌트 ID
|
||||
}
|
||||
|
||||
|
|
@ -689,7 +689,7 @@ export const TableListComponent: React.FC<TableListComponentProps> = ({
|
|||
const [viewMode, setViewMode] = useState<"table" | "card" | "grouped-card">("table");
|
||||
// 체크박스 컬럼은 항상 기본 틀고정
|
||||
const [frozenColumns, setFrozenColumns] = useState<string[]>(
|
||||
(tableConfig.checkbox?.enabled ?? true) ? ["__checkbox__"] : []
|
||||
(tableConfig.checkbox?.enabled ?? true) ? ["__checkbox__"] : [],
|
||||
);
|
||||
const [frozenColumnCount, setFrozenColumnCount] = useState<number>(0);
|
||||
|
||||
|
|
@ -1311,17 +1311,15 @@ export const TableListComponent: React.FC<TableListComponentProps> = ({
|
|||
const parts = columnName.split(".");
|
||||
targetTable = parts[0]; // 조인된 테이블명 (예: item_info)
|
||||
targetColumn = parts[1]; // 실제 컬럼명 (예: material)
|
||||
console.log(`🔗 [TableList] 엔티티 조인 컬럼 감지:`, {
|
||||
console.log("🔗 [TableList] 엔티티 조인 컬럼 감지:", {
|
||||
originalColumn: columnName,
|
||||
targetTable,
|
||||
targetColumn,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
const response = await apiClient.get(`/table-categories/${targetTable}/${targetColumn}/values`);
|
||||
|
||||
|
||||
if (response.data.success && response.data.data && Array.isArray(response.data.data)) {
|
||||
const mapping: Record<string, { label: string; color?: string }> = {};
|
||||
|
||||
|
|
@ -1376,7 +1374,6 @@ export const TableListComponent: React.FC<TableListComponentProps> = ({
|
|||
col.columnName,
|
||||
})) || [];
|
||||
|
||||
|
||||
// 조인 테이블별로 그룹화
|
||||
const joinedTableColumns: Record<string, { columnName: string; actualColumn: string }[]> = {};
|
||||
|
||||
|
|
@ -1408,7 +1405,6 @@ export const TableListComponent: React.FC<TableListComponentProps> = ({
|
|||
});
|
||||
}
|
||||
|
||||
|
||||
// 조인된 테이블별로 inputType 정보 가져오기
|
||||
const newJoinedColumnMeta: Record<string, { webType?: string; codeCategory?: string; inputType?: string }> = {};
|
||||
|
||||
|
|
@ -1471,6 +1467,41 @@ export const TableListComponent: React.FC<TableListComponentProps> = ({
|
|||
console.log("✅ [TableList] 조인 컬럼 메타데이터 설정:", newJoinedColumnMeta);
|
||||
}
|
||||
|
||||
// 🆕 카테고리 연쇄관계 매핑 로드 (category_value_cascading_mapping)
|
||||
try {
|
||||
const cascadingResponse = await apiClient.get(
|
||||
`/category-value-cascading/table/${tableConfig.selectedTable}/mappings`,
|
||||
);
|
||||
if (cascadingResponse.data.success && cascadingResponse.data.data) {
|
||||
const cascadingMappings = cascadingResponse.data.data;
|
||||
|
||||
// 각 자식 컬럼에 대한 매핑 추가
|
||||
for (const [columnName, columnMappings] of Object.entries(
|
||||
cascadingMappings as Record<string, Array<{ code: string; label: string }>>,
|
||||
)) {
|
||||
if (!mappings[columnName]) {
|
||||
mappings[columnName] = {};
|
||||
}
|
||||
// 연쇄관계 매핑 추가
|
||||
for (const item of columnMappings) {
|
||||
mappings[columnName][item.code] = {
|
||||
label: item.label,
|
||||
color: undefined, // 연쇄관계는 색상 없음
|
||||
};
|
||||
}
|
||||
}
|
||||
console.log("✅ [TableList] 카테고리 연쇄관계 매핑 로드 완료:", {
|
||||
tableName: tableConfig.selectedTable,
|
||||
cascadingColumns: Object.keys(cascadingMappings),
|
||||
});
|
||||
}
|
||||
} catch (cascadingError: any) {
|
||||
// 연쇄관계 매핑이 없는 경우 무시 (404 등)
|
||||
if (cascadingError?.response?.status !== 404) {
|
||||
console.warn("⚠️ [TableList] 카테고리 연쇄관계 매핑 로드 실패:", cascadingError?.message);
|
||||
}
|
||||
}
|
||||
|
||||
if (Object.keys(mappings).length > 0) {
|
||||
setCategoryMappings(mappings);
|
||||
setCategoryMappingsKey((prev) => prev + 1);
|
||||
|
|
@ -1495,7 +1526,6 @@ export const TableListComponent: React.FC<TableListComponentProps> = ({
|
|||
// ========================================
|
||||
|
||||
const fetchTableDataInternal = useCallback(async () => {
|
||||
|
||||
if (!tableConfig.selectedTable || isDesignMode) {
|
||||
setData([]);
|
||||
setTotalPages(0);
|
||||
|
|
@ -1514,11 +1544,10 @@ export const TableListComponent: React.FC<TableListComponentProps> = ({
|
|||
const search = searchTerm || undefined;
|
||||
|
||||
// 🆕 연결 필터 값 가져오기 (분할 패널 내부일 때)
|
||||
let linkedFilterValues: Record<string, any> = {};
|
||||
const linkedFilterValues: Record<string, any> = {};
|
||||
let hasLinkedFiltersConfigured = false; // 연결 필터가 설정되어 있는지 여부
|
||||
let hasSelectedLeftData = false; // 좌측에서 데이터가 선택되었는지 여부
|
||||
|
||||
|
||||
if (splitPanelContext) {
|
||||
// 연결 필터 설정 여부 확인 (현재 테이블에 해당하는 필터가 있는지)
|
||||
const linkedFiltersConfig = splitPanelContext.linkedFilters || [];
|
||||
|
|
@ -1609,7 +1638,7 @@ export const TableListComponent: React.FC<TableListComponentProps> = ({
|
|||
}
|
||||
|
||||
// 🆕 RelatedDataButtons 필터 값 준비
|
||||
let relatedButtonFilterValues: Record<string, any> = {};
|
||||
const relatedButtonFilterValues: Record<string, any> = {};
|
||||
if (relatedButtonFilter) {
|
||||
relatedButtonFilterValues[relatedButtonFilter.filterColumn] = {
|
||||
value: relatedButtonFilter.filterValue,
|
||||
|
|
@ -1685,7 +1714,6 @@ export const TableListComponent: React.FC<TableListComponentProps> = ({
|
|||
};
|
||||
});
|
||||
|
||||
|
||||
// 🆕 제외 필터 처리 (다른 테이블에 이미 존재하는 데이터 제외)
|
||||
let excludeFilterParam: any = undefined;
|
||||
if (tableConfig.excludeFilter?.enabled) {
|
||||
|
|
@ -2427,7 +2455,7 @@ export const TableListComponent: React.FC<TableListComponentProps> = ({
|
|||
try {
|
||||
const { apiClient } = await import("@/lib/api/client");
|
||||
|
||||
await apiClient.put(`/dynamic-form/update-field`, {
|
||||
await apiClient.put("/dynamic-form/update-field", {
|
||||
tableName: tableConfig.selectedTable,
|
||||
keyField: primaryKeyField,
|
||||
keyValue: primaryKeyValue,
|
||||
|
|
@ -2468,7 +2496,7 @@ export const TableListComponent: React.FC<TableListComponentProps> = ({
|
|||
|
||||
// 모든 변경사항 저장
|
||||
const savePromises = Array.from(pendingChanges.values()).map((change) =>
|
||||
apiClient.put(`/dynamic-form/update-field`, {
|
||||
apiClient.put("/dynamic-form/update-field", {
|
||||
tableName: tableConfig.selectedTable,
|
||||
keyField: primaryKeyField,
|
||||
keyValue: change.primaryKeyValue,
|
||||
|
|
@ -2942,9 +2970,10 @@ export const TableListComponent: React.FC<TableListComponentProps> = ({
|
|||
if (state.frozenColumns) {
|
||||
// 체크박스 컬럼이 항상 포함되도록 보장
|
||||
const checkboxColumn = (tableConfig.checkbox?.enabled ?? true) ? "__checkbox__" : null;
|
||||
const restoredFrozenColumns = checkboxColumn && !state.frozenColumns.includes(checkboxColumn)
|
||||
? [checkboxColumn, ...state.frozenColumns]
|
||||
: state.frozenColumns;
|
||||
const restoredFrozenColumns =
|
||||
checkboxColumn && !state.frozenColumns.includes(checkboxColumn)
|
||||
? [checkboxColumn, ...state.frozenColumns]
|
||||
: state.frozenColumns;
|
||||
setFrozenColumns(restoredFrozenColumns);
|
||||
}
|
||||
if (state.frozenColumnCount !== undefined) setFrozenColumnCount(state.frozenColumnCount); // 틀고정 컬럼 수 복원
|
||||
|
|
@ -2956,7 +2985,6 @@ export const TableListComponent: React.FC<TableListComponentProps> = ({
|
|||
});
|
||||
setHeaderFilters(filters);
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error("❌ 테이블 상태 복원 실패:", error);
|
||||
}
|
||||
|
|
@ -3576,7 +3604,7 @@ export const TableListComponent: React.FC<TableListComponentProps> = ({
|
|||
}));
|
||||
|
||||
// 배치 업데이트
|
||||
await Promise.all(updates.map((update) => apiClient.put(`/dynamic-form/update-field`, update)));
|
||||
await Promise.all(updates.map((update) => apiClient.put("/dynamic-form/update-field", update)));
|
||||
|
||||
toast.success("순서가 변경되었습니다.");
|
||||
setRefreshTrigger((prev) => prev + 1);
|
||||
|
|
@ -4894,7 +4922,7 @@ export const TableListComponent: React.FC<TableListComponentProps> = ({
|
|||
useEffect(() => {
|
||||
const handleRelatedButtonSelect = (event: CustomEvent) => {
|
||||
const { targetTable, filterColumn, filterValue } = event.detail || {};
|
||||
|
||||
|
||||
// 이 테이블이 대상 테이블인지 확인
|
||||
if (targetTable === tableConfig.selectedTable) {
|
||||
// filterValue가 null이면 선택 해제 (빈 상태)
|
||||
|
|
@ -4925,9 +4953,9 @@ export const TableListComponent: React.FC<TableListComponentProps> = ({
|
|||
useEffect(() => {
|
||||
if (!isDesignMode) {
|
||||
// relatedButtonFilter가 있으면 데이터 로드, null이면 빈 상태 (setRefreshTrigger로 트리거)
|
||||
console.log("🔄 [TableList] RelatedDataButtons 상태 변경:", {
|
||||
relatedButtonFilter,
|
||||
isRelatedButtonTarget
|
||||
console.log("🔄 [TableList] RelatedDataButtons 상태 변경:", {
|
||||
relatedButtonFilter,
|
||||
isRelatedButtonTarget,
|
||||
});
|
||||
setRefreshTrigger((prev) => prev + 1);
|
||||
}
|
||||
|
|
@ -5618,7 +5646,7 @@ export const TableListComponent: React.FC<TableListComponentProps> = ({
|
|||
for (let i = 0; i < frozenIndex; i++) {
|
||||
const frozenCol = frozenColumns[i];
|
||||
// 체크박스 컬럼은 48px 고정
|
||||
const frozenColWidth = frozenCol === "__checkbox__" ? 48 : (columnWidths[frozenCol] || 150);
|
||||
const frozenColWidth = frozenCol === "__checkbox__" ? 48 : columnWidths[frozenCol] || 150;
|
||||
leftPosition += frozenColWidth;
|
||||
}
|
||||
}
|
||||
|
|
@ -5930,7 +5958,8 @@ export const TableListComponent: React.FC<TableListComponentProps> = ({
|
|||
for (let i = 0; i < frozenIndex; i++) {
|
||||
const frozenCol = frozenColumns[i];
|
||||
// 체크박스 컬럼은 48px 고정
|
||||
const frozenColWidth = frozenCol === "__checkbox__" ? 48 : (columnWidths[frozenCol] || 150);
|
||||
const frozenColWidth =
|
||||
frozenCol === "__checkbox__" ? 48 : columnWidths[frozenCol] || 150;
|
||||
leftPosition += frozenColWidth;
|
||||
}
|
||||
}
|
||||
|
|
@ -5958,7 +5987,7 @@ export const TableListComponent: React.FC<TableListComponentProps> = ({
|
|||
: `${100 / visibleColumns.length}%`,
|
||||
minWidth: column.columnName === "__checkbox__" ? "48px" : undefined,
|
||||
maxWidth: column.columnName === "__checkbox__" ? "48px" : undefined,
|
||||
...(isFrozen && {
|
||||
...(isFrozen && {
|
||||
left: `${leftPosition}px`,
|
||||
backgroundColor: "hsl(var(--background))",
|
||||
}),
|
||||
|
|
@ -6094,7 +6123,8 @@ export const TableListComponent: React.FC<TableListComponentProps> = ({
|
|||
for (let i = 0; i < frozenIndex; i++) {
|
||||
const frozenCol = frozenColumns[i];
|
||||
// 체크박스 컬럼은 48px 고정
|
||||
const frozenColWidth = frozenCol === "__checkbox__" ? 48 : (columnWidths[frozenCol] || 150);
|
||||
const frozenColWidth =
|
||||
frozenCol === "__checkbox__" ? 48 : columnWidths[frozenCol] || 150;
|
||||
leftPosition += frozenColWidth;
|
||||
}
|
||||
}
|
||||
|
|
@ -6134,7 +6164,7 @@ export const TableListComponent: React.FC<TableListComponentProps> = ({
|
|||
column.columnName === "__checkbox__" ? "48px" : `${100 / visibleColumns.length}%`,
|
||||
minWidth: column.columnName === "__checkbox__" ? "48px" : undefined,
|
||||
maxWidth: column.columnName === "__checkbox__" ? "48px" : undefined,
|
||||
...(isFrozen && {
|
||||
...(isFrozen && {
|
||||
left: `${leftPosition}px`,
|
||||
backgroundColor: "hsl(var(--background))",
|
||||
}),
|
||||
|
|
@ -6259,7 +6289,7 @@ export const TableListComponent: React.FC<TableListComponentProps> = ({
|
|||
for (let i = 0; i < frozenIndex; i++) {
|
||||
const frozenCol = frozenColumns[i];
|
||||
// 체크박스 컬럼은 48px 고정
|
||||
const frozenColWidth = frozenCol === "__checkbox__" ? 48 : (columnWidths[frozenCol] || 150);
|
||||
const frozenColWidth = frozenCol === "__checkbox__" ? 48 : columnWidths[frozenCol] || 150;
|
||||
leftPosition += frozenColWidth;
|
||||
}
|
||||
}
|
||||
|
|
@ -6284,7 +6314,7 @@ export const TableListComponent: React.FC<TableListComponentProps> = ({
|
|||
: columnWidth
|
||||
? `${columnWidth}px`
|
||||
: undefined,
|
||||
...(isFrozen && {
|
||||
...(isFrozen && {
|
||||
left: `${leftPosition}px`,
|
||||
backgroundColor: "hsl(var(--muted) / 0.8)",
|
||||
}),
|
||||
|
|
|
|||
Loading…
Reference in New Issue