템플릿 구현
This commit is contained in:
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user