[agent-pipeline] pipe-20260329010534-qgv9 round-3
This commit is contained in:
@@ -51,9 +51,9 @@ const escapeRegExp = (str: string): string => {
|
||||
};
|
||||
|
||||
interface LinkedModalScreen {
|
||||
screenId: number;
|
||||
screenName: string;
|
||||
screenCode: string;
|
||||
screen_id: number;
|
||||
screen_name: string;
|
||||
screen_code: string;
|
||||
newScreenName?: string;
|
||||
newScreenCode?: string;
|
||||
}
|
||||
@@ -237,7 +237,7 @@ export default function CopyScreenModal({
|
||||
setLinkedScreens((prev) =>
|
||||
prev.map((screen) => ({
|
||||
...screen,
|
||||
newScreenName: applyBulkRename(screen.screenName),
|
||||
newScreenName: applyBulkRename(screen.screen_name),
|
||||
}))
|
||||
);
|
||||
} else {
|
||||
@@ -247,7 +247,7 @@ export default function CopyScreenModal({
|
||||
setLinkedScreens((prev) =>
|
||||
prev.map((screen) => ({
|
||||
...screen,
|
||||
newScreenName: screen.screenName,
|
||||
newScreenName: screen.screen_name,
|
||||
}))
|
||||
);
|
||||
}
|
||||
@@ -344,7 +344,7 @@ export default function CopyScreenModal({
|
||||
setLinkedScreens(
|
||||
linked.map((screen) => ({
|
||||
...screen,
|
||||
newScreenName: `${screen.screenName} (복사본)`,
|
||||
newScreenName: `${screen.screen_name} (복사본)`,
|
||||
}))
|
||||
);
|
||||
|
||||
@@ -394,7 +394,7 @@ export default function CopyScreenModal({
|
||||
|
||||
setLinkedScreens(updatedLinkedScreens);
|
||||
console.log("✅ 모달 화면 코드 할당 완료:", updatedLinkedScreens.map(s => ({
|
||||
name: s.screenName,
|
||||
name: s.screen_name,
|
||||
code: s.newScreenCode
|
||||
})));
|
||||
}
|
||||
@@ -408,14 +408,14 @@ export default function CopyScreenModal({
|
||||
const updateLinkedScreenName = (screenId: number, newName: string) => {
|
||||
setLinkedScreens((prev) =>
|
||||
prev.map((screen) =>
|
||||
screen.screenId === screenId ? { ...screen, newScreenName: newName } : screen
|
||||
screen.screen_id === screenId ? { ...screen, newScreenName: newName } : screen
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
// 연결된 화면 제거 (복사하지 않음)
|
||||
const removeLinkedScreen = (screenId: number) => {
|
||||
setLinkedScreens((prev) => prev.filter((screen) => screen.screenId !== screenId));
|
||||
setLinkedScreens((prev) => prev.filter((screen) => screen.screen_id !== screenId));
|
||||
};
|
||||
|
||||
// 화면명 일괄 변경 적용
|
||||
@@ -448,8 +448,8 @@ export default function CopyScreenModal({
|
||||
preview: applyBulkRename(sourceScreen.screen_name), // (복사본) 없음
|
||||
},
|
||||
modals: linkedScreens.map((screen) => ({
|
||||
original: screen.screenName,
|
||||
preview: applyBulkRename(screen.screenName),
|
||||
original: screen.screen_name,
|
||||
preview: applyBulkRename(screen.screen_name),
|
||||
})),
|
||||
};
|
||||
};
|
||||
@@ -548,11 +548,11 @@ export default function CopyScreenModal({
|
||||
// 연결된 화면들의 이름 검증
|
||||
for (const linked of linkedScreens) {
|
||||
if (!linked.newScreenName?.trim()) {
|
||||
toast.error(`"${linked.screenName}" 모달 화면의 새 이름을 입력해주세요.`);
|
||||
toast.error(`"${linked.screen_name}" 모달 화면의 새 이름을 입력해주세요.`);
|
||||
return;
|
||||
}
|
||||
if (!linked.newScreenCode?.trim()) {
|
||||
toast.error(`"${linked.screenName}" 모달 화면의 코드가 생성되지 않았습니다.`);
|
||||
toast.error(`"${linked.screen_name}" 모달 화면의 코드가 생성되지 않았습니다.`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -599,7 +599,7 @@ export default function CopyScreenModal({
|
||||
description: description.trim(),
|
||||
},
|
||||
modalScreens: linkedScreens.map((screen) => ({
|
||||
sourceScreenId: screen.screenId,
|
||||
sourceScreenId: screen.screen_id,
|
||||
screenName: screen.newScreenName!.trim(),
|
||||
screenCode: screen.newScreenCode!.trim(),
|
||||
})),
|
||||
@@ -1785,11 +1785,11 @@ export default function CopyScreenModal({
|
||||
</div>
|
||||
<div className="space-y-2 max-h-[150px] overflow-y-auto">
|
||||
{linkedScreens.map((linked) => (
|
||||
<div key={linked.screenId} className="flex items-center justify-between text-xs bg-muted rounded p-2">
|
||||
<div key={linked.screen_id} className="flex items-center justify-between text-xs bg-muted rounded p-2">
|
||||
<div className="flex-1 min-w-0">
|
||||
<Input
|
||||
value={linked.newScreenName || ""}
|
||||
onChange={(e) => updateLinkedScreenName(linked.screenId, e.target.value)}
|
||||
onChange={(e) => updateLinkedScreenName(linked.screen_id, e.target.value)}
|
||||
className="h-7 text-xs"
|
||||
placeholder="모달 화면명"
|
||||
/>
|
||||
@@ -1798,7 +1798,7 @@ export default function CopyScreenModal({
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="h-7 w-7 ml-1 text-destructive"
|
||||
onClick={() => removeLinkedScreen(linked.screenId)}
|
||||
onClick={() => removeLinkedScreen(linked.screen_id)}
|
||||
>
|
||||
<Trash2 className="h-3 w-3" />
|
||||
</Button>
|
||||
|
||||
@@ -264,7 +264,7 @@ export const EditModal: React.FC<EditModalProps> = ({ className }) => {
|
||||
let detailTableName = eventTableName;
|
||||
if (!detailTableName) {
|
||||
const screenInfo = await screenApi.getScreen(targetScreenId);
|
||||
detailTableName = screenInfo?.table_name ?? screenInfo?.tableName;
|
||||
detailTableName = screenInfo?.table_name;
|
||||
}
|
||||
|
||||
if (!detailTableName) {
|
||||
|
||||
@@ -1350,7 +1350,7 @@ export default function ScreenDesigner({
|
||||
const tableListResponse = await tableManagementApi.getTableList();
|
||||
const currentTable =
|
||||
tableListResponse.success && tableListResponse.data
|
||||
? tableListResponse.data.find((t) => t.tableName === tableName)
|
||||
? tableListResponse.data.find((t) => t.table_name === tableName)
|
||||
: null;
|
||||
const tableLabel = currentTable?.display_name || tableName;
|
||||
|
||||
@@ -1359,11 +1359,11 @@ export default function ScreenDesigner({
|
||||
|
||||
const columns: ColumnInfo[] = (columnsResponse || []).map((col: any) => {
|
||||
// widgetType 결정: inputType(entity 등) > webType > widget_type
|
||||
const inputType = col.inputType || col.input_type;
|
||||
const widgetType = inputType || col.widgetType || col.widget_type || col.webType || col.web_type;
|
||||
const inputType = col.input_type;
|
||||
const widgetType = inputType || col.widget_type || col.web_type;
|
||||
|
||||
// detailSettings 파싱 (문자열이면 JSON 파싱)
|
||||
let detailSettings = col.detailSettings || col.detail_settings;
|
||||
let detailSettings = col.detail_settings;
|
||||
if (typeof detailSettings === "string") {
|
||||
// JSON 형식인 경우에만 파싱 시도 (중괄호로 시작하는 경우)
|
||||
if (detailSettings.trim().startsWith("{")) {
|
||||
@@ -1382,33 +1382,33 @@ export default function ScreenDesigner({
|
||||
// 엔티티 타입 디버깅
|
||||
if (inputType === "entity" || widgetType === "entity") {
|
||||
console.log("🔍 엔티티 컬럼 감지:", {
|
||||
columnName: col.columnName || col.column_name,
|
||||
columnName: col.column_name,
|
||||
inputType,
|
||||
widgetType,
|
||||
detailSettings,
|
||||
referenceTable: detailSettings?.referenceTable || col.referenceTable || col.reference_table,
|
||||
referenceTable: detailSettings?.referenceTable || col.reference_table,
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
tableName: col.tableName || tableName,
|
||||
columnName: col.columnName || col.column_name,
|
||||
columnLabel: col.displayName || col.columnLabel || col.column_label || col.columnName || col.column_name,
|
||||
dataType: col.dataType || col.data_type || col.dbType,
|
||||
webType: col.webType || col.web_type,
|
||||
tableName: col.table_name || tableName,
|
||||
columnName: col.column_name,
|
||||
columnLabel: col.display_name || col.column_label || col.column_name,
|
||||
dataType: col.data_type || col.db_type,
|
||||
webType: col.web_type,
|
||||
input_type: inputType,
|
||||
inputType: inputType,
|
||||
widgetType,
|
||||
isNullable: col.isNullable || col.is_nullable,
|
||||
required: col.required !== undefined ? col.required : col.isNullable === "NO" || col.is_nullable === "NO",
|
||||
columnDefault: col.columnDefault || col.column_default,
|
||||
characterMaximumLength: col.characterMaximumLength || col.character_maximum_length,
|
||||
codeCategory: col.codeCategory || col.code_category,
|
||||
codeValue: col.codeValue || col.code_value,
|
||||
isNullable: col.is_nullable,
|
||||
required: col.required !== undefined ? col.required : col.is_nullable === "NO",
|
||||
columnDefault: col.column_default,
|
||||
characterMaximumLength: col.character_maximum_length,
|
||||
codeCategory: col.code_category,
|
||||
codeValue: col.code_value,
|
||||
// 엔티티 타입용 참조 테이블 정보 (detailSettings에서 추출)
|
||||
referenceTable: detailSettings?.referenceTable || col.referenceTable || col.reference_table,
|
||||
referenceColumn: detailSettings?.referenceColumn || col.referenceColumn || col.reference_column,
|
||||
displayColumn: detailSettings?.displayColumn || col.displayColumn || col.display_column,
|
||||
referenceTable: detailSettings?.referenceTable || col.reference_table,
|
||||
referenceColumn: detailSettings?.referenceColumn || col.reference_column,
|
||||
displayColumn: detailSettings?.displayColumn || col.display_column,
|
||||
// detailSettings 전체 보존 (V2 컴포넌트용)
|
||||
detailSettings,
|
||||
};
|
||||
@@ -1455,7 +1455,7 @@ export default function ScreenDesigner({
|
||||
const tableListResponse = await tableManagementApi.getTableList();
|
||||
const currentTable =
|
||||
tableListResponse.success && tableListResponse.data
|
||||
? tableListResponse.data.find((t: any) => (t.tableName || t.table_name) === tableName)
|
||||
? tableListResponse.data.find((t: any) => t.table_name === tableName)
|
||||
: null;
|
||||
const tableLabel = currentTable?.display_name || currentTable?.table_label || tableName;
|
||||
|
||||
@@ -1463,10 +1463,10 @@ export default function ScreenDesigner({
|
||||
const columnsResponse = await tableTypeApi.getColumns(tableName, true);
|
||||
|
||||
const columns: ColumnInfo[] = (columnsResponse || []).map((col: any) => {
|
||||
const inputType = col.inputType || col.input_type;
|
||||
const widgetType = inputType || col.widgetType || col.widget_type || col.webType || col.web_type;
|
||||
const inputType = col.input_type;
|
||||
const widgetType = inputType || col.widget_type || col.web_type;
|
||||
|
||||
let detailSettings = col.detailSettings || col.detail_settings;
|
||||
let detailSettings = col.detail_settings;
|
||||
if (typeof detailSettings === "string") {
|
||||
try {
|
||||
detailSettings = JSON.parse(detailSettings);
|
||||
@@ -1476,23 +1476,23 @@ export default function ScreenDesigner({
|
||||
}
|
||||
|
||||
return {
|
||||
tableName: col.tableName || tableName,
|
||||
columnName: col.columnName || col.column_name,
|
||||
columnLabel: col.displayName || col.columnLabel || col.column_label || col.columnName || col.column_name,
|
||||
dataType: col.dataType || col.data_type || col.dbType,
|
||||
webType: col.webType || col.web_type,
|
||||
tableName: col.table_name || tableName,
|
||||
columnName: col.column_name,
|
||||
columnLabel: col.display_name || col.column_label || col.column_name,
|
||||
dataType: col.data_type || col.db_type,
|
||||
webType: col.web_type,
|
||||
input_type: inputType,
|
||||
inputType: inputType,
|
||||
widgetType,
|
||||
isNullable: col.isNullable || col.is_nullable,
|
||||
required: col.required !== undefined ? col.required : col.isNullable === "NO" || col.is_nullable === "NO",
|
||||
columnDefault: col.columnDefault || col.column_default,
|
||||
characterMaximumLength: col.characterMaximumLength || col.character_maximum_length,
|
||||
codeCategory: col.codeCategory || col.code_category,
|
||||
codeValue: col.codeValue || col.code_value,
|
||||
referenceTable: detailSettings?.referenceTable || col.referenceTable || col.reference_table,
|
||||
referenceColumn: detailSettings?.referenceColumn || col.referenceColumn || col.reference_column,
|
||||
displayColumn: detailSettings?.displayColumn || col.displayColumn || col.display_column,
|
||||
isNullable: col.is_nullable,
|
||||
required: col.required !== undefined ? col.required : col.is_nullable === "NO",
|
||||
columnDefault: col.column_default,
|
||||
characterMaximumLength: col.character_maximum_length,
|
||||
codeCategory: col.code_category,
|
||||
codeValue: col.code_value,
|
||||
referenceTable: detailSettings?.referenceTable || col.reference_table,
|
||||
referenceColumn: detailSettings?.referenceColumn || col.reference_column,
|
||||
displayColumn: detailSettings?.displayColumn || col.display_column,
|
||||
detailSettings,
|
||||
};
|
||||
});
|
||||
@@ -2174,8 +2174,8 @@ export default function ScreenDesigner({
|
||||
if (Array.isArray(columns)) {
|
||||
columnLabelMap[tableName] = {};
|
||||
columns.forEach((col: any) => {
|
||||
const colName = col.columnName || col.column_name || col.name;
|
||||
const colLabel = col.displayName || col.columnLabel || col.column_label || colName;
|
||||
const colName = col.column_name || col.name;
|
||||
const colLabel = col.display_name || col.column_label || colName;
|
||||
if (colName) {
|
||||
columnLabelMap[tableName][colName] = colLabel;
|
||||
}
|
||||
|
||||
@@ -273,12 +273,12 @@ export default function ScreenList({ onScreenSelect, selectedScreen, onDesignScr
|
||||
|
||||
// 최고 관리자이고 특정 회사를 선택한 경우
|
||||
if (isSuperAdmin && selectedCompanyCode !== "all") {
|
||||
params.companyCode = selectedCompanyCode;
|
||||
params.company_code = selectedCompanyCode;
|
||||
}
|
||||
|
||||
// 그룹 필터
|
||||
if (selectedGroupId !== "all") {
|
||||
params.groupId = selectedGroupId;
|
||||
params.group_id = selectedGroupId;
|
||||
}
|
||||
|
||||
console.log("🔍 화면 목록 API 호출:", params); // 디버깅용
|
||||
@@ -325,9 +325,9 @@ export default function ScreenList({ onScreenSelect, selectedScreen, onDesignScr
|
||||
|
||||
// 최고 관리자이고 특정 회사를 선택한 경우
|
||||
if (isSuperAdmin && selectedCompanyCode !== "all") {
|
||||
params.companyCode = selectedCompanyCode;
|
||||
params.company_code = selectedCompanyCode;
|
||||
}
|
||||
|
||||
|
||||
const resp = await screenApi.getScreens(params);
|
||||
setScreens(resp.data || []);
|
||||
setTotalPages(Math.max(1, Math.ceil((resp.total || 0) / 20)));
|
||||
@@ -740,7 +740,7 @@ export default function ScreenList({ onScreenSelect, selectedScreen, onDesignScr
|
||||
<SelectItem value="ungrouped">미분류</SelectItem>
|
||||
{groups.map((group) => (
|
||||
<SelectItem key={group.id} value={String(group.id)}>
|
||||
{group.groupName}
|
||||
{group.group_name}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
|
||||
@@ -189,18 +189,18 @@ export function ScreenRelationView({ screen }: ScreenRelationViewProps) {
|
||||
className="flex items-center gap-2 p-2 rounded-md bg-muted/50 text-sm"
|
||||
>
|
||||
<div className="flex items-center gap-1">
|
||||
<span className="font-mono text-xs">{join.sourceTable}</span>
|
||||
<span className="font-mono text-xs">{join.save_table}</span>
|
||||
<span className="text-muted-foreground">.</span>
|
||||
<span className="font-mono text-xs text-primary">{join.sourceColumn}</span>
|
||||
<span className="font-mono text-xs text-primary">{join.save_column}</span>
|
||||
</div>
|
||||
<ArrowRight className="h-3 w-3 text-muted-foreground" />
|
||||
<div className="flex items-center gap-1">
|
||||
<span className="font-mono text-xs">{join.targetTable}</span>
|
||||
<span className="font-mono text-xs">{join.join_table}</span>
|
||||
<span className="text-muted-foreground">.</span>
|
||||
<span className="font-mono text-xs text-emerald-600">{join.targetColumn}</span>
|
||||
<span className="font-mono text-xs text-emerald-600">{join.join_column}</span>
|
||||
</div>
|
||||
<Badge variant="outline" className="ml-auto text-xs">
|
||||
{join.joinType}
|
||||
{join.join_type}
|
||||
</Badge>
|
||||
</div>
|
||||
))}
|
||||
@@ -231,14 +231,14 @@ export function ScreenRelationView({ screen }: ScreenRelationViewProps) {
|
||||
className="flex items-center gap-2 p-2 rounded-md bg-muted/50 text-sm"
|
||||
>
|
||||
<Monitor className="h-4 w-4 text-primary" />
|
||||
<span className="truncate">{flow.flowName || "이름 없음"}</span>
|
||||
<span className="truncate">{flow.flow_label || "이름 없음"}</span>
|
||||
<ArrowRight className="h-3 w-3 text-muted-foreground" />
|
||||
<Monitor className="h-4 w-4 text-emerald-500" />
|
||||
<span className="text-muted-foreground truncate">
|
||||
화면 #{flow.targetScreenId}
|
||||
화면 #{flow.target_screen_id}
|
||||
</span>
|
||||
<Badge variant="outline" className="ml-auto text-xs">
|
||||
{flow.flowType}
|
||||
{flow.flow_type}
|
||||
</Badge>
|
||||
</div>
|
||||
))}
|
||||
@@ -269,11 +269,11 @@ export function ScreenRelationView({ screen }: ScreenRelationViewProps) {
|
||||
className="flex items-center gap-2 p-2 rounded-md bg-muted/50 text-sm"
|
||||
>
|
||||
<Table className="h-4 w-4 text-muted-foreground" />
|
||||
<span className="font-mono text-xs">{relation.parentTable}</span>
|
||||
<span className="font-mono text-xs">{screen.table_name}</span>
|
||||
<ArrowRight className="h-3 w-3 text-muted-foreground" />
|
||||
<span className="font-mono text-xs">{relation.childTable}</span>
|
||||
<span className="font-mono text-xs">{relation.table_name}</span>
|
||||
<Badge variant="outline" className="ml-auto text-xs">
|
||||
{relation.relationType}
|
||||
{relation.relation_type}
|
||||
</Badge>
|
||||
</div>
|
||||
))}
|
||||
|
||||
+13
-13
@@ -61,10 +61,10 @@ export const dataApi = {
|
||||
try {
|
||||
const params: any = {};
|
||||
if (enableEntityJoin) {
|
||||
params.enableEntityJoin = true;
|
||||
params.enable_entity_join = true;
|
||||
}
|
||||
if (groupByColumns.length > 0) {
|
||||
params.groupByColumns = JSON.stringify(groupByColumns);
|
||||
params.group_by_columns = JSON.stringify(groupByColumns);
|
||||
}
|
||||
|
||||
console.log("🌐 [dataApi.getRecordDetail] API 호출:", {
|
||||
@@ -123,14 +123,14 @@ export const dataApi = {
|
||||
): Promise<any[]> => {
|
||||
const response = await apiClient.get(`/data/join`, {
|
||||
params: {
|
||||
leftTable,
|
||||
rightTable,
|
||||
leftColumn,
|
||||
rightColumn,
|
||||
leftValue,
|
||||
dataFilter: dataFilter ? JSON.stringify(dataFilter) : undefined,
|
||||
enableEntityJoin: enableEntityJoin ?? true,
|
||||
displayColumns: displayColumns ? JSON.stringify(displayColumns) : undefined, // 🆕 표시 컬럼 전달
|
||||
left_table: leftTable,
|
||||
right_table: rightTable,
|
||||
left_column: leftColumn,
|
||||
right_column: rightColumn,
|
||||
left_value: leftValue,
|
||||
data_filter: dataFilter ? JSON.stringify(dataFilter) : undefined,
|
||||
enable_entity_join: enableEntityJoin ?? true,
|
||||
display_columns: displayColumns ? JSON.stringify(displayColumns) : undefined, // 🆕 표시 컬럼 전달
|
||||
deduplication: deduplication ? JSON.stringify(deduplication) : undefined, // 🆕 중복 제거 설정 전달
|
||||
},
|
||||
});
|
||||
@@ -215,7 +215,7 @@ export const dataApi = {
|
||||
try {
|
||||
const params: any = {};
|
||||
if (enableEntityJoin) {
|
||||
params.enableEntityJoin = "true";
|
||||
params.enable_entity_join = "true";
|
||||
}
|
||||
const response = await apiClient.get(`/data/${tableName}/${id}`, { params });
|
||||
return response.data; // { success: true, data: ... } 형식 그대로 반환
|
||||
@@ -249,10 +249,10 @@ export const dataApi = {
|
||||
});
|
||||
|
||||
const requestBody = {
|
||||
tableName,
|
||||
table_name: tableName,
|
||||
parentKeys,
|
||||
records,
|
||||
deleteOrphans: options?.deleteOrphans ?? true, // 기본값: true (기존 동작 유지)
|
||||
delete_orphans: options?.deleteOrphans ?? true, // 기본값: true (기존 동작 유지)
|
||||
};
|
||||
console.log("📦 [dataApi.upsertGroupedRecords] 요청 본문 (JSON):", JSON.stringify(requestBody, null, 2));
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ export const loadDataflowRelationship = async (diagramId: number) => {
|
||||
let relationshipsData;
|
||||
|
||||
// Case 1: 현재 구조 - relationships 자체가 관계 데이터
|
||||
if (diagram.relationships && (diagram.relationships.connection_type || diagram.relationships.connectionType)) {
|
||||
if (diagram.relationships && diagram.relationships.connection_type) {
|
||||
relationshipsData = diagram.relationships;
|
||||
console.log("✅ 현재 구조 감지 (relationships 직접):", relationshipsData);
|
||||
}
|
||||
@@ -85,22 +85,22 @@ export const loadDataflowRelationship = async (diagramId: number) => {
|
||||
// 기존 구조를 redesigned 구조로 변환
|
||||
relationshipsData = {
|
||||
description: firstRelation.note || "",
|
||||
connectionType: firstRelation.connection_type || firstRelation.connectionType || "data_save",
|
||||
fromConnection: { id: 0, name: "메인 데이터베이스 (현재 시스템)" }, // 기본값
|
||||
toConnection: { id: 0, name: "메인 데이터베이스 (현재 시스템)" }, // 기본값
|
||||
fromTable: firstRelation.from_table || firstRelation.fromTable,
|
||||
toTable: firstRelation.to_table || firstRelation.toTable,
|
||||
actionType: "insert", // 기본값
|
||||
controlConditions: [],
|
||||
actionConditions: [],
|
||||
fieldMappings: [],
|
||||
connection_type: firstRelation.connection_type || "data_save",
|
||||
from_connection: { id: 0, name: "메인 데이터베이스 (현재 시스템)" }, // 기본값
|
||||
to_connection: { id: 0, name: "메인 데이터베이스 (현재 시스템)" }, // 기본값
|
||||
from_table: firstRelation.from_table,
|
||||
to_table: firstRelation.to_table,
|
||||
action_type: "insert", // 기본값
|
||||
control_conditions: [],
|
||||
action_conditions: [],
|
||||
field_mappings: [],
|
||||
};
|
||||
|
||||
// 기존 control 및 plan 데이터를 변환
|
||||
if (diagram.control && diagram.control.length > 0) {
|
||||
const control = diagram.control.find((c) => c.id === firstRelation.id);
|
||||
if (control && control.conditions) {
|
||||
relationshipsData.controlConditions = control.conditions;
|
||||
relationshipsData.control_conditions = control.conditions;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,9 +108,9 @@ export const loadDataflowRelationship = async (diagramId: number) => {
|
||||
const plan = diagram.plan.find((p) => p.id === firstRelation.id);
|
||||
if (plan && plan.actions && plan.actions.length > 0) {
|
||||
const firstAction = plan.actions[0];
|
||||
relationshipsData.actionType = firstAction.action_type || firstAction.actionType || "insert";
|
||||
relationshipsData.fieldMappings = firstAction.field_mappings || firstAction.fieldMappings || [];
|
||||
relationshipsData.actionConditions = firstAction.action_conditions || firstAction.conditions || [];
|
||||
relationshipsData.action_type = firstAction.action_type || "insert";
|
||||
relationshipsData.field_mappings = firstAction.field_mappings || [];
|
||||
relationshipsData.action_conditions = firstAction.action_conditions || firstAction.conditions || [];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -121,18 +121,18 @@ export const loadDataflowRelationship = async (diagramId: number) => {
|
||||
// 현재 DB에 저장된 구조 처리 (relationships 객체에 모든 데이터가 있음)
|
||||
relationshipsData = {
|
||||
description: diagram.relationships.description || "",
|
||||
connection_type: diagram.relationships.connection_type || diagram.relationships.connectionType || "data_save",
|
||||
from_connection: diagram.relationships.from_connection || diagram.relationships.fromConnection || { id: 0, name: "메인 데이터베이스 (현재 시스템)" },
|
||||
to_connection: diagram.relationships.to_connection || diagram.relationships.toConnection || { id: 0, name: "메인 데이터베이스 (현재 시스템)" },
|
||||
from_table: diagram.relationships.from_table || diagram.relationships.fromTable,
|
||||
to_table: diagram.relationships.to_table || diagram.relationships.toTable,
|
||||
action_type: diagram.relationships.action_type || diagram.relationships.actionType || "insert",
|
||||
control_conditions: diagram.relationships.control_conditions || diagram.relationships.controlConditions || [],
|
||||
action_conditions: diagram.relationships.action_conditions || diagram.relationships.actionConditions || [],
|
||||
field_mappings: diagram.relationships.field_mappings || diagram.relationships.fieldMappings || [],
|
||||
connection_type: diagram.relationships.connection_type || "data_save",
|
||||
from_connection: diagram.relationships.from_connection || { id: 0, name: "메인 데이터베이스 (현재 시스템)" },
|
||||
to_connection: diagram.relationships.to_connection || { id: 0, name: "메인 데이터베이스 (현재 시스템)" },
|
||||
from_table: diagram.relationships.from_table,
|
||||
to_table: diagram.relationships.to_table,
|
||||
action_type: diagram.relationships.action_type || "insert",
|
||||
control_conditions: diagram.relationships.control_conditions || [],
|
||||
action_conditions: diagram.relationships.action_conditions || [],
|
||||
field_mappings: diagram.relationships.field_mappings || [],
|
||||
// 🔧 멀티 액션 그룹 데이터 로드
|
||||
action_groups: diagram.relationships.action_groups || diagram.relationships.actionGroups || null,
|
||||
external_call_config: diagram.relationships.external_call_config || diagram.relationships.externalCallConfig,
|
||||
action_groups: diagram.relationships.action_groups || null,
|
||||
external_call_config: diagram.relationships.external_call_config,
|
||||
};
|
||||
console.log("✅ 현재 DB 구조 처리 완료:", relationshipsData);
|
||||
} else {
|
||||
@@ -146,19 +146,19 @@ export const loadDataflowRelationship = async (diagramId: number) => {
|
||||
diagramId: diagram.diagram_id, // 🔧 수정 모드를 위한 diagramId 추가
|
||||
relationshipName: diagram.diagram_name,
|
||||
description: relationshipsData.description || diagram.description || "", // 🔧 diagram.description도 확인
|
||||
connectionType: relationshipsData.connection_type || relationshipsData.connectionType || "data_save",
|
||||
fromConnection: relationshipsData.from_connection || relationshipsData.fromConnection || { id: 0, name: "메인 데이터베이스 (현재 시스템)" },
|
||||
toConnection: relationshipsData.to_connection || relationshipsData.toConnection || { id: 0, name: "메인 데이터베이스 (현재 시스템)" },
|
||||
fromTable: relationshipsData.from_table || relationshipsData.fromTable,
|
||||
toTable: relationshipsData.to_table || relationshipsData.toTable,
|
||||
actionType: relationshipsData.action_type || relationshipsData.actionType || "insert",
|
||||
controlConditions: relationshipsData.control_conditions || relationshipsData.controlConditions || [],
|
||||
actionConditions: relationshipsData.action_conditions || relationshipsData.actionConditions || [],
|
||||
fieldMappings: relationshipsData.field_mappings || relationshipsData.fieldMappings || [],
|
||||
connectionType: relationshipsData.connection_type || "data_save",
|
||||
fromConnection: relationshipsData.from_connection || { id: 0, name: "메인 데이터베이스 (현재 시스템)" },
|
||||
toConnection: relationshipsData.to_connection || { id: 0, name: "메인 데이터베이스 (현재 시스템)" },
|
||||
fromTable: relationshipsData.from_table,
|
||||
toTable: relationshipsData.to_table,
|
||||
actionType: relationshipsData.action_type || "insert",
|
||||
controlConditions: relationshipsData.control_conditions || [],
|
||||
actionConditions: relationshipsData.action_conditions || [],
|
||||
fieldMappings: relationshipsData.field_mappings || [],
|
||||
// 🔧 멀티 액션 그룹 데이터 포함
|
||||
actionGroups: relationshipsData.action_groups || relationshipsData.actionGroups,
|
||||
actionGroups: relationshipsData.action_groups,
|
||||
// 🔧 외부호출 설정 데이터 포함
|
||||
externalCallConfig: relationshipsData.external_call_config || relationshipsData.externalCallConfig,
|
||||
externalCallConfig: relationshipsData.external_call_config,
|
||||
};
|
||||
|
||||
console.log("✨ 변환된 로드 데이터:", loadedData);
|
||||
|
||||
@@ -247,8 +247,8 @@ export class DynamicFormApi {
|
||||
page?: number;
|
||||
size?: number;
|
||||
search?: string;
|
||||
sortBy?: string;
|
||||
sortOrder?: "asc" | "desc";
|
||||
sort_by?: string;
|
||||
sort_order?: "asc" | "desc";
|
||||
},
|
||||
): Promise<
|
||||
ApiResponse<{
|
||||
@@ -433,12 +433,12 @@ export class DynamicFormApi {
|
||||
tableName: string,
|
||||
params?: {
|
||||
page?: number;
|
||||
pageSize?: number;
|
||||
page_size?: number;
|
||||
search?: string;
|
||||
sortBy?: string;
|
||||
sortOrder?: "asc" | "desc";
|
||||
sort_by?: string;
|
||||
sort_order?: "asc" | "desc";
|
||||
filters?: Record<string, any>;
|
||||
autoFilter?: {
|
||||
auto_filter?: {
|
||||
enabled: boolean;
|
||||
filter_column?: string;
|
||||
user_field?: string;
|
||||
@@ -452,8 +452,8 @@ export class DynamicFormApi {
|
||||
// pageSize를 size로 변환 (백엔드 파라미터명 호환)
|
||||
const requestParams = {
|
||||
...params,
|
||||
size: params?.pageSize || params?.size || 100, // 기본값 100
|
||||
autoFilter: params?.autoFilter ?? {
|
||||
size: params?.page_size || params?.size || 100, // 기본값 100
|
||||
auto_filter: params?.auto_filter ?? {
|
||||
enabled: true,
|
||||
filter_column: "company_code",
|
||||
user_field: "company_code",
|
||||
@@ -533,10 +533,10 @@ export class DynamicFormApi {
|
||||
* @returns 업로드 결과
|
||||
*/
|
||||
static async uploadExcelData(payload: {
|
||||
tableName: string;
|
||||
table_name: string;
|
||||
data: any[];
|
||||
uploadMode: "insert" | "update" | "upsert";
|
||||
keyColumn?: string;
|
||||
upload_mode: "insert" | "update" | "upsert";
|
||||
key_column?: string;
|
||||
}): Promise<ApiResponse<any>> {
|
||||
try {
|
||||
console.log("📤 엑셀 업로드 요청:", payload);
|
||||
|
||||
@@ -22,7 +22,7 @@ export interface FileUploadResponse {
|
||||
export interface FileDownloadParams {
|
||||
fileId: string;
|
||||
server_filename: string;
|
||||
originalName: string;
|
||||
original_name: string;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -89,7 +89,7 @@ export const downloadFile = async (params: FileDownloadParams): Promise<void> =>
|
||||
const response = await apiClient.get(`/files/download/${params.fileId}`, {
|
||||
params: {
|
||||
server_filename: params.server_filename,
|
||||
originalName: params.originalName,
|
||||
original_name: params.original_name,
|
||||
},
|
||||
responseType: "blob", // 파일 다운로드를 위해 blob 타입으로 설정
|
||||
});
|
||||
@@ -103,7 +103,7 @@ export const downloadFile = async (params: FileDownloadParams): Promise<void> =>
|
||||
// 다운로드 링크 생성 및 클릭
|
||||
const link = document.createElement("a");
|
||||
link.href = url;
|
||||
link.download = params.originalName;
|
||||
link.download = params.original_name;
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
|
||||
|
||||
@@ -358,7 +358,7 @@ export const screenApi = {
|
||||
// 연결된 모달 화면 감지
|
||||
detectLinkedModals: async (
|
||||
screenId: number,
|
||||
): Promise<Array<{ screenId: number; screenName: string; screenCode: string }>> => {
|
||||
): Promise<Array<{ screen_id: number; screen_name: string; screen_code: string }>> => {
|
||||
const response = await apiClient.get(`/screen-management/screens/${screenId}/linked-modals`);
|
||||
return response.data.data || [];
|
||||
},
|
||||
|
||||
@@ -823,8 +823,8 @@ const FileUploadComponent: React.FC<FileUploadComponentProps> = ({
|
||||
try {
|
||||
await downloadFile({
|
||||
fileId: file.objid,
|
||||
serverFilename: file.savedFileName,
|
||||
originalName: file.realFileName,
|
||||
server_filename: file.savedFileName,
|
||||
original_name: file.realFileName,
|
||||
});
|
||||
toast.success(`${file.realFileName} 다운로드 완료`);
|
||||
} catch (error) {
|
||||
@@ -934,7 +934,7 @@ const FileUploadComponent: React.FC<FileUploadComponentProps> = ({
|
||||
// 🔑 previewUrl 상대 경로 대신 apiClient를 사용하여 Docker 환경에서도 정상 동작
|
||||
const response = await apiClient.get(`/files/preview/${file.objid}`, {
|
||||
params: {
|
||||
serverFilename: file.savedFileName,
|
||||
server_filename: file.savedFileName,
|
||||
},
|
||||
responseType: "blob",
|
||||
});
|
||||
|
||||
+5
-5
@@ -1656,7 +1656,7 @@ export const SplitPanelLayoutConfigPanel: React.FC<SplitPanelLayoutConfigPanelPr
|
||||
required: col.required !== undefined ? col.required : col.is_nullable === "NO",
|
||||
columnDefault: col.column_default,
|
||||
characterMaximumLength: col.character_maximum_length,
|
||||
isPrimaryKey: col.isPrimaryKey || false, // PK 여부 추가
|
||||
isPrimaryKey: col.is_primary_key || false, // PK 여부 추가
|
||||
codeCategory: col.code_category,
|
||||
codeValue: col.code_value,
|
||||
referenceTable: col.reference_table, // 🆕 참조 테이블
|
||||
@@ -1776,8 +1776,8 @@ export const SplitPanelLayoutConfigPanel: React.FC<SplitPanelLayoutConfigPanelPr
|
||||
// 🆕 좌측/우측 테이블이 모두 선택되면 엔티티 관계 자동 감지
|
||||
const [autoDetectedRelations, setAutoDetectedRelations] = useState<
|
||||
Array<{
|
||||
leftColumn: string;
|
||||
rightColumn: string;
|
||||
left_column: string;
|
||||
right_column: string;
|
||||
direction: "left_to_right" | "right_to_left";
|
||||
inputType: string;
|
||||
displayColumn?: string;
|
||||
@@ -1818,8 +1818,8 @@ export const SplitPanelLayoutConfigPanel: React.FC<SplitPanelLayoutConfigPanelPr
|
||||
useMultipleKeys: true,
|
||||
keys: [
|
||||
{
|
||||
leftColumn: firstRel.leftColumn,
|
||||
rightColumn: firstRel.rightColumn,
|
||||
leftColumn: firstRel.left_column,
|
||||
rightColumn: firstRel.right_column,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
+3
-3
@@ -116,10 +116,10 @@ export const LeftPanelConfigTab: React.FC<LeftPanelConfigTabProps> = ({
|
||||
)}
|
||||
<CommandGroup heading="전체 테이블">
|
||||
{allTables
|
||||
.filter((t) => (t.tableName || t.table_name) !== screenTableName)
|
||||
.filter((t) => t.table_name !== screenTableName)
|
||||
.map((table) => {
|
||||
const tableName = table.tableName || table.table_name;
|
||||
const displayName = table.tableLabel || table.displayName || tableName;
|
||||
const tableName = table.table_name;
|
||||
const displayName = table.table_label || table.display_name || tableName;
|
||||
return (
|
||||
<CommandItem
|
||||
key={tableName}
|
||||
|
||||
@@ -264,8 +264,8 @@ export class DataflowJobQueue {
|
||||
|
||||
try {
|
||||
const response = await apiClient.post("/api/button-dataflow/execute-background", {
|
||||
buttonId: job.buttonId,
|
||||
actionType: job.actionType,
|
||||
button_id: job.buttonId,
|
||||
action_type: job.actionType,
|
||||
buttonConfig: config,
|
||||
contextData,
|
||||
companyCode,
|
||||
|
||||
@@ -484,8 +484,8 @@ export class ImprovedButtonActionExecutor {
|
||||
|
||||
// 백엔드 프록시 API 호출 - GenericApiSettings 형식에 맞게 전달
|
||||
const requestPayload = {
|
||||
diagramId: relationships.diagramId || 45, // 관계 ID 사용
|
||||
relationshipId: relationships.relationshipId || "relationship-45",
|
||||
diagram_id: relationships.diagramId || 45, // 관계 ID 사용
|
||||
relationship_id: relationships.relationshipId || "relationship-45",
|
||||
settings: {
|
||||
callType: "rest-api",
|
||||
apiType: "generic",
|
||||
@@ -497,7 +497,7 @@ export class ImprovedButtonActionExecutor {
|
||||
timeout: restApiSettings.timeout || 30000,
|
||||
retryCount: restApiSettings.retryCount || 3,
|
||||
},
|
||||
templateData: restApiSettings.httpMethod !== "GET" && requestBody ? JSON.parse(requestBody) : formData,
|
||||
template_data: restApiSettings.httpMethod !== "GET" && requestBody ? JSON.parse(requestBody) : formData,
|
||||
};
|
||||
|
||||
console.log("📤 백엔드로 전송할 데이터:", requestPayload);
|
||||
@@ -706,9 +706,9 @@ export class ImprovedButtonActionExecutor {
|
||||
|
||||
// 데이터 저장 API 호출 (apiClient 사용)
|
||||
const response = await apiClient.post("/dataflow/execute-data-action", {
|
||||
tableName,
|
||||
table_name: tableName,
|
||||
data,
|
||||
actionType,
|
||||
action_type: actionType,
|
||||
connection,
|
||||
});
|
||||
|
||||
|
||||
@@ -136,13 +136,13 @@ async function fetchBatchTranslations(
|
||||
const response = await apiClient.post(
|
||||
"/multilang/batch",
|
||||
{
|
||||
langKeys: keys,
|
||||
lang_keys: keys,
|
||||
},
|
||||
{
|
||||
params: {
|
||||
companyCode,
|
||||
menuCode,
|
||||
userLang,
|
||||
company_code: companyCode,
|
||||
menu_code: menuCode,
|
||||
user_lang: userLang,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user