refactor: 코드 정리 및 가독성 향상

- numberingRuleController.ts에서 API 엔드포인트의 코드 스타일을 일관되게 정리하여 가독성을 높였습니다.
- 불필요한 줄바꿈을 제거하고, 코드 블록을 명확하게 정리하여 유지보수성을 개선했습니다.
- tableManagementService.ts와 ButtonConfigPanel.tsx에서 코드 정리를 통해 일관성을 유지하고, 가독성을 향상시켰습니다.
- 전반적으로 코드의 깔끔함을 유지하고, 향후 개발 시 이해하기 쉽게 개선했습니다.
This commit is contained in:
kjs
2026-02-05 17:38:06 +09:00
parent 73d05b991c
commit e31bb970a2
11 changed files with 1570 additions and 1348 deletions

View File

@@ -8,7 +8,7 @@
* - modal: 엔티티 선택 (FK 저장) + 추가 입력 컬럼
*
* RepeaterTable 및 ItemSelectionModal 재사용
*
*
* 데이터 전달 인터페이스:
* - DataProvidable: 선택된 데이터 제공
* - DataReceivable: 외부에서 데이터 수신
@@ -124,83 +124,91 @@ export const UnifiedRepeater: React.FC<UnifiedRepeaterProps> = ({
// DataProvidable 인터페이스 구현
// 다른 컴포넌트에서 이 리피터의 데이터를 가져갈 수 있게 함
// ============================================================
const dataProvider: DataProvidable = useMemo(() => ({
componentId: parentId || config.fieldName || "unified-repeater",
componentType: "unified-repeater",
// 선택된 행 데이터 반환
getSelectedData: () => {
return Array.from(selectedRows).map((idx) => data[idx]).filter(Boolean);
},
// 전체 데이터 반환
getAllData: () => {
return [...data];
},
// 선택 초기화
clearSelection: () => {
setSelectedRows(new Set());
},
}), [parentId, config.fieldName, data, selectedRows]);
const dataProvider: DataProvidable = useMemo(
() => ({
componentId: parentId || config.fieldName || "unified-repeater",
componentType: "unified-repeater",
// 선택된 행 데이터 반환
getSelectedData: () => {
return Array.from(selectedRows)
.map((idx) => data[idx])
.filter(Boolean);
},
// 전체 데이터 반환
getAllData: () => {
return [...data];
},
// 선택 초기화
clearSelection: () => {
setSelectedRows(new Set());
},
}),
[parentId, config.fieldName, data, selectedRows],
);
// ============================================================
// DataReceivable 인터페이스 구현
// 외부에서 이 리피터로 데이터를 전달받을 수 있게 함
// ============================================================
const dataReceiver: DataReceivable = useMemo(() => ({
componentId: parentId || config.fieldName || "unified-repeater",
componentType: "repeater",
// 데이터 수신 (append, replace, merge 모드 지원)
receiveData: async (incomingData: any[], receiverConfig: DataReceiverConfig) => {
if (!incomingData || incomingData.length === 0) return;
const dataReceiver: DataReceivable = useMemo(
() => ({
componentId: parentId || config.fieldName || "unified-repeater",
componentType: "repeater",
// 매핑 규칙 적용
const mappedData = incomingData.map((item, index) => {
const newRow: any = { _id: `received_${Date.now()}_${index}` };
if (receiverConfig.mappingRules && receiverConfig.mappingRules.length > 0) {
receiverConfig.mappingRules.forEach((rule) => {
const sourceValue = item[rule.sourceField];
newRow[rule.targetField] = sourceValue !== undefined ? sourceValue : rule.defaultValue;
});
} else {
// 매핑 규칙 없으면 그대로 복사
Object.assign(newRow, item);
// 데이터 수신 (append, replace, merge 모드 지원)
receiveData: async (incomingData: any[], receiverConfig: DataReceiverConfig) => {
if (!incomingData || incomingData.length === 0) return;
// 매핑 규칙 적용
const mappedData = incomingData.map((item, index) => {
const newRow: any = { _id: `received_${Date.now()}_${index}` };
if (receiverConfig.mappingRules && receiverConfig.mappingRules.length > 0) {
receiverConfig.mappingRules.forEach((rule) => {
const sourceValue = item[rule.sourceField];
newRow[rule.targetField] = sourceValue !== undefined ? sourceValue : rule.defaultValue;
});
} else {
// 매핑 규칙 없으면 그대로 복사
Object.assign(newRow, item);
}
return newRow;
});
// 모드에 따라 데이터 처리
switch (receiverConfig.mode) {
case "replace":
setData(mappedData);
onDataChange?.(mappedData);
break;
case "merge":
// 중복 제거 후 병합 (id 또는 _id 기준)
const existingIds = new Set(data.map((row) => row.id || row._id));
const newItems = mappedData.filter((row) => !existingIds.has(row.id || row._id));
const mergedData = [...data, ...newItems];
setData(mergedData);
onDataChange?.(mergedData);
break;
case "append":
default:
const appendedData = [...data, ...mappedData];
setData(appendedData);
onDataChange?.(appendedData);
break;
}
return newRow;
});
},
// 모드에 따라 데이터 처리
switch (receiverConfig.mode) {
case "replace":
setData(mappedData);
onDataChange?.(mappedData);
break;
case "merge":
// 중복 제거 후 병합 (id 또는 _id 기준)
const existingIds = new Set(data.map((row) => row.id || row._id));
const newItems = mappedData.filter((row) => !existingIds.has(row.id || row._id));
const mergedData = [...data, ...newItems];
setData(mergedData);
onDataChange?.(mergedData);
break;
case "append":
default:
const appendedData = [...data, ...mappedData];
setData(appendedData);
onDataChange?.(appendedData);
break;
}
},
// 현재 데이터 반환
getData: () => {
return [...data];
},
}), [parentId, config.fieldName, data, onDataChange]);
// 현재 데이터 반환
getData: () => {
return [...data];
},
}),
[parentId, config.fieldName, data, onDataChange],
);
// ============================================================
// ScreenContext에 DataProvider/DataReceiver 등록
@@ -208,7 +216,7 @@ export const UnifiedRepeater: React.FC<UnifiedRepeaterProps> = ({
useEffect(() => {
if (screenContext && (parentId || config.fieldName)) {
const componentId = parentId || config.fieldName || "unified-repeater";
screenContext.registerDataProvider(componentId, dataProvider);
screenContext.registerDataReceiver(componentId, dataReceiver);
@@ -231,7 +239,9 @@ export const UnifiedRepeater: React.FC<UnifiedRepeaterProps> = ({
componentId: parentId || config.fieldName || "unified-repeater",
tableName: config.dataSource?.tableName || "",
data: data,
selectedData: Array.from(selectedRows).map((idx) => data[idx]).filter(Boolean),
selectedData: Array.from(selectedRows)
.map((idx) => data[idx])
.filter(Boolean),
});
prevDataLengthRef.current = data.length;
}
@@ -701,19 +711,22 @@ export const UnifiedRepeater: React.FC<UnifiedRepeaterProps> = ({
// 🆕 채번 API 호출 (비동기)
// 🆕 수동 입력 부분 지원을 위해 userInputCode 파라미터 추가
const generateNumberingCode = useCallback(async (ruleId: string, userInputCode?: string, formData?: Record<string, any>): Promise<string> => {
try {
const result = await allocateNumberingCode(ruleId, userInputCode, formData);
if (result.success && result.data?.generatedCode) {
return result.data.generatedCode;
const generateNumberingCode = useCallback(
async (ruleId: string, userInputCode?: string, formData?: Record<string, any>): Promise<string> => {
try {
const result = await allocateNumberingCode(ruleId, userInputCode, formData);
if (result.success && result.data?.generatedCode) {
return result.data.generatedCode;
}
console.error("채번 실패:", result.error);
return "";
} catch (error) {
console.error("채번 API 호출 실패:", error);
return "";
}
console.error("채번 실패:", result.error);
return "";
} catch (error) {
console.error("채번 API 호출 실패:", error);
return "";
}
}, []);
},
[],
);
// 🆕 행 추가 (inline 모드 또는 모달 열기) - 비동기로 변경
const handleAddRow = useCallback(async () => {