버튼 수정
This commit is contained in:
@@ -26,7 +26,7 @@ export default function ScreenViewPage() {
|
||||
|
||||
// 🆕 현재 로그인한 사용자 정보
|
||||
const { user, userName, companyCode } = useAuth();
|
||||
|
||||
|
||||
// 🆕 모바일 환경 감지
|
||||
const { isMobile } = useResponsive();
|
||||
|
||||
@@ -189,10 +189,10 @@ export default function ScreenViewPage() {
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="flex h-full min-h-[400px] w-full items-center justify-center bg-gradient-to-br from-muted to-muted/50">
|
||||
<div className="rounded-xl border border-border bg-background p-8 text-center shadow-lg">
|
||||
<Loader2 className="mx-auto h-10 w-10 animate-spin text-primary" />
|
||||
<p className="mt-4 font-medium text-foreground">화면을 불러오는 중...</p>
|
||||
<div className="from-muted to-muted/50 flex h-full min-h-[400px] w-full items-center justify-center bg-gradient-to-br">
|
||||
<div className="border-border bg-background rounded-xl border p-8 text-center shadow-lg">
|
||||
<Loader2 className="text-primary mx-auto h-10 w-10 animate-spin" />
|
||||
<p className="text-foreground mt-4 font-medium">화면을 불러오는 중...</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -200,13 +200,13 @@ export default function ScreenViewPage() {
|
||||
|
||||
if (error || !screen) {
|
||||
return (
|
||||
<div className="flex h-full min-h-[400px] w-full items-center justify-center bg-gradient-to-br from-muted to-muted/50">
|
||||
<div className="max-w-md rounded-xl border border-border bg-background p-8 text-center shadow-lg">
|
||||
<div className="mx-auto mb-6 flex h-20 w-20 items-center justify-center rounded-full bg-gradient-to-br from-destructive/20 to-warning/20 shadow-sm">
|
||||
<div className="from-muted to-muted/50 flex h-full min-h-[400px] w-full items-center justify-center bg-gradient-to-br">
|
||||
<div className="border-border bg-background max-w-md rounded-xl border p-8 text-center shadow-lg">
|
||||
<div className="from-destructive/20 to-warning/20 mx-auto mb-6 flex h-20 w-20 items-center justify-center rounded-full bg-gradient-to-br shadow-sm">
|
||||
<span className="text-3xl">⚠️</span>
|
||||
</div>
|
||||
<h2 className="mb-3 text-xl font-bold text-foreground">화면을 찾을 수 없습니다</h2>
|
||||
<p className="mb-6 leading-relaxed text-muted-foreground">{error || "요청하신 화면이 존재하지 않습니다."}</p>
|
||||
<h2 className="text-foreground mb-3 text-xl font-bold">화면을 찾을 수 없습니다</h2>
|
||||
<p className="text-muted-foreground mb-6 leading-relaxed">{error || "요청하신 화면이 존재하지 않습니다."}</p>
|
||||
<Button onClick={() => router.back()} variant="outline" className="rounded-lg">
|
||||
이전으로 돌아가기
|
||||
</Button>
|
||||
@@ -225,7 +225,7 @@ export default function ScreenViewPage() {
|
||||
{/* 절대 위치 기반 렌더링 */}
|
||||
{layout && layout.components.length > 0 ? (
|
||||
<div
|
||||
className="bg-background relative origin-top-left h-full flex justify-start items-start"
|
||||
className="bg-background relative flex h-full origin-top-left items-start justify-start"
|
||||
style={{
|
||||
transform: `scale(${scale})`,
|
||||
transformOrigin: "top left",
|
||||
@@ -238,27 +238,76 @@ export default function ScreenViewPage() {
|
||||
// 🆕 플로우 버튼 그룹 감지 및 처리
|
||||
const topLevelComponents = layout.components.filter((component) => !component.parentId);
|
||||
|
||||
// 버튼은 scale에 맞춰 위치만 조정하면 됨 (scale = 1.0이면 그대로, scale < 1.0이면 왼쪽으로)
|
||||
// 하지만 x=0 컴포넌트는 width: 100%로 확장되므로, 그만큼 버튼을 오른쪽으로 이동
|
||||
const leftmostComponent = topLevelComponents.find((c) => c.position.x === 0);
|
||||
let widthOffset = 0;
|
||||
|
||||
if (leftmostComponent && containerWidth > 0) {
|
||||
const originalWidth = leftmostComponent.size?.width || screenWidth;
|
||||
const actualWidth = containerWidth / scale;
|
||||
widthOffset = Math.max(0, actualWidth - originalWidth);
|
||||
|
||||
console.log("📊 widthOffset 계산:", {
|
||||
containerWidth,
|
||||
scale,
|
||||
screenWidth,
|
||||
originalWidth,
|
||||
actualWidth,
|
||||
widthOffset,
|
||||
leftmostType: leftmostComponent.type,
|
||||
});
|
||||
}
|
||||
|
||||
const buttonGroups: Record<string, any[]> = {};
|
||||
const processedButtonIds = new Set<string>();
|
||||
// 🔍 전체 버튼 목록 확인
|
||||
const allButtons = topLevelComponents.filter((component) => {
|
||||
const isButton =
|
||||
(component.type === "component" &&
|
||||
["button-primary", "button-secondary"].includes((component as any).componentType)) ||
|
||||
(component.type === "widget" && (component as any).widgetType === "button");
|
||||
return isButton;
|
||||
});
|
||||
|
||||
console.log(
|
||||
"🔍 메뉴에서 발견된 전체 버튼:",
|
||||
allButtons.map((b) => ({
|
||||
id: b.id,
|
||||
label: b.label,
|
||||
positionX: b.position.x,
|
||||
positionY: b.position.y,
|
||||
})),
|
||||
);
|
||||
|
||||
topLevelComponents.forEach((component) => {
|
||||
const isButton =
|
||||
component.type === "button" ||
|
||||
(component.type === "component" &&
|
||||
["button-primary", "button-secondary"].includes((component as any).componentType));
|
||||
["button-primary", "button-secondary"].includes((component as any).componentType)) ||
|
||||
(component.type === "widget" && (component as any).widgetType === "button");
|
||||
|
||||
if (isButton) {
|
||||
const flowConfig = (component as any).webTypeConfig?.flowVisibilityConfig as
|
||||
| FlowVisibilityConfig
|
||||
| undefined;
|
||||
|
||||
if (flowConfig?.enabled && flowConfig.layoutBehavior === "auto-compact" && flowConfig.groupId) {
|
||||
// 🔧 임시: 버튼 그룹 기능 완전 비활성화
|
||||
// TODO: 사용자가 명시적으로 그룹을 원하는 경우에만 활성화하도록 UI 개선 필요
|
||||
const DISABLE_BUTTON_GROUPS = true;
|
||||
|
||||
if (
|
||||
!DISABLE_BUTTON_GROUPS &&
|
||||
flowConfig?.enabled &&
|
||||
flowConfig.layoutBehavior === "auto-compact" &&
|
||||
flowConfig.groupId
|
||||
) {
|
||||
if (!buttonGroups[flowConfig.groupId]) {
|
||||
buttonGroups[flowConfig.groupId] = [];
|
||||
}
|
||||
buttonGroups[flowConfig.groupId].push(component);
|
||||
processedButtonIds.add(component.id);
|
||||
}
|
||||
// else: 모든 버튼을 개별 렌더링
|
||||
}
|
||||
});
|
||||
|
||||
@@ -267,92 +316,121 @@ export default function ScreenViewPage() {
|
||||
return (
|
||||
<>
|
||||
{/* 일반 컴포넌트들 */}
|
||||
{regularComponents.map((component) => (
|
||||
<RealtimePreview
|
||||
key={component.id}
|
||||
component={component}
|
||||
isSelected={false}
|
||||
isDesignMode={false}
|
||||
onClick={() => {}}
|
||||
screenId={screenId}
|
||||
tableName={screen?.tableName}
|
||||
userId={user?.userId}
|
||||
userName={userName}
|
||||
companyCode={companyCode}
|
||||
selectedRowsData={selectedRowsData}
|
||||
onSelectedRowsChange={(_, selectedData) => {
|
||||
console.log("🔍 화면에서 선택된 행 데이터:", selectedData);
|
||||
setSelectedRowsData(selectedData);
|
||||
}}
|
||||
flowSelectedData={flowSelectedData}
|
||||
flowSelectedStepId={flowSelectedStepId}
|
||||
onFlowSelectedDataChange={(selectedData: any[], stepId: number | null) => {
|
||||
setFlowSelectedData(selectedData);
|
||||
setFlowSelectedStepId(stepId);
|
||||
}}
|
||||
refreshKey={tableRefreshKey}
|
||||
onRefresh={() => {
|
||||
setTableRefreshKey((prev) => prev + 1);
|
||||
setSelectedRowsData([]); // 선택 해제
|
||||
}}
|
||||
flowRefreshKey={flowRefreshKey}
|
||||
onFlowRefresh={() => {
|
||||
setFlowRefreshKey((prev) => prev + 1);
|
||||
setFlowSelectedData([]); // 선택 해제
|
||||
setFlowSelectedStepId(null);
|
||||
}}
|
||||
formData={formData}
|
||||
onFormDataChange={(fieldName, value) => {
|
||||
setFormData((prev) => ({ ...prev, [fieldName]: value }));
|
||||
}}
|
||||
>
|
||||
{/* 자식 컴포넌트들 */}
|
||||
{(component.type === "group" || component.type === "container" || component.type === "area") &&
|
||||
layout.components
|
||||
.filter((child) => child.parentId === component.id)
|
||||
.map((child) => {
|
||||
// 자식 컴포넌트의 위치를 부모 기준 상대 좌표로 조정
|
||||
const relativeChildComponent = {
|
||||
...child,
|
||||
position: {
|
||||
x: child.position.x - component.position.x,
|
||||
y: child.position.y - component.position.y,
|
||||
z: child.position.z || 1,
|
||||
},
|
||||
};
|
||||
{regularComponents.map((component) => {
|
||||
// 버튼인 경우 위치 조정 (테이블이 늘어난 만큼 오른쪽으로 이동)
|
||||
const isButton =
|
||||
(component.type === "component" &&
|
||||
["button-primary", "button-secondary"].includes((component as any).componentType)) ||
|
||||
(component.type === "widget" && (component as any).widgetType === "button");
|
||||
|
||||
return (
|
||||
<RealtimePreview
|
||||
key={child.id}
|
||||
component={relativeChildComponent}
|
||||
isSelected={false}
|
||||
isDesignMode={false}
|
||||
onClick={() => {}}
|
||||
screenId={screenId}
|
||||
tableName={screen?.tableName}
|
||||
userId={user?.userId}
|
||||
userName={userName}
|
||||
companyCode={companyCode}
|
||||
selectedRowsData={selectedRowsData}
|
||||
onSelectedRowsChange={(_, selectedData) => {
|
||||
console.log("🔍 화면에서 선택된 행 데이터 (자식):", selectedData);
|
||||
setSelectedRowsData(selectedData);
|
||||
}}
|
||||
refreshKey={tableRefreshKey}
|
||||
onRefresh={() => {
|
||||
console.log("🔄 테이블 새로고침 요청됨 (자식)");
|
||||
setTableRefreshKey((prev) => prev + 1);
|
||||
setSelectedRowsData([]); // 선택 해제
|
||||
}}
|
||||
formData={formData}
|
||||
onFormDataChange={(fieldName, value) => {
|
||||
setFormData((prev) => ({ ...prev, [fieldName]: value }));
|
||||
}}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</RealtimePreview>
|
||||
))}
|
||||
const adjustedComponent =
|
||||
isButton && widthOffset > 0
|
||||
? {
|
||||
...component,
|
||||
position: {
|
||||
...component.position,
|
||||
x: component.position.x + widthOffset,
|
||||
},
|
||||
}
|
||||
: component;
|
||||
|
||||
// 버튼일 경우 로그 출력
|
||||
if (isButton) {
|
||||
console.log("🔘 버튼 위치 조정:", {
|
||||
label: component.label,
|
||||
originalX: component.position.x,
|
||||
adjustedX: component.position.x + widthOffset,
|
||||
widthOffset,
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<RealtimePreview
|
||||
key={component.id}
|
||||
component={adjustedComponent}
|
||||
isSelected={false}
|
||||
isDesignMode={false}
|
||||
onClick={() => {}}
|
||||
screenId={screenId}
|
||||
tableName={screen?.tableName}
|
||||
userId={user?.userId}
|
||||
userName={userName}
|
||||
companyCode={companyCode}
|
||||
selectedRowsData={selectedRowsData}
|
||||
onSelectedRowsChange={(_, selectedData) => {
|
||||
console.log("🔍 화면에서 선택된 행 데이터:", selectedData);
|
||||
setSelectedRowsData(selectedData);
|
||||
}}
|
||||
flowSelectedData={flowSelectedData}
|
||||
flowSelectedStepId={flowSelectedStepId}
|
||||
onFlowSelectedDataChange={(selectedData: any[], stepId: number | null) => {
|
||||
setFlowSelectedData(selectedData);
|
||||
setFlowSelectedStepId(stepId);
|
||||
}}
|
||||
refreshKey={tableRefreshKey}
|
||||
onRefresh={() => {
|
||||
setTableRefreshKey((prev) => prev + 1);
|
||||
setSelectedRowsData([]); // 선택 해제
|
||||
}}
|
||||
flowRefreshKey={flowRefreshKey}
|
||||
onFlowRefresh={() => {
|
||||
setFlowRefreshKey((prev) => prev + 1);
|
||||
setFlowSelectedData([]); // 선택 해제
|
||||
setFlowSelectedStepId(null);
|
||||
}}
|
||||
formData={formData}
|
||||
onFormDataChange={(fieldName, value) => {
|
||||
setFormData((prev) => ({ ...prev, [fieldName]: value }));
|
||||
}}
|
||||
>
|
||||
{/* 자식 컴포넌트들 */}
|
||||
{(component.type === "group" || component.type === "container" || component.type === "area") &&
|
||||
layout.components
|
||||
.filter((child) => child.parentId === component.id)
|
||||
.map((child) => {
|
||||
// 자식 컴포넌트의 위치를 부모 기준 상대 좌표로 조정
|
||||
const relativeChildComponent = {
|
||||
...child,
|
||||
position: {
|
||||
x: child.position.x - component.position.x,
|
||||
y: child.position.y - component.position.y,
|
||||
z: child.position.z || 1,
|
||||
},
|
||||
};
|
||||
|
||||
return (
|
||||
<RealtimePreview
|
||||
key={child.id}
|
||||
component={relativeChildComponent}
|
||||
isSelected={false}
|
||||
isDesignMode={false}
|
||||
onClick={() => {}}
|
||||
screenId={screenId}
|
||||
tableName={screen?.tableName}
|
||||
userId={user?.userId}
|
||||
userName={userName}
|
||||
companyCode={companyCode}
|
||||
selectedRowsData={selectedRowsData}
|
||||
onSelectedRowsChange={(_, selectedData) => {
|
||||
console.log("🔍 화면에서 선택된 행 데이터 (자식):", selectedData);
|
||||
setSelectedRowsData(selectedData);
|
||||
}}
|
||||
refreshKey={tableRefreshKey}
|
||||
onRefresh={() => {
|
||||
console.log("🔄 테이블 새로고침 요청됨 (자식)");
|
||||
setTableRefreshKey((prev) => prev + 1);
|
||||
setSelectedRowsData([]); // 선택 해제
|
||||
}}
|
||||
formData={formData}
|
||||
onFormDataChange={(fieldName, value) => {
|
||||
setFormData((prev) => ({ ...prev, [fieldName]: value }));
|
||||
}}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</RealtimePreview>
|
||||
);
|
||||
})}
|
||||
|
||||
{/* 🆕 플로우 버튼 그룹들 */}
|
||||
{Object.entries(buttonGroups).map(([groupId, buttons]) => {
|
||||
@@ -372,6 +450,12 @@ export default function ScreenViewPage() {
|
||||
{ x: buttons[0].position.x, y: buttons[0].position.y, z: buttons[0].position.z || 2 },
|
||||
);
|
||||
|
||||
// 버튼 그룹 위치에도 widthOffset 적용 (테이블이 늘어난 만큼 오른쪽으로 이동)
|
||||
const adjustedGroupPosition = {
|
||||
...groupPosition,
|
||||
x: groupPosition.x + widthOffset,
|
||||
};
|
||||
|
||||
// 그룹의 크기 계산: 버튼들의 실제 크기 + 간격을 기준으로 계산
|
||||
const direction = groupConfig.groupDirection || "horizontal";
|
||||
const gap = groupConfig.groupGap ?? 8;
|
||||
|
||||
Reference in New Issue
Block a user