Merge branch 'main' of http://39.117.244.52:3000/kjs/ERP-node into feature/v2-unified-renewal
This commit is contained in:
@@ -78,6 +78,7 @@ import StyleEditor from "./StyleEditor";
|
||||
import { RealtimePreview } from "./RealtimePreviewDynamic";
|
||||
import FloatingPanel from "./FloatingPanel";
|
||||
import { DynamicComponentRenderer } from "@/lib/registry/DynamicComponentRenderer";
|
||||
import { MultilangSettingsModal } from "./modals/MultilangSettingsModal";
|
||||
import DesignerToolbar from "./DesignerToolbar";
|
||||
import TablesPanel from "./panels/TablesPanel";
|
||||
import { TemplatesPanel, TemplateComponent } from "./panels/TemplatesPanel";
|
||||
@@ -144,6 +145,8 @@ export default function ScreenDesigner({ selectedScreen, onBackToList }: ScreenD
|
||||
},
|
||||
});
|
||||
const [isSaving, setIsSaving] = useState(false);
|
||||
const [isGeneratingMultilang, setIsGeneratingMultilang] = useState(false);
|
||||
const [showMultilangSettingsModal, setShowMultilangSettingsModal] = useState(false);
|
||||
|
||||
// 🆕 화면에 할당된 메뉴 OBJID
|
||||
const [menuObjid, setMenuObjid] = useState<number | undefined>(undefined);
|
||||
@@ -1474,6 +1477,101 @@ export default function ScreenDesigner({ selectedScreen, onBackToList }: ScreenD
|
||||
}
|
||||
}, [selectedScreen, layout, screenResolution]);
|
||||
|
||||
// 다국어 자동 생성 핸들러
|
||||
const handleGenerateMultilang = useCallback(async () => {
|
||||
if (!selectedScreen?.screenId) {
|
||||
toast.error("화면 정보가 없습니다.");
|
||||
return;
|
||||
}
|
||||
|
||||
setIsGeneratingMultilang(true);
|
||||
|
||||
try {
|
||||
// 공통 유틸 사용하여 라벨 추출
|
||||
const { extractMultilangLabels, extractTableNames, applyMultilangMappings } = await import(
|
||||
"@/lib/utils/multilangLabelExtractor"
|
||||
);
|
||||
const { apiClient } = await import("@/lib/api/client");
|
||||
|
||||
// 테이블별 컬럼 라벨 로드
|
||||
const tableNames = extractTableNames(layout.components);
|
||||
const columnLabelMap: Record<string, Record<string, string>> = {};
|
||||
|
||||
for (const tableName of tableNames) {
|
||||
try {
|
||||
const response = await apiClient.get(`/table-management/tables/${tableName}/columns`);
|
||||
if (response.data?.success && response.data?.data) {
|
||||
const columns = response.data.data.columns || response.data.data;
|
||||
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;
|
||||
if (colName) {
|
||||
columnLabelMap[tableName][colName] = colLabel;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`컬럼 라벨 조회 실패 (${tableName}):`, error);
|
||||
}
|
||||
}
|
||||
|
||||
// 라벨 추출 (다국어 설정과 동일한 로직)
|
||||
const extractedLabels = extractMultilangLabels(layout.components, columnLabelMap);
|
||||
const labels = extractedLabels.map((l) => ({
|
||||
componentId: l.componentId,
|
||||
label: l.label,
|
||||
type: l.type,
|
||||
}));
|
||||
|
||||
if (labels.length === 0) {
|
||||
toast.info("다국어로 변환할 라벨이 없습니다.");
|
||||
setIsGeneratingMultilang(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// API 호출
|
||||
const { generateScreenLabelKeys } = await import("@/lib/api/multilang");
|
||||
const response = await generateScreenLabelKeys({
|
||||
screenId: selectedScreen.screenId,
|
||||
menuObjId: menuObjid?.toString(),
|
||||
labels,
|
||||
});
|
||||
|
||||
if (response.success && response.data) {
|
||||
// 자동 매핑 적용
|
||||
const updatedComponents = applyMultilangMappings(layout.components, response.data);
|
||||
|
||||
// 레이아웃 업데이트
|
||||
const updatedLayout = {
|
||||
...layout,
|
||||
components: updatedComponents,
|
||||
screenResolution: screenResolution,
|
||||
};
|
||||
|
||||
setLayout(updatedLayout);
|
||||
|
||||
// 자동 저장 (매핑 정보가 손실되지 않도록)
|
||||
try {
|
||||
await screenApi.saveLayout(selectedScreen.screenId, updatedLayout);
|
||||
toast.success(`${response.data.length}개의 다국어 키가 생성되고 자동 저장되었습니다.`);
|
||||
} catch (saveError) {
|
||||
console.error("다국어 매핑 저장 실패:", saveError);
|
||||
toast.warning(`${response.data.length}개의 다국어 키가 생성되었습니다. 저장 버튼을 눌러 매핑을 저장하세요.`);
|
||||
}
|
||||
} else {
|
||||
toast.error(response.error?.details || "다국어 키 생성에 실패했습니다.");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("다국어 생성 실패:", error);
|
||||
toast.error("다국어 키 생성 중 오류가 발생했습니다.");
|
||||
} finally {
|
||||
setIsGeneratingMultilang(false);
|
||||
}
|
||||
}, [selectedScreen, layout, screenResolution, menuObjid]);
|
||||
|
||||
// 템플릿 드래그 처리
|
||||
const handleTemplateDrop = useCallback(
|
||||
(e: React.DragEvent, template: TemplateComponent) => {
|
||||
@@ -4255,6 +4353,9 @@ export default function ScreenDesigner({ selectedScreen, onBackToList }: ScreenD
|
||||
onResolutionChange={setScreenResolution}
|
||||
gridSettings={layout.gridSettings}
|
||||
onGridSettingsChange={updateGridSettings}
|
||||
onGenerateMultilang={handleGenerateMultilang}
|
||||
isGeneratingMultilang={isGeneratingMultilang}
|
||||
onOpenMultilangSettings={() => setShowMultilangSettingsModal(true)}
|
||||
/>
|
||||
{/* 메인 컨테이너 (좌측 툴바 + 패널들 + 캔버스) */}
|
||||
<div className="flex flex-1 overflow-hidden">
|
||||
@@ -5033,6 +5134,42 @@ export default function ScreenDesigner({ selectedScreen, onBackToList }: ScreenD
|
||||
screenId={selectedScreen.screenId}
|
||||
/>
|
||||
)}
|
||||
{/* 다국어 설정 모달 */}
|
||||
<MultilangSettingsModal
|
||||
isOpen={showMultilangSettingsModal}
|
||||
onClose={() => setShowMultilangSettingsModal(false)}
|
||||
components={layout.components}
|
||||
onSave={async (updates) => {
|
||||
if (updates.length === 0) {
|
||||
toast.info("저장할 변경사항이 없습니다.");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 공통 유틸 사용하여 매핑 적용
|
||||
const { applyMultilangMappings } = await import("@/lib/utils/multilangLabelExtractor");
|
||||
|
||||
// 매핑 형식 변환
|
||||
const mappings = updates.map((u) => ({
|
||||
componentId: u.componentId,
|
||||
keyId: u.langKeyId,
|
||||
langKey: u.langKey,
|
||||
}));
|
||||
|
||||
// 레이아웃 업데이트
|
||||
const updatedComponents = applyMultilangMappings(layout.components, mappings);
|
||||
setLayout((prev) => ({
|
||||
...prev,
|
||||
components: updatedComponents,
|
||||
}));
|
||||
|
||||
toast.success(`${updates.length}개 항목의 다국어 설정이 저장되었습니다.`);
|
||||
} catch (error) {
|
||||
console.error("다국어 설정 저장 실패:", error);
|
||||
toast.error("다국어 설정 저장 중 오류가 발생했습니다.");
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</TableOptionsProvider>
|
||||
</ScreenPreviewProvider>
|
||||
|
||||
Reference in New Issue
Block a user