Merge branch 'main' of http://39.117.244.52:3000/kjs/ERP-node into feature/prisma-to-raw-query-phase1-complete

This commit is contained in:
kjs
2025-10-01 11:28:00 +09:00
58 changed files with 4604 additions and 1464 deletions

View File

@@ -2,6 +2,7 @@ import {
Users, Shield, Settings, BarChart3, Palette, Layout, Database, Package
} from "lucide-react";
import Link from "next/link";
import { GlobalFileViewer } from "@/components/GlobalFileViewer";
/**
* 관리자 메인 페이지
@@ -199,6 +200,16 @@ export default function AdminPage() {
</Link>
</div>
</div>
{/* 전역 파일 관리 */}
<div className="mx-auto max-w-7xl space-y-6">
<div className="text-center mb-6">
<h2 className="text-2xl font-bold text-gray-900 mb-2"> </h2>
<p className="text-gray-600"> </p>
</div>
<GlobalFileViewer />
</div>
</div>
</div>
);

View File

@@ -13,6 +13,7 @@ import { useRouter } from "next/navigation";
import { toast } from "sonner";
import { initializeComponents } from "@/lib/registry/components";
import { EditModal } from "@/components/screen/EditModal";
import { isFileComponent, getComponentWebType } from "@/lib/utils/componentTypeUtils";
// import { ResponsiveScreenContainer } from "@/components/screen/ResponsiveScreenContainer"; // 컨테이너 제거
export default function ScreenViewPage() {
@@ -116,10 +117,10 @@ export default function ScreenViewPage() {
if (loading) {
return (
<div className="flex h-full min-h-[400px] w-full items-center justify-center bg-white">
<div className="text-center">
<Loader2 className="mx-auto h-8 w-8 animate-spin text-blue-600" />
<p className="mt-2 text-gray-600"> ...</p>
<div className="flex h-full min-h-[400px] w-full items-center justify-center bg-gradient-to-br from-gray-50 to-slate-100">
<div className="text-center bg-white rounded-xl border border-gray-200/60 shadow-lg p-8">
<Loader2 className="mx-auto h-10 w-10 animate-spin text-blue-600" />
<p className="mt-4 text-gray-700 font-medium"> ...</p>
</div>
</div>
);
@@ -127,14 +128,14 @@ export default function ScreenViewPage() {
if (error || !screen) {
return (
<div className="flex h-full min-h-[400px] w-full items-center justify-center bg-white">
<div className="text-center">
<div className="mx-auto mb-4 flex h-16 w-16 items-center justify-center rounded-full bg-red-100">
<span className="text-2xl"></span>
<div className="flex h-full min-h-[400px] w-full items-center justify-center bg-gradient-to-br from-gray-50 to-slate-100">
<div className="text-center bg-white rounded-xl border border-gray-200/60 shadow-lg p-8 max-w-md">
<div className="mx-auto mb-6 flex h-20 w-20 items-center justify-center rounded-full bg-gradient-to-br from-red-100 to-orange-100 shadow-sm">
<span className="text-3xl"></span>
</div>
<h2 className="mb-2 text-xl font-semibold text-gray-900"> </h2>
<p className="mb-4 text-gray-600">{error || "요청하신 화면이 존재하지 않습니다."}</p>
<Button onClick={() => router.back()} variant="outline">
<h2 className="mb-3 text-xl font-bold text-gray-900"> </h2>
<p className="mb-6 text-gray-600 leading-relaxed">{error || "요청하신 화면이 존재하지 않습니다."}</p>
<Button onClick={() => router.back()} variant="outline" className="rounded-lg">
</Button>
</div>
@@ -147,17 +148,17 @@ export default function ScreenViewPage() {
const screenHeight = layout?.screenResolution?.height || 800;
return (
<div className="h-full w-full overflow-auto bg-white pt-10">
<div className="h-full w-full overflow-auto bg-gradient-to-br from-gray-50 to-slate-100 pt-10">
{layout && layout.components.length > 0 ? (
// 캔버스 컴포넌트들을 정확한 해상도로 표시
<div
className="relative bg-white"
className="relative bg-white rounded-xl border border-gray-200/60 shadow-lg shadow-gray-900/5 mx-auto"
style={{
width: `${screenWidth}px`,
height: `${screenHeight}px`,
minWidth: `${screenWidth}px`,
minHeight: `${screenHeight}px`,
margin: "0", // mx-auto 제거하여 사이드바 오프셋 방지
margin: "0 auto 40px auto", // 하단 여백 추가
}}
>
{layout.components
@@ -177,15 +178,16 @@ export default function ScreenViewPage() {
width: `${component.size.width}px`,
height: `${component.size.height}px`,
zIndex: component.position.z || 1,
backgroundColor: (component as any).backgroundColor || "rgba(59, 130, 246, 0.1)",
border: (component as any).border || "2px dashed #3b82f6",
borderRadius: (component as any).borderRadius || "8px",
padding: "16px",
backgroundColor: (component as any).backgroundColor || "rgba(59, 130, 246, 0.05)",
border: (component as any).border || "1px solid rgba(59, 130, 246, 0.2)",
borderRadius: (component as any).borderRadius || "12px",
padding: "20px",
boxShadow: "0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)",
}}
>
{/* 그룹 제목 */}
{(component as any).title && (
<div className="mb-2 text-sm font-medium text-blue-700">{(component as any).title}</div>
<div className="mb-3 text-sm font-semibold text-blue-700 bg-blue-50 px-3 py-1 rounded-lg inline-block">{(component as any).title}</div>
)}
{/* 그룹 내 자식 컴포넌트들 렌더링 */}
@@ -324,7 +326,19 @@ export default function ScreenViewPage() {
/>
) : (
<DynamicWebTypeRenderer
webType={component.webType || "text"}
webType={(() => {
// 유틸리티 함수로 파일 컴포넌트 감지
if (isFileComponent(component)) {
console.log(`🎯 page.tsx - 파일 컴포넌트 감지 → webType: "file"`, {
componentId: component.id,
componentType: component.type,
originalWebType: component.webType
});
return "file";
}
// 다른 컴포넌트는 유틸리티 함수로 webType 결정
return getComponentWebType(component) || "text";
})()}
config={component.webTypeConfig}
props={{
component: component,
@@ -338,13 +352,13 @@ export default function ScreenViewPage() {
},
onFormDataChange: (fieldName, value) => {
console.log(`🎯 page.tsx onFormDataChange 호출: ${fieldName} = "${value}"`);
console.log(`📋 현재 formData:`, formData);
console.log("📋 현재 formData:", formData);
setFormData((prev) => {
const newFormData = {
...prev,
[fieldName]: value,
};
console.log(`📝 업데이트된 formData:`, newFormData);
console.log("📝 업데이트된 formData:", newFormData);
return newFormData;
});
},

View File

@@ -45,9 +45,9 @@ export default function RootLayout({
<div id="root" className="h-full">
<QueryProvider>
<RegistryProvider>{children}</RegistryProvider>
<Toaster position="top-right" richColors />
<ScreenModal />
</QueryProvider>
<Toaster position="top-right" richColors />
<ScreenModal />
</div>
</body>
</html>