템플릿 구현

This commit is contained in:
dohyeons
2025-10-01 14:05:06 +09:00
parent 7a588b47f6
commit 7cefc39b74
3 changed files with 576 additions and 2 deletions

View File

@@ -13,6 +13,251 @@ export interface ReportQuery {
parameters: string[];
}
// 템플릿 레이아웃 정의
interface TemplateLayout {
components: ComponentConfig[];
queries: ReportQuery[];
}
function getTemplateLayout(templateId: string): TemplateLayout | null {
switch (templateId) {
case "order":
return {
components: [
{
id: `comp-${Date.now()}-1`,
type: "label",
x: 50,
y: 30,
width: 200,
height: 40,
fontSize: 24,
fontColor: "#000000",
backgroundColor: "#ffffff",
borderColor: "#000000",
borderWidth: 0,
zIndex: 1,
defaultValue: "발주서",
},
{
id: `comp-${Date.now()}-2`,
type: "text",
x: 50,
y: 80,
width: 150,
height: 30,
fontSize: 14,
fontColor: "#000000",
backgroundColor: "#ffffff",
borderColor: "#cccccc",
borderWidth: 1,
zIndex: 1,
},
{
id: `comp-${Date.now()}-3`,
type: "text",
x: 220,
y: 80,
width: 150,
height: 30,
fontSize: 14,
fontColor: "#000000",
backgroundColor: "#ffffff",
borderColor: "#cccccc",
borderWidth: 1,
zIndex: 1,
},
{
id: `comp-${Date.now()}-4`,
type: "text",
x: 390,
y: 80,
width: 150,
height: 30,
fontSize: 14,
fontColor: "#000000",
backgroundColor: "#ffffff",
borderColor: "#cccccc",
borderWidth: 1,
zIndex: 1,
},
{
id: `comp-${Date.now()}-5`,
type: "table",
x: 50,
y: 130,
width: 500,
height: 200,
fontSize: 12,
fontColor: "#000000",
backgroundColor: "#ffffff",
borderColor: "#cccccc",
borderWidth: 1,
zIndex: 1,
},
],
queries: [
{
id: `query-${Date.now()}-1`,
name: "발주 헤더",
type: "MASTER",
sqlQuery: "SELECT order_no, order_date, supplier_name FROM orders WHERE order_no = $1",
parameters: ["$1"],
},
{
id: `query-${Date.now()}-2`,
name: "발주 품목",
type: "DETAIL",
sqlQuery: "SELECT item_name, quantity, unit_price FROM order_items WHERE order_no = $1",
parameters: ["$1"],
},
],
};
case "invoice":
return {
components: [
{
id: `comp-${Date.now()}-1`,
type: "label",
x: 50,
y: 30,
width: 200,
height: 40,
fontSize: 24,
fontColor: "#000000",
backgroundColor: "#ffffff",
borderColor: "#000000",
borderWidth: 0,
zIndex: 1,
defaultValue: "청구서",
},
{
id: `comp-${Date.now()}-2`,
type: "text",
x: 50,
y: 80,
width: 150,
height: 30,
fontSize: 14,
fontColor: "#000000",
backgroundColor: "#ffffff",
borderColor: "#cccccc",
borderWidth: 1,
zIndex: 1,
},
{
id: `comp-${Date.now()}-3`,
type: "text",
x: 220,
y: 80,
width: 150,
height: 30,
fontSize: 14,
fontColor: "#000000",
backgroundColor: "#ffffff",
borderColor: "#cccccc",
borderWidth: 1,
zIndex: 1,
},
{
id: `comp-${Date.now()}-4`,
type: "table",
x: 50,
y: 130,
width: 500,
height: 200,
fontSize: 12,
fontColor: "#000000",
backgroundColor: "#ffffff",
borderColor: "#cccccc",
borderWidth: 1,
zIndex: 1,
},
{
id: `comp-${Date.now()}-5`,
type: "label",
x: 400,
y: 350,
width: 150,
height: 30,
fontSize: 16,
fontColor: "#000000",
backgroundColor: "#ffffcc",
borderColor: "#000000",
borderWidth: 1,
zIndex: 1,
defaultValue: "합계: 0원",
},
],
queries: [
{
id: `query-${Date.now()}-1`,
name: "청구 헤더",
type: "MASTER",
sqlQuery: "SELECT invoice_no, invoice_date, customer_name FROM invoices WHERE invoice_no = $1",
parameters: ["$1"],
},
{
id: `query-${Date.now()}-2`,
name: "청구 항목",
type: "DETAIL",
sqlQuery: "SELECT description, quantity, unit_price, amount FROM invoice_items WHERE invoice_no = $1",
parameters: ["$1"],
},
],
};
case "basic":
return {
components: [
{
id: `comp-${Date.now()}-1`,
type: "label",
x: 50,
y: 30,
width: 300,
height: 40,
fontSize: 20,
fontColor: "#000000",
backgroundColor: "#ffffff",
borderColor: "#000000",
borderWidth: 0,
zIndex: 1,
defaultValue: "리포트 제목",
},
{
id: `comp-${Date.now()}-2`,
type: "text",
x: 50,
y: 80,
width: 500,
height: 100,
fontSize: 14,
fontColor: "#000000",
backgroundColor: "#ffffff",
borderColor: "#cccccc",
borderWidth: 1,
zIndex: 1,
defaultValue: "내용을 입력하세요",
},
],
queries: [
{
id: `query-${Date.now()}-1`,
name: "기본 쿼리",
type: "MASTER",
sqlQuery: "SELECT * FROM table_name WHERE id = $1",
parameters: ["$1"],
},
],
};
default:
return null;
}
}
export interface QueryResult {
queryId: string;
fields: string[];
@@ -48,6 +293,9 @@ interface ReportDesignerContextType {
saveLayout: () => Promise<void>;
loadLayout: () => Promise<void>;
// 템플릿 적용
applyTemplate: (templateId: string) => void;
// 캔버스 설정
canvasWidth: number;
canvasHeight: number;
@@ -275,6 +523,41 @@ export function ReportDesignerProvider({ reportId, children }: { reportId: strin
}
}, [reportId, canvasWidth, canvasHeight, pageOrientation, margins, components, queries, toast, loadLayout]);
// 템플릿 적용
const applyTemplate = useCallback(
(templateId: string) => {
const templates = getTemplateLayout(templateId);
if (!templates) {
toast({
title: "오류",
description: "템플릿을 찾을 수 없습니다.",
variant: "destructive",
});
return;
}
// 기존 컴포넌트가 있으면 확인
if (components.length > 0) {
if (!confirm("현재 레이아웃을 덮어씁니다. 계속하시겠습니까?")) {
return;
}
}
// 컴포넌트 배치
setComponents(templates.components);
// 쿼리 설정
setQueries(templates.queries);
toast({
title: "성공",
description: "템플릿이 적용되었습니다.",
});
},
[components.length, toast],
);
const value: ReportDesignerContextType = {
reportId,
reportDetail,
@@ -295,6 +578,7 @@ export function ReportDesignerProvider({ reportId, children }: { reportId: strin
updateLayout,
saveLayout,
loadLayout,
applyTemplate,
canvasWidth,
canvasHeight,
pageOrientation,