리포트 저장 구현
This commit is contained in:
@@ -47,6 +47,8 @@ export function CanvasComponent({ component }: CanvasComponentProps) {
|
||||
|
||||
// 마우스 이동 핸들러 (전역)
|
||||
useEffect(() => {
|
||||
if (!isDragging && !isResizing) return;
|
||||
|
||||
const handleMouseMove = (e: MouseEvent) => {
|
||||
if (isDragging) {
|
||||
const newX = Math.max(0, e.clientX - dragStart.x);
|
||||
@@ -66,15 +68,25 @@ export function CanvasComponent({ component }: CanvasComponentProps) {
|
||||
setIsResizing(false);
|
||||
};
|
||||
|
||||
if (isDragging || isResizing) {
|
||||
document.addEventListener("mousemove", handleMouseMove);
|
||||
document.addEventListener("mouseup", handleMouseUp);
|
||||
return () => {
|
||||
document.removeEventListener("mousemove", handleMouseMove);
|
||||
document.removeEventListener("mouseup", handleMouseUp);
|
||||
};
|
||||
}
|
||||
}, [isDragging, isResizing, dragStart, resizeStart, component.id, updateComponent]);
|
||||
document.addEventListener("mousemove", handleMouseMove);
|
||||
document.addEventListener("mouseup", handleMouseUp);
|
||||
|
||||
return () => {
|
||||
document.removeEventListener("mousemove", handleMouseMove);
|
||||
document.removeEventListener("mouseup", handleMouseUp);
|
||||
};
|
||||
}, [
|
||||
isDragging,
|
||||
isResizing,
|
||||
dragStart.x,
|
||||
dragStart.y,
|
||||
resizeStart.x,
|
||||
resizeStart.y,
|
||||
resizeStart.width,
|
||||
resizeStart.height,
|
||||
component.id,
|
||||
updateComponent,
|
||||
]);
|
||||
|
||||
// 표시할 값 결정
|
||||
const getDisplayValue = (): string => {
|
||||
|
||||
@@ -67,7 +67,6 @@ export function QueryManager() {
|
||||
setSelectedQueryId(null);
|
||||
setParameterValues({});
|
||||
setParameterTypes({});
|
||||
setTestResult(null);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -76,7 +75,6 @@ export function QueryManager() {
|
||||
setSelectedQueryId(queryId);
|
||||
setParameterValues({});
|
||||
setParameterTypes({});
|
||||
setTestResult(null);
|
||||
};
|
||||
|
||||
// 파라미터 값이 모두 입력되었는지 확인
|
||||
|
||||
@@ -38,9 +38,9 @@ export function ReportDesignerCanvas() {
|
||||
fontFamily: "Malgun Gothic",
|
||||
fontWeight: "normal",
|
||||
fontColor: "#000000",
|
||||
backgroundColor: "#ffffff",
|
||||
borderWidth: 1,
|
||||
borderColor: "#666666",
|
||||
backgroundColor: "transparent",
|
||||
borderWidth: 0,
|
||||
borderColor: "#cccccc",
|
||||
borderRadius: 5,
|
||||
textAlign: "left",
|
||||
padding: 10,
|
||||
|
||||
@@ -16,6 +16,11 @@ export function ReportDesignerToolbar() {
|
||||
await saveLayout();
|
||||
};
|
||||
|
||||
const handleSaveAndClose = async () => {
|
||||
await saveLayout();
|
||||
router.push("/admin/report");
|
||||
};
|
||||
|
||||
const handleReset = async () => {
|
||||
if (confirm("현재 변경사항을 모두 취소하고 마지막 저장 상태로 되돌리시겠습니까?")) {
|
||||
await loadLayout();
|
||||
@@ -56,7 +61,7 @@ export function ReportDesignerToolbar() {
|
||||
<Eye className="h-4 w-4" />
|
||||
미리보기
|
||||
</Button>
|
||||
<Button size="sm" onClick={handleSave} disabled={isSaving} className="gap-2">
|
||||
<Button variant="outline" size="sm" onClick={handleSave} disabled={isSaving} className="gap-2">
|
||||
{isSaving ? (
|
||||
<>
|
||||
<Loader2 className="h-4 w-4 animate-spin" />
|
||||
@@ -69,6 +74,19 @@ export function ReportDesignerToolbar() {
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
<Button size="sm" onClick={handleSaveAndClose} disabled={isSaving} className="gap-2">
|
||||
{isSaving ? (
|
||||
<>
|
||||
<Loader2 className="h-4 w-4 animate-spin" />
|
||||
저장 중...
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Save className="h-4 w-4" />
|
||||
저장 후 닫기
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -33,8 +33,8 @@ function getTemplateLayout(templateId: string): TemplateLayout | null {
|
||||
height: 40,
|
||||
fontSize: 24,
|
||||
fontColor: "#000000",
|
||||
backgroundColor: "#ffffff",
|
||||
borderColor: "#000000",
|
||||
backgroundColor: "transparent",
|
||||
borderColor: "#cccccc",
|
||||
borderWidth: 0,
|
||||
zIndex: 1,
|
||||
defaultValue: "발주서",
|
||||
@@ -48,9 +48,9 @@ function getTemplateLayout(templateId: string): TemplateLayout | null {
|
||||
height: 30,
|
||||
fontSize: 14,
|
||||
fontColor: "#000000",
|
||||
backgroundColor: "#ffffff",
|
||||
backgroundColor: "transparent",
|
||||
borderColor: "#cccccc",
|
||||
borderWidth: 1,
|
||||
borderWidth: 0,
|
||||
zIndex: 1,
|
||||
},
|
||||
{
|
||||
@@ -62,9 +62,9 @@ function getTemplateLayout(templateId: string): TemplateLayout | null {
|
||||
height: 30,
|
||||
fontSize: 14,
|
||||
fontColor: "#000000",
|
||||
backgroundColor: "#ffffff",
|
||||
backgroundColor: "transparent",
|
||||
borderColor: "#cccccc",
|
||||
borderWidth: 1,
|
||||
borderWidth: 0,
|
||||
zIndex: 1,
|
||||
},
|
||||
{
|
||||
@@ -76,9 +76,9 @@ function getTemplateLayout(templateId: string): TemplateLayout | null {
|
||||
height: 30,
|
||||
fontSize: 14,
|
||||
fontColor: "#000000",
|
||||
backgroundColor: "#ffffff",
|
||||
backgroundColor: "transparent",
|
||||
borderColor: "#cccccc",
|
||||
borderWidth: 1,
|
||||
borderWidth: 0,
|
||||
zIndex: 1,
|
||||
},
|
||||
{
|
||||
@@ -90,9 +90,9 @@ function getTemplateLayout(templateId: string): TemplateLayout | null {
|
||||
height: 200,
|
||||
fontSize: 12,
|
||||
fontColor: "#000000",
|
||||
backgroundColor: "#ffffff",
|
||||
backgroundColor: "transparent",
|
||||
borderColor: "#cccccc",
|
||||
borderWidth: 1,
|
||||
borderWidth: 0,
|
||||
zIndex: 1,
|
||||
},
|
||||
],
|
||||
@@ -126,8 +126,8 @@ function getTemplateLayout(templateId: string): TemplateLayout | null {
|
||||
height: 40,
|
||||
fontSize: 24,
|
||||
fontColor: "#000000",
|
||||
backgroundColor: "#ffffff",
|
||||
borderColor: "#000000",
|
||||
backgroundColor: "transparent",
|
||||
borderColor: "#cccccc",
|
||||
borderWidth: 0,
|
||||
zIndex: 1,
|
||||
defaultValue: "청구서",
|
||||
@@ -141,9 +141,9 @@ function getTemplateLayout(templateId: string): TemplateLayout | null {
|
||||
height: 30,
|
||||
fontSize: 14,
|
||||
fontColor: "#000000",
|
||||
backgroundColor: "#ffffff",
|
||||
backgroundColor: "transparent",
|
||||
borderColor: "#cccccc",
|
||||
borderWidth: 1,
|
||||
borderWidth: 0,
|
||||
zIndex: 1,
|
||||
},
|
||||
{
|
||||
@@ -155,9 +155,9 @@ function getTemplateLayout(templateId: string): TemplateLayout | null {
|
||||
height: 30,
|
||||
fontSize: 14,
|
||||
fontColor: "#000000",
|
||||
backgroundColor: "#ffffff",
|
||||
backgroundColor: "transparent",
|
||||
borderColor: "#cccccc",
|
||||
borderWidth: 1,
|
||||
borderWidth: 0,
|
||||
zIndex: 1,
|
||||
},
|
||||
{
|
||||
@@ -169,9 +169,9 @@ function getTemplateLayout(templateId: string): TemplateLayout | null {
|
||||
height: 200,
|
||||
fontSize: 12,
|
||||
fontColor: "#000000",
|
||||
backgroundColor: "#ffffff",
|
||||
backgroundColor: "transparent",
|
||||
borderColor: "#cccccc",
|
||||
borderWidth: 1,
|
||||
borderWidth: 0,
|
||||
zIndex: 1,
|
||||
},
|
||||
{
|
||||
@@ -220,8 +220,8 @@ function getTemplateLayout(templateId: string): TemplateLayout | null {
|
||||
height: 40,
|
||||
fontSize: 20,
|
||||
fontColor: "#000000",
|
||||
backgroundColor: "#ffffff",
|
||||
borderColor: "#000000",
|
||||
backgroundColor: "transparent",
|
||||
borderColor: "#cccccc",
|
||||
borderWidth: 0,
|
||||
zIndex: 1,
|
||||
defaultValue: "리포트 제목",
|
||||
@@ -235,9 +235,9 @@ function getTemplateLayout(templateId: string): TemplateLayout | null {
|
||||
height: 100,
|
||||
fontSize: 14,
|
||||
fontColor: "#000000",
|
||||
backgroundColor: "#ffffff",
|
||||
backgroundColor: "transparent",
|
||||
borderColor: "#cccccc",
|
||||
borderWidth: 1,
|
||||
borderWidth: 0,
|
||||
zIndex: 1,
|
||||
defaultValue: "내용을 입력하세요",
|
||||
},
|
||||
@@ -381,6 +381,8 @@ export function ReportDesignerProvider({ reportId, children }: { reportId: strin
|
||||
// 레이아웃이 없으면 기본값 사용
|
||||
console.log("레이아웃 없음, 기본값 사용");
|
||||
}
|
||||
|
||||
// 쿼리 조회는 이미 위에서 처리됨 (reportResponse.data.queries)
|
||||
} catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : "리포트를 불러오는데 실패했습니다.";
|
||||
toast({
|
||||
@@ -396,7 +398,8 @@ export function ReportDesignerProvider({ reportId, children }: { reportId: strin
|
||||
// 초기 로드
|
||||
useEffect(() => {
|
||||
loadLayout();
|
||||
}, [loadLayout]);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [reportId]);
|
||||
|
||||
// 쿼리 결과 저장
|
||||
const setQueryResult = useCallback((queryId: string, fields: string[], rows: Record<string, unknown>[]) => {
|
||||
|
||||
Reference in New Issue
Block a user