Merge branch 'main' of http://39.117.244.52:3000/kjs/ERP-node into feature/screen-management

This commit is contained in:
kjs
2025-12-01 10:21:34 +09:00
13 changed files with 1985 additions and 291 deletions

View File

@@ -995,6 +995,17 @@ export default function ScreenDesigner({ selectedScreen, onBackToList }: ScreenD
// console.log("🔧 기본 해상도 적용:", defaultResolution);
}
// 🔍 디버깅: 로드된 버튼 컴포넌트의 action 확인
const buttonComponents = layoutWithDefaultGrid.components.filter(
(c: any) => c.componentType?.startsWith("button")
);
console.log("🔍 [로드] 버튼 컴포넌트 action 확인:", buttonComponents.map((c: any) => ({
id: c.id,
type: c.componentType,
actionType: c.componentConfig?.action?.type,
fullAction: c.componentConfig?.action,
})));
setLayout(layoutWithDefaultGrid);
setHistory([layoutWithDefaultGrid]);
setHistoryIndex(0);
@@ -1452,7 +1463,7 @@ export default function ScreenDesigner({ selectedScreen, onBackToList }: ScreenD
};
// 🔍 버튼 컴포넌트들의 action.type 확인
const buttonComponents = layoutWithResolution.components.filter(
(c: any) => c.type === "button" || c.type === "button-primary" || c.type === "button-secondary",
(c: any) => c.componentType?.startsWith("button") || c.type === "button" || c.type === "button-primary",
);
console.log("💾 저장 시작:", {
screenId: selectedScreen.screenId,
@@ -1462,6 +1473,7 @@ export default function ScreenDesigner({ selectedScreen, onBackToList }: ScreenD
buttonComponents: buttonComponents.map((c: any) => ({
id: c.id,
type: c.type,
componentType: c.componentType,
text: c.componentConfig?.text,
actionType: c.componentConfig?.action?.type,
fullAction: c.componentConfig?.action,

View File

@@ -503,6 +503,8 @@ export const ButtonConfigPanel: React.FC<ButtonConfigPanelProps> = ({
<SelectItem value="excel_upload"> </SelectItem>
<SelectItem value="barcode_scan"> </SelectItem>
<SelectItem value="code_merge"> </SelectItem>
<SelectItem value="geolocation"> </SelectItem>
<SelectItem value="update_field"> </SelectItem>
</SelectContent>
</Select>
</div>
@@ -1662,6 +1664,255 @@ export const ButtonConfigPanel: React.FC<ButtonConfigPanelProps> = ({
</div>
)}
{/* 위치정보 가져오기 설정 */}
{(component.componentConfig?.action?.type || "save") === "geolocation" && (
<div className="mt-4 space-y-4 rounded-lg border bg-muted/50 p-4">
<h4 className="text-sm font-medium text-foreground">📍 </h4>
{/* 테이블 선택 */}
<div>
<Label htmlFor="geolocation-table">
<span className="text-destructive">*</span>
</Label>
<Select
value={config.action?.geolocationTableName || currentTableName || ""}
onValueChange={(value) => {
onUpdateProperty("componentConfig.action.geolocationTableName", value);
onUpdateProperty("componentConfig.action.geolocationLatField", "");
onUpdateProperty("componentConfig.action.geolocationLngField", "");
onUpdateProperty("componentConfig.action.geolocationAccuracyField", "");
onUpdateProperty("componentConfig.action.geolocationTimestampField", "");
}}
>
<SelectTrigger className="h-8 text-xs">
<SelectValue placeholder="테이블 선택" />
</SelectTrigger>
<SelectContent>
{availableTables.map((table) => (
<SelectItem key={table.name} value={table.name} className="text-xs">
{table.label || table.name}
</SelectItem>
))}
</SelectContent>
</Select>
<p className="mt-1 text-xs text-muted-foreground">
(기본: 현재 )
</p>
</div>
<div className="grid grid-cols-2 gap-4">
<div>
<Label htmlFor="geolocation-lat-field">
<span className="text-destructive">*</span>
</Label>
<Input
id="geolocation-lat-field"
placeholder="예: latitude"
value={config.action?.geolocationLatField || ""}
onChange={(e) => onUpdateProperty("componentConfig.action.geolocationLatField", e.target.value)}
className="h-8 text-xs"
/>
</div>
<div>
<Label htmlFor="geolocation-lng-field">
<span className="text-destructive">*</span>
</Label>
<Input
id="geolocation-lng-field"
placeholder="예: longitude"
value={config.action?.geolocationLngField || ""}
onChange={(e) => onUpdateProperty("componentConfig.action.geolocationLngField", e.target.value)}
className="h-8 text-xs"
/>
</div>
</div>
<div className="grid grid-cols-2 gap-4">
<div>
<Label htmlFor="geolocation-accuracy-field"> ()</Label>
<Input
id="geolocation-accuracy-field"
placeholder="예: accuracy"
value={config.action?.geolocationAccuracyField || ""}
onChange={(e) => onUpdateProperty("componentConfig.action.geolocationAccuracyField", e.target.value)}
className="h-8 text-xs"
/>
</div>
<div>
<Label htmlFor="geolocation-timestamp-field"> ()</Label>
<Input
id="geolocation-timestamp-field"
placeholder="예: location_time"
value={config.action?.geolocationTimestampField || ""}
onChange={(e) => onUpdateProperty("componentConfig.action.geolocationTimestampField", e.target.value)}
className="h-8 text-xs"
/>
</div>
</div>
<div className="flex items-center justify-between">
<div className="space-y-0.5">
<Label htmlFor="geolocation-high-accuracy"> </Label>
<p className="text-xs text-muted-foreground">GPS를 ( )</p>
</div>
<Switch
id="geolocation-high-accuracy"
checked={config.action?.geolocationHighAccuracy !== false}
onCheckedChange={(checked) => onUpdateProperty("componentConfig.action.geolocationHighAccuracy", checked)}
/>
</div>
<div className="flex items-center justify-between">
<div className="space-y-0.5">
<Label htmlFor="geolocation-auto-save"> </Label>
<p className="text-xs text-muted-foreground"> </p>
</div>
<Switch
id="geolocation-auto-save"
checked={config.action?.geolocationAutoSave === true}
onCheckedChange={(checked) => onUpdateProperty("componentConfig.action.geolocationAutoSave", checked)}
/>
</div>
<div className="rounded-md bg-blue-50 p-3 dark:bg-blue-950">
<p className="text-xs text-blue-900 dark:text-blue-100">
<strong> :</strong>
<br />
1.
<br />
2. GPS
<br />
3. /
<br />
<br />
<strong>:</strong> HTTPS .
</p>
</div>
</div>
)}
{/* 필드 값 변경 설정 */}
{(component.componentConfig?.action?.type || "save") === "update_field" && (
<div className="mt-4 space-y-4 rounded-lg border bg-muted/50 p-4">
<h4 className="text-sm font-medium text-foreground">📝 </h4>
<div>
<Label htmlFor="update-table">
<span className="text-destructive">*</span>
</Label>
<Select
value={config.action?.updateTableName || currentTableName || ""}
onValueChange={(value) => {
onUpdateProperty("componentConfig.action.updateTableName", value);
onUpdateProperty("componentConfig.action.updateTargetField", "");
}}
>
<SelectTrigger className="h-8 text-xs">
<SelectValue placeholder="테이블 선택" />
</SelectTrigger>
<SelectContent>
{availableTables.map((table) => (
<SelectItem key={table.name} value={table.name} className="text-xs">
{table.label || table.name}
</SelectItem>
))}
</SelectContent>
</Select>
<p className="mt-1 text-xs text-muted-foreground">
(기본: 현재 )
</p>
</div>
<div className="grid grid-cols-2 gap-4">
<div>
<Label htmlFor="update-target-field">
<span className="text-destructive">*</span>
</Label>
<Input
id="update-target-field"
placeholder="예: status"
value={config.action?.updateTargetField || ""}
onChange={(e) => onUpdateProperty("componentConfig.action.updateTargetField", e.target.value)}
className="h-8 text-xs"
/>
<p className="mt-1 text-xs text-muted-foreground"> DB </p>
</div>
<div>
<Label htmlFor="update-target-value">
<span className="text-destructive">*</span>
</Label>
<Input
id="update-target-value"
placeholder="예: active"
value={config.action?.updateTargetValue || ""}
onChange={(e) => onUpdateProperty("componentConfig.action.updateTargetValue", e.target.value)}
className="h-8 text-xs"
/>
<p className="mt-1 text-xs text-muted-foreground"> (, )</p>
</div>
</div>
<div className="flex items-center justify-between">
<div className="space-y-0.5">
<Label htmlFor="update-auto-save"> </Label>
<p className="text-xs text-muted-foreground"> DB에 </p>
</div>
<Switch
id="update-auto-save"
checked={config.action?.updateAutoSave !== false}
onCheckedChange={(checked) => onUpdateProperty("componentConfig.action.updateAutoSave", checked)}
/>
</div>
<div>
<Label htmlFor="update-confirm-message"> ()</Label>
<Input
id="update-confirm-message"
placeholder="예: 운행을 시작하시겠습니까?"
value={config.action?.confirmMessage || ""}
onChange={(e) => onUpdateProperty("componentConfig.action.confirmMessage", e.target.value)}
className="h-8 text-xs"
/>
<p className="mt-1 text-xs text-muted-foreground"> </p>
</div>
<div className="grid grid-cols-2 gap-4">
<div>
<Label htmlFor="update-success-message"> ()</Label>
<Input
id="update-success-message"
placeholder="예: 운행이 시작되었습니다."
value={config.action?.successMessage || ""}
onChange={(e) => onUpdateProperty("componentConfig.action.successMessage", e.target.value)}
className="h-8 text-xs"
/>
</div>
<div>
<Label htmlFor="update-error-message"> ()</Label>
<Input
id="update-error-message"
placeholder="예: 운행 시작에 실패했습니다."
value={config.action?.errorMessage || ""}
onChange={(e) => onUpdateProperty("componentConfig.action.errorMessage", e.target.value)}
className="h-8 text-xs"
/>
</div>
</div>
<div className="rounded-md bg-blue-50 p-3 dark:bg-blue-950">
<p className="text-xs text-blue-900 dark:text-blue-100">
<strong> :</strong>
<br />
- 버튼: status &quot;active&quot;
<br />
- 버튼: approval_status &quot;approved&quot;
<br />
- 버튼: is_completed &quot;Y&quot;
</p>
</div>
</div>
)}
{/* 데이터 전달 액션 설정 */}
{(component.componentConfig?.action?.type || "save") === "transferData" && (
<div className="mt-4 space-y-4 rounded-lg border bg-muted/50 p-4">