refactor: 코드 정리 및 불필요한 로그 제거
- scheduleService.ts에서 스케줄 생성 로직을 간소화하고, 불필요한 줄바꿈을 제거하여 가독성을 향상시켰습니다. - v2-sales-order-modal-layout.json에서 JSON 포맷을 정리하여 일관성을 유지했습니다. - page.tsx, ScreenModal.tsx, ScreenDesigner.tsx, V2Input.tsx, V2Select.tsx, V2SelectConfigPanel.tsx, SimpleRepeaterTableComponent.tsx, ButtonPrimaryComponent.tsx, FileUploadComponent.tsx 등 여러 파일에서 디버깅 로그를 제거하여 코드의 깔끔함을 유지했습니다. - 전반적으로 코드의 가독성을 높이고, 불필요한 로그를 제거하여 유지보수성을 개선했습니다.
This commit is contained in:
@@ -90,7 +90,7 @@ export function SimpleRepeaterTableComponent({
|
||||
const newRowDefaults = componentConfig?.newRowDefaults || {};
|
||||
const summaryConfig = componentConfig?.summaryConfig;
|
||||
const maxHeight = componentConfig?.maxHeight || propMaxHeight || "240px";
|
||||
|
||||
|
||||
// 🆕 컴포넌트 레벨의 저장 테이블 설정
|
||||
const componentTargetTable = componentConfig?.targetTable || componentConfig?.saveTable;
|
||||
const componentFkColumn = componentConfig?.fkColumn;
|
||||
@@ -149,14 +149,11 @@ export function SimpleRepeaterTableComponent({
|
||||
}
|
||||
|
||||
// API 호출
|
||||
const response = await apiClient.post(
|
||||
`/table-management/tables/${initialConfig.sourceTable}/data`,
|
||||
{
|
||||
search: filters,
|
||||
page: 1,
|
||||
size: 1000, // 대량 조회
|
||||
}
|
||||
);
|
||||
const response = await apiClient.post(`/table-management/tables/${initialConfig.sourceTable}/data`, {
|
||||
search: filters,
|
||||
page: 1,
|
||||
size: 1000, // 대량 조회
|
||||
});
|
||||
|
||||
if (response.data.success && response.data.data?.data) {
|
||||
const loadedData = response.data.data.data;
|
||||
@@ -182,7 +179,7 @@ export function SimpleRepeaterTableComponent({
|
||||
|
||||
// 2. 조인 데이터 처리
|
||||
const joinColumns = columns.filter(
|
||||
(col) => col.sourceConfig?.type === "join" && col.sourceConfig.joinTable && col.sourceConfig.joinKey
|
||||
(col) => col.sourceConfig?.type === "join" && col.sourceConfig.joinTable && col.sourceConfig.joinKey,
|
||||
);
|
||||
|
||||
if (joinColumns.length > 0) {
|
||||
@@ -208,25 +205,20 @@ export function SimpleRepeaterTableComponent({
|
||||
const [tableName] = groupKey.split(":");
|
||||
|
||||
// 조인 키 값 수집 (중복 제거)
|
||||
const keyValues = Array.from(new Set(
|
||||
baseMappedData
|
||||
.map((row: any) => row[key])
|
||||
.filter((v: any) => v !== undefined && v !== null)
|
||||
));
|
||||
const keyValues = Array.from(
|
||||
new Set(baseMappedData.map((row: any) => row[key]).filter((v: any) => v !== undefined && v !== null)),
|
||||
);
|
||||
|
||||
if (keyValues.length === 0) return;
|
||||
|
||||
try {
|
||||
// 조인 테이블 조회
|
||||
// refKey(타겟 테이블 컬럼)로 검색
|
||||
const response = await apiClient.post(
|
||||
`/table-management/tables/${tableName}/data`,
|
||||
{
|
||||
search: { [refKey]: keyValues }, // { id: [1, 2, 3] }
|
||||
page: 1,
|
||||
size: 1000,
|
||||
}
|
||||
);
|
||||
const response = await apiClient.post(`/table-management/tables/${tableName}/data`, {
|
||||
search: { [refKey]: keyValues }, // { id: [1, 2, 3] }
|
||||
page: 1,
|
||||
size: 1000,
|
||||
});
|
||||
|
||||
if (response.data.success && response.data.data?.data) {
|
||||
const joinedRows = response.data.data.data;
|
||||
@@ -251,7 +243,7 @@ export function SimpleRepeaterTableComponent({
|
||||
console.error(`조인 실패 (${tableName}):`, error);
|
||||
// 실패 시 무시하고 진행 (값은 undefined)
|
||||
}
|
||||
})
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -296,7 +288,7 @@ export function SimpleRepeaterTableComponent({
|
||||
// 🆕 컴포넌트 레벨의 targetTable이 설정되어 있으면 우선 사용
|
||||
if (componentTargetTable) {
|
||||
console.log("✅ [SimpleRepeaterTable] 컴포넌트 레벨 저장 테이블 사용:", componentTargetTable);
|
||||
|
||||
|
||||
// 모든 행을 해당 테이블에 저장
|
||||
const dataToSave = value.map((row: any) => {
|
||||
// 메타데이터 필드 제외 (_, _rowIndex 등)
|
||||
@@ -399,9 +391,12 @@ export function SimpleRepeaterTableComponent({
|
||||
// 기존 onFormDataChange도 호출 (호환성)
|
||||
if (onFormDataChange && columnName) {
|
||||
// 테이블별 데이터를 통합하여 전달
|
||||
onFormDataChange(columnName, Object.entries(dataByTable).flatMap(([table, rows]) =>
|
||||
rows.map((row: any) => ({ ...row, _targetTable: table }))
|
||||
));
|
||||
onFormDataChange(
|
||||
columnName,
|
||||
Object.entries(dataByTable).flatMap(([table, rows]) =>
|
||||
rows.map((row: any) => ({ ...row, _targetTable: table })),
|
||||
),
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -543,24 +538,14 @@ export function SimpleRepeaterTableComponent({
|
||||
if (!allowAdd || readOnly || value.length >= maxRows) return null;
|
||||
|
||||
return (
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={handleAddRow}
|
||||
className="h-8 text-xs"
|
||||
>
|
||||
<Plus className="h-3.5 w-3.5 mr-1" />
|
||||
<Button type="button" variant="outline" size="sm" onClick={handleAddRow} className="h-8 text-xs">
|
||||
<Plus className="mr-1 h-3.5 w-3.5" />
|
||||
{addButtonText}
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
const renderCell = (
|
||||
row: any,
|
||||
column: SimpleRepeaterColumnConfig,
|
||||
rowIndex: number
|
||||
) => {
|
||||
const renderCell = (row: any, column: SimpleRepeaterColumnConfig, rowIndex: number) => {
|
||||
const cellValue = row[column.field];
|
||||
|
||||
// 계산 필드는 편집 불가
|
||||
@@ -583,9 +568,7 @@ export function SimpleRepeaterTableComponent({
|
||||
<Input
|
||||
type="number"
|
||||
value={cellValue || ""}
|
||||
onChange={(e) =>
|
||||
handleCellEdit(rowIndex, column.field, parseFloat(e.target.value) || 0)
|
||||
}
|
||||
onChange={(e) => handleCellEdit(rowIndex, column.field, parseFloat(e.target.value) || 0)}
|
||||
className="h-7 text-xs"
|
||||
/>
|
||||
);
|
||||
@@ -604,19 +587,19 @@ export function SimpleRepeaterTableComponent({
|
||||
return (
|
||||
<Select
|
||||
value={cellValue || ""}
|
||||
onValueChange={(newValue) =>
|
||||
handleCellEdit(rowIndex, column.field, newValue)
|
||||
}
|
||||
onValueChange={(newValue) => handleCellEdit(rowIndex, column.field, newValue)}
|
||||
>
|
||||
<SelectTrigger className="h-7 text-xs">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{column.selectOptions?.filter((option) => option.value && option.value !== "").map((option) => (
|
||||
<SelectItem key={option.value} value={option.value}>
|
||||
{option.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
{column.selectOptions
|
||||
?.filter((option) => option.value && option.value !== "")
|
||||
.map((option) => (
|
||||
<SelectItem key={option.value} value={option.value}>
|
||||
{option.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
);
|
||||
@@ -636,11 +619,11 @@ export function SimpleRepeaterTableComponent({
|
||||
// 로딩 중일 때
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className={cn("border rounded-md overflow-hidden bg-background", className)}>
|
||||
<div className={cn("bg-background overflow-hidden rounded-md border", className)}>
|
||||
<div className="flex items-center justify-center py-12" style={{ minHeight: maxHeight }}>
|
||||
<div className="text-center">
|
||||
<Loader2 className="h-8 w-8 animate-spin text-primary mx-auto mb-2" />
|
||||
<p className="text-sm text-muted-foreground">데이터를 불러오는 중...</p>
|
||||
<Loader2 className="text-primary mx-auto mb-2 h-8 w-8 animate-spin" />
|
||||
<p className="text-muted-foreground text-sm">데이터를 불러오는 중...</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -650,14 +633,14 @@ export function SimpleRepeaterTableComponent({
|
||||
// 에러 발생 시
|
||||
if (loadError) {
|
||||
return (
|
||||
<div className={cn("border rounded-md overflow-hidden bg-background", className)}>
|
||||
<div className={cn("bg-background overflow-hidden rounded-md border", className)}>
|
||||
<div className="flex items-center justify-center py-12" style={{ minHeight: maxHeight }}>
|
||||
<div className="text-center">
|
||||
<div className="w-12 h-12 rounded-full bg-destructive/10 flex items-center justify-center mx-auto mb-2">
|
||||
<X className="h-6 w-6 text-destructive" />
|
||||
<div className="bg-destructive/10 mx-auto mb-2 flex h-12 w-12 items-center justify-center rounded-full">
|
||||
<X className="text-destructive h-6 w-6" />
|
||||
</div>
|
||||
<p className="text-sm font-medium text-destructive mb-1">데이터 로드 실패</p>
|
||||
<p className="text-xs text-muted-foreground">{loadError}</p>
|
||||
<p className="text-destructive mb-1 text-sm font-medium">데이터 로드 실패</p>
|
||||
<p className="text-muted-foreground text-xs">{loadError}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -668,30 +651,27 @@ export function SimpleRepeaterTableComponent({
|
||||
const totalColumns = columns.length + (showRowNumber ? 1 : 0) + (allowDelete && !readOnly ? 1 : 0);
|
||||
|
||||
return (
|
||||
<div className={cn("border rounded-md overflow-hidden bg-background", className)}>
|
||||
<div className={cn("bg-background overflow-hidden rounded-md border", className)}>
|
||||
{/* 상단 행 추가 버튼 */}
|
||||
{allowAdd && addButtonPosition !== "bottom" && (
|
||||
<div className="p-2 border-b bg-muted/50">
|
||||
<div className="bg-muted/50 border-b p-2">
|
||||
<AddRowButton />
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div
|
||||
className="overflow-x-auto overflow-y-auto"
|
||||
style={{ maxHeight }}
|
||||
>
|
||||
<div className="overflow-x-auto overflow-y-auto" style={{ maxHeight }}>
|
||||
<table className="w-full text-xs sm:text-sm">
|
||||
<thead className="bg-muted sticky top-0 z-10">
|
||||
<tr>
|
||||
{showRowNumber && (
|
||||
<th key="header-rownum" className="px-4 py-2 text-left font-medium text-muted-foreground w-12">
|
||||
<th key="header-rownum" className="text-muted-foreground w-12 px-4 py-2 text-left font-medium">
|
||||
#
|
||||
</th>
|
||||
)}
|
||||
{columns.map((col) => (
|
||||
<th
|
||||
key={`header-${col.field}`}
|
||||
className="px-4 py-2 text-left font-medium text-muted-foreground"
|
||||
className="text-muted-foreground px-4 py-2 text-left font-medium"
|
||||
style={{ width: col.width }}
|
||||
>
|
||||
{col.label}
|
||||
@@ -699,7 +679,7 @@ export function SimpleRepeaterTableComponent({
|
||||
</th>
|
||||
))}
|
||||
{!readOnly && allowDelete && (
|
||||
<th key="header-delete" className="px-4 py-2 text-left font-medium text-muted-foreground w-20">
|
||||
<th key="header-delete" className="text-muted-foreground w-20 px-4 py-2 text-left font-medium">
|
||||
삭제
|
||||
</th>
|
||||
)}
|
||||
@@ -708,11 +688,7 @@ export function SimpleRepeaterTableComponent({
|
||||
<tbody className="bg-background">
|
||||
{value.length === 0 ? (
|
||||
<tr key="empty-row">
|
||||
<td
|
||||
key="empty-cell"
|
||||
colSpan={totalColumns}
|
||||
className="px-4 py-8 text-center text-muted-foreground"
|
||||
>
|
||||
<td key="empty-cell" colSpan={totalColumns} className="text-muted-foreground px-4 py-8 text-center">
|
||||
{allowAdd ? (
|
||||
<div className="flex flex-col items-center gap-2">
|
||||
<span>표시할 데이터가 없습니다</span>
|
||||
@@ -725,9 +701,9 @@ export function SimpleRepeaterTableComponent({
|
||||
</tr>
|
||||
) : (
|
||||
value.map((row, rowIndex) => (
|
||||
<tr key={`row-${rowIndex}`} className="border-t hover:bg-accent/50">
|
||||
<tr key={`row-${rowIndex}`} className="hover:bg-accent/50 border-t">
|
||||
{showRowNumber && (
|
||||
<td key={`rownum-${rowIndex}`} className="px-4 py-2 text-center text-muted-foreground">
|
||||
<td key={`rownum-${rowIndex}`} className="text-muted-foreground px-4 py-2 text-center">
|
||||
{rowIndex + 1}
|
||||
</td>
|
||||
)}
|
||||
@@ -743,7 +719,7 @@ export function SimpleRepeaterTableComponent({
|
||||
size="sm"
|
||||
onClick={() => handleRowDelete(rowIndex)}
|
||||
disabled={value.length <= minRows}
|
||||
className="h-7 w-7 p-0 text-destructive hover:text-destructive disabled:opacity-50"
|
||||
className="text-destructive hover:text-destructive h-7 w-7 p-0 disabled:opacity-50"
|
||||
>
|
||||
<Trash2 className="h-4 w-4" />
|
||||
</Button>
|
||||
@@ -758,35 +734,29 @@ export function SimpleRepeaterTableComponent({
|
||||
|
||||
{/* 합계 표시 */}
|
||||
{summaryConfig?.enabled && summaryValues && (
|
||||
<div className={cn(
|
||||
"border-t bg-muted/30 p-3",
|
||||
summaryConfig.position === "bottom-right" && "flex justify-end"
|
||||
)}>
|
||||
<div className={cn(
|
||||
summaryConfig.position === "bottom-right" ? "w-auto min-w-[200px]" : "w-full"
|
||||
)}>
|
||||
<div
|
||||
className={cn("bg-muted/30 border-t p-3", summaryConfig.position === "bottom-right" && "flex justify-end")}
|
||||
>
|
||||
<div className={cn(summaryConfig.position === "bottom-right" ? "w-auto min-w-[200px]" : "w-full")}>
|
||||
{summaryConfig.title && (
|
||||
<div className="text-xs font-medium text-muted-foreground mb-2">
|
||||
{summaryConfig.title}
|
||||
</div>
|
||||
<div className="text-muted-foreground mb-2 text-xs font-medium">{summaryConfig.title}</div>
|
||||
)}
|
||||
<div className={cn(
|
||||
"grid gap-2",
|
||||
summaryConfig.position === "bottom-right" ? "grid-cols-1" : "grid-cols-2 sm:grid-cols-3 lg:grid-cols-4"
|
||||
)}>
|
||||
<div
|
||||
className={cn(
|
||||
"grid gap-2",
|
||||
summaryConfig.position === "bottom-right" ? "grid-cols-1" : "grid-cols-2 sm:grid-cols-3 lg:grid-cols-4",
|
||||
)}
|
||||
>
|
||||
{summaryConfig.fields.map((field) => (
|
||||
<div
|
||||
key={field.field}
|
||||
className={cn(
|
||||
"flex justify-between items-center px-3 py-1.5 rounded",
|
||||
field.highlight ? "bg-primary/10 font-semibold" : "bg-background"
|
||||
"flex items-center justify-between rounded px-3 py-1.5",
|
||||
field.highlight ? "bg-primary/10 font-semibold" : "bg-background",
|
||||
)}
|
||||
>
|
||||
<span className="text-xs text-muted-foreground">{field.label}</span>
|
||||
<span className={cn(
|
||||
"text-sm font-medium",
|
||||
field.highlight && "text-primary"
|
||||
)}>
|
||||
<span className="text-muted-foreground text-xs">{field.label}</span>
|
||||
<span className={cn("text-sm font-medium", field.highlight && "text-primary")}>
|
||||
{formatSummaryValue(field, summaryValues[field.field] || 0)}
|
||||
</span>
|
||||
</div>
|
||||
@@ -798,10 +768,10 @@ export function SimpleRepeaterTableComponent({
|
||||
|
||||
{/* 하단 행 추가 버튼 */}
|
||||
{allowAdd && addButtonPosition !== "top" && value.length > 0 && (
|
||||
<div className="p-2 border-t bg-muted/50 flex justify-between items-center">
|
||||
<div className="bg-muted/50 flex items-center justify-between border-t p-2">
|
||||
<AddRowButton />
|
||||
{maxRows !== Infinity && (
|
||||
<span className="text-xs text-muted-foreground">
|
||||
<span className="text-muted-foreground text-xs">
|
||||
{value.length} / {maxRows}
|
||||
</span>
|
||||
)}
|
||||
@@ -810,4 +780,3 @@ export function SimpleRepeaterTableComponent({
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user