feat: 메뉴 복사 기능 - 2단계 복사 방식으로 화면 참조 매핑 문제 해결
- 문제: 화면 복사 시 참조되는 화면이 아직 복사되지 않아 screenIdMap에 매핑 정보가 없었음 - 해결: 2단계 복사 방식 도입 1단계: 모든 screen_definitions 먼저 복사하여 screenIdMap 완성 2단계: screen_layouts 복사하면서 완성된 screenIdMap으로 참조 업데이트 - 결과: targetScreenId가 올바르게 새 회사의 화면 ID로 매핑됨 (예: 149 → 517) - 추가: 화면 수집 시 문자열 타입 ID도 올바르게 파싱하도록 개선 - 추가: 참조 화면 발견 및 업데이트 로그 추가 관련 파일: - backend-node/src/services/menuCopyService.ts - db/migrations/1003_add_source_menu_objid_to_menu_info.sql - db/scripts/cleanup_company_11_*.sql
This commit is contained in:
@@ -5,6 +5,7 @@ import { menuApi } from "@/lib/api/menu";
|
||||
import type { MenuItem } from "@/lib/api/menu";
|
||||
import { MenuTable } from "./MenuTable";
|
||||
import { MenuFormModal } from "./MenuFormModal";
|
||||
import { MenuCopyDialog } from "./MenuCopyDialog";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { LoadingSpinner, LoadingOverlay } from "@/components/common/LoadingSpinner";
|
||||
import { toast } from "sonner";
|
||||
@@ -25,17 +26,21 @@ import { useMenu } from "@/contexts/MenuContext";
|
||||
import { useMenuManagementText, setTranslationCache, getMenuTextSync } from "@/lib/utils/multilang";
|
||||
import { useMultiLang } from "@/hooks/useMultiLang";
|
||||
import { apiClient } from "@/lib/api/client";
|
||||
import { useAuth } from "@/hooks/useAuth"; // useAuth 추가
|
||||
|
||||
type MenuType = "admin" | "user";
|
||||
|
||||
export const MenuManagement: React.FC = () => {
|
||||
const { adminMenus, userMenus, refreshMenus } = useMenu();
|
||||
const { user } = useAuth(); // 현재 사용자 정보 가져오기
|
||||
const [selectedMenuType, setSelectedMenuType] = useState<MenuType>("admin");
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [deleting, setDeleting] = useState(false);
|
||||
const [formModalOpen, setFormModalOpen] = useState(false);
|
||||
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
|
||||
const [copyDialogOpen, setCopyDialogOpen] = useState(false);
|
||||
const [selectedMenuId, setSelectedMenuId] = useState<string>("");
|
||||
const [selectedMenuName, setSelectedMenuName] = useState<string>("");
|
||||
const [selectedMenus, setSelectedMenus] = useState<Set<string>>(new Set());
|
||||
|
||||
// 메뉴 관리 화면용 로컬 상태 (모든 상태의 메뉴 표시)
|
||||
@@ -46,6 +51,9 @@ export const MenuManagement: React.FC = () => {
|
||||
// getMenuText는 더 이상 사용하지 않음 - getUITextSync만 사용
|
||||
const { userLang } = useMultiLang({ companyCode: "*" });
|
||||
|
||||
// SUPER_ADMIN 여부 확인
|
||||
const isSuperAdmin = user?.userType === "SUPER_ADMIN";
|
||||
|
||||
// 다국어 텍스트 상태
|
||||
const [uiTexts, setUiTexts] = useState<Record<string, string>>({});
|
||||
const [uiTextsLoading, setUiTextsLoading] = useState(false);
|
||||
@@ -749,6 +757,18 @@ export const MenuManagement: React.FC = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const handleCopyMenu = (menuId: string, menuName: string) => {
|
||||
setSelectedMenuId(menuId);
|
||||
setSelectedMenuName(menuName);
|
||||
setCopyDialogOpen(true);
|
||||
};
|
||||
|
||||
const handleCopyComplete = async () => {
|
||||
// 복사 완료 후 메뉴 목록 새로고침
|
||||
await loadMenus(false);
|
||||
toast.success("메뉴 복사가 완료되었습니다");
|
||||
};
|
||||
|
||||
const handleToggleStatus = async (menuId: string) => {
|
||||
try {
|
||||
const response = await menuApi.toggleMenuStatus(menuId);
|
||||
@@ -1062,6 +1082,7 @@ export const MenuManagement: React.FC = () => {
|
||||
title=""
|
||||
onAddMenu={handleAddMenu}
|
||||
onEditMenu={handleEditMenu}
|
||||
onCopyMenu={handleCopyMenu}
|
||||
onToggleStatus={handleToggleStatus}
|
||||
selectedMenus={selectedMenus}
|
||||
onMenuSelectionChange={handleMenuSelectionChange}
|
||||
@@ -1069,6 +1090,7 @@ export const MenuManagement: React.FC = () => {
|
||||
expandedMenus={expandedMenus}
|
||||
onToggleExpand={handleToggleExpand}
|
||||
uiTexts={uiTexts}
|
||||
isSuperAdmin={isSuperAdmin} // SUPER_ADMIN 여부 전달
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1101,6 +1123,14 @@ export const MenuManagement: React.FC = () => {
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
</AlertDialog>
|
||||
|
||||
<MenuCopyDialog
|
||||
menuObjid={selectedMenuId ? parseInt(selectedMenuId, 10) : null}
|
||||
menuName={selectedMenuName}
|
||||
open={copyDialogOpen}
|
||||
onOpenChange={setCopyDialogOpen}
|
||||
onCopyComplete={handleCopyComplete}
|
||||
/>
|
||||
</LoadingOverlay>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user