Merge branch 'ycshin-node' of http://39.117.244.52:3000/kjs/ERP-node into jskim-node

This commit is contained in:
kjs
2026-03-10 14:52:33 +09:00
54 changed files with 6530 additions and 749 deletions

View File

@@ -22,6 +22,7 @@ import {
import { toast } from "sonner";
import { showErrorToast } from "@/lib/utils/toastUtils";
import { filterDOMProps } from "@/lib/utils/domPropsFilter";
import { ButtonIconRenderer } from "@/lib/button-icon-map";
import { useCurrentFlowStep } from "@/stores/flowStepStore";
import { useScreenPreview } from "@/contexts/ScreenPreviewContext";
import { useScreenContextOptional } from "@/contexts/ScreenContext";
@@ -29,7 +30,6 @@ import { useSplitPanelContext, SplitPanelPosition } from "@/contexts/SplitPanelC
import { applyMappingRules } from "@/lib/utils/dataMapping";
import { apiClient } from "@/lib/api/client";
import { V2ErrorBoundary, v2EventBus, V2_EVENTS } from "@/lib/v2-core";
export interface ButtonPrimaryComponentProps extends ComponentRendererProps {
config?: ButtonPrimaryConfig;
// 추가 props
@@ -556,13 +556,23 @@ export const ButtonPrimaryComponent: React.FC<ButtonPrimaryComponentProps> = ({
}
// 스타일 계산
// 🔧 사용자가 설정한 크기가 있으면 그대로 사용
const componentStyle: React.CSSProperties = {
// 외부 wrapper는 부모 컨테이너(RealtimePreviewDynamic)에 맞춰 100% 채움
// border는 내부 버튼에서만 적용 (wrapper에 적용되면 이중 테두리 발생)
const {
border: _border, borderWidth: _bw, borderStyle: _bs, borderColor: _bc, borderRadius: _br,
...restComponentStyle
} = {
...component.style,
...style,
} as React.CSSProperties & Record<string, any>;
const componentStyle: React.CSSProperties = {
...restComponentStyle,
width: "100%",
height: "100%",
};
// 디자인 모드 스타일 (border 속성 분리하여 충돌 방지)
// 디자인 모드 스타일
if (isDesignMode) {
componentStyle.borderWidth = "1px";
componentStyle.borderStyle = "dashed";
@@ -1217,15 +1227,6 @@ export const ButtonPrimaryComponent: React.FC<ButtonPrimaryComponentProps> = ({
effectiveFormData = { ...splitPanelParentData };
}
console.log("🔴 [ButtonPrimary] 저장 시 formData 디버그:", {
propsFormDataKeys: Object.keys(propsFormData),
screenContextFormDataKeys: Object.keys(screenContextFormData),
effectiveFormDataKeys: Object.keys(effectiveFormData),
process_code: effectiveFormData.process_code,
equipment_code: effectiveFormData.equipment_code,
fullData: JSON.stringify(effectiveFormData),
});
const context: ButtonActionContext = {
formData: effectiveFormData,
originalData: originalData, // 🔧 빈 객체 대신 undefined 유지 (UPDATE 판단에 사용)
@@ -1382,31 +1383,29 @@ export const ButtonPrimaryComponent: React.FC<ButtonPrimaryComponentProps> = ({
}
}
// 🆕 최종 비활성화 상태 (설정 + 조건부 비활성화 + 행 선택 필수)
const finalDisabled =
componentConfig.disabled || isOperationButtonDisabled || isRowSelectionDisabled || statusLoading;
// 공통 버튼 스타일
// 🔧 component.style에서 background/backgroundColor 충돌 방지 (width/height는 허용)
// 크기는 부모 컨테이너(RealtimePreviewDynamic)에서 관리하므로 width/height 제외
const userStyle = component.style
? Object.fromEntries(
Object.entries(component.style).filter(([key]) => !["background", "backgroundColor"].includes(key)),
Object.entries(component.style).filter(([key]) => !["background", "backgroundColor", "width", "height"].includes(key)),
)
: {};
// 🔧 사용자가 설정한 크기 우선 사용, 없으면 100%
const buttonWidth = component.size?.width ? `${component.size.width}px` : style?.width || "100%";
const buttonHeight = component.size?.height ? `${component.size.height}px` : style?.height || "100%";
// 버튼은 부모 컨테이너를 꽉 채움 (크기는 RealtimePreviewDynamic에서 관리)
const buttonWidth = "100%";
const buttonHeight = "100%";
const buttonElementStyle: React.CSSProperties = {
width: buttonWidth,
height: buttonHeight,
minHeight: "32px", // 🔧 최소 높이를 32px로 줄임
// 🔧 커스텀 테두리 스타일 (StyleEditor에서 설정한 값 우선)
border: style?.border || (style?.borderWidth ? undefined : "none"),
borderWidth: style?.borderWidth || undefined,
borderStyle: (style?.borderStyle as React.CSSProperties["borderStyle"]) || undefined,
borderColor: style?.borderColor || undefined,
// 커스텀 테두리 스타일 (StyleEditor 설정 우선, shorthand 사용 안 함)
borderWidth: style?.borderWidth || "0",
borderStyle: (style?.borderStyle as React.CSSProperties["borderStyle"]) || (style?.borderWidth ? "solid" : "none"),
borderColor: style?.borderColor || "transparent",
borderRadius: style?.borderRadius || "0.5rem",
backgroundColor: finalDisabled ? "#e5e7eb" : buttonColor,
color: finalDisabled ? "#9ca3af" : (style?.color || buttonTextColor), // 🔧 StyleEditor 텍스트 색상도 지원
@@ -1444,7 +1443,7 @@ export const ButtonPrimaryComponent: React.FC<ButtonPrimaryComponentProps> = ({
cancel: "취소",
};
const buttonContent =
const buttonTextContent =
processedConfig.text ||
component.webTypeConfig?.text ||
component.componentConfig?.text ||
@@ -1458,16 +1457,17 @@ export const ButtonPrimaryComponent: React.FC<ButtonPrimaryComponentProps> = ({
<>
<div style={componentStyle} className={className} {...safeDomProps}>
{isDesignMode ? (
// 디자인 모드: div로 렌더링하여 선택 가능하게 함
<div
className="transition-colors duration-150 hover:opacity-90"
style={buttonElementStyle}
onClick={handleClick}
>
{buttonContent}
<ButtonIconRenderer
componentConfig={componentConfig}
fallbackLabel={buttonTextContent as string}
/>
</div>
) : (
// 일반 모드: button으로 렌더링
<button
type={componentConfig.actionType || "button"}
disabled={finalDisabled}
@@ -1476,8 +1476,12 @@ export const ButtonPrimaryComponent: React.FC<ButtonPrimaryComponentProps> = ({
onClick={handleClick}
onDragStart={onDragStart}
onDragEnd={onDragEnd}
{...(actionType ? { "data-action-type": actionType } : {})}
>
{buttonContent}
<ButtonIconRenderer
componentConfig={componentConfig}
fallbackLabel={buttonTextContent as string}
/>
</button>
)}
</div>