FreeReportv0.1.0English

매출 보고서

조회 조건, 지역별 그룹과 소계, 페이지 소계, 차트, 출력자·출력 일시 워터마크.

보고서 정의 (JSON)

{
  "name": "지역별 매출 보고서",
  "page": {
    "size": "A4",
    "margins": [
      14,
      15,
      14,
      15
    ]
  },
  "font": {
    "family": "Nanum Gothic",
    "size": 8.5
  },
  "params": {
    "title": {
      "label": "보고서 제목",
      "type": "string",
      "default": "2026년 3분기 지역별 매출 보고서"
    },
    "minAmount": {
      "label": "최소 금액",
      "type": "number",
      "default": 0
    },
    "printedBy": {
      "label": "출력자",
      "type": "string",
      "default": "홍길동"
    }
  },
  "filter": "amount >= (params.minAmount ?? 0)",
  "sort": [
    "date"
  ],
  "watermark": {
    "text": "{params.printedBy} · {format(now(), \"yyyy-MM-dd HH:mm\")} 출력",
    "repeat": true,
    "opacity": 0.06,
    "fontSize": 11,
    "gap": 55
  },
  "bands": {
    "title": {
      "height": 30,
      "elements": [
        {
          "type": "text",
          "x": 0,
          "y": 0,
          "w": 180,
          "h": 12,
          "text": "{params.title}",
          "style": {
            "fontSize": 17,
            "bold": true,
            "align": "center"
          }
        },
        {
          "type": "text",
          "x": 0,
          "y": 13,
          "w": 180,
          "h": 6,
          "text": "기간 2026-07-01 ~ 2026-09-30 · 대상 {count()}건 · 합계 {sum(amount):#,##0}원",
          "style": {
            "align": "center",
            "color": "#4a5568"
          }
        }
      ]
    },
    "pageHeader": {
      "height": 8,
      "elements": [
        {
          "type": "text",
          "x": 0,
          "y": 0,
          "w": 120,
          "h": 6,
          "text": "(주)세컨드코리아 · 영업관리팀",
          "style": {
            "color": "#6b7280",
            "fontSize": 7.5
          }
        },
        {
          "type": "text",
          "x": 120,
          "y": 0,
          "w": 60,
          "h": 6,
          "text": "{params.title}",
          "style": {
            "color": "#6b7280",
            "fontSize": 7.5,
            "align": "right"
          }
        },
        {
          "type": "line",
          "x": 0,
          "y": 6.5,
          "w": 180,
          "h": 0,
          "color": "#c9d0da",
          "width": 0.2
        }
      ]
    },
    "columnHeader": {
      "height": 7,
      "elements": [
        {
          "x": 0,
          "y": 0,
          "w": 12,
          "h": 7,
          "type": "text",
          "text": "번호",
          "style": {
            "bold": true,
            "align": "center",
            "background": "#eef1f6",
            "border": "0.2 solid #8a94a6"
          }
        },
        {
          "x": 12,
          "y": 0,
          "w": 22,
          "h": 7,
          "type": "text",
          "text": "일자",
          "style": {
            "bold": true,
            "align": "center",
            "background": "#eef1f6",
            "border": "0.2 solid #8a94a6"
          }
        },
        {
          "x": 34,
          "y": 0,
          "w": 34,
          "h": 7,
          "type": "text",
          "text": "거래처",
          "style": {
            "bold": true,
            "align": "center",
            "background": "#eef1f6",
            "border": "0.2 solid #8a94a6"
          }
        },
        {
          "x": 68,
          "y": 0,
          "w": 42,
          "h": 7,
          "type": "text",
          "text": "품목",
          "style": {
            "bold": true,
            "align": "center",
            "background": "#eef1f6",
            "border": "0.2 solid #8a94a6"
          }
        },
        {
          "x": 110,
          "y": 0,
          "w": 14,
          "h": 7,
          "type": "text",
          "text": "수량",
          "style": {
            "bold": true,
            "align": "center",
            "background": "#eef1f6",
            "border": "0.2 solid #8a94a6"
          }
        },
        {
          "x": 124,
          "y": 0,
          "w": 24,
          "h": 7,
          "type": "text",
          "text": "단가",
          "style": {
            "bold": true,
            "align": "center",
            "background": "#eef1f6",
            "border": "0.2 solid #8a94a6"
          }
        },
        {
          "x": 148,
          "y": 0,
          "w": 32,
          "h": 7,
          "type": "text",
          "text": "금액",
          "style": {
            "bold": true,
            "align": "center",
            "background": "#eef1f6",
            "border": "0.2 solid #8a94a6"
          }
        }
      ]
    },
    "groups": [
      {
        "by": "region",
        "sort": "asc",
        "repeatHeader": true,
        "keepWithRows": 2,
        "header": {
          "height": 7,
          "elements": [
            {
              "type": "text",
              "x": 0,
              "y": 0,
              "w": 180,
              "h": 7,
              "text": "■ {region}  ({count()}건)",
              "style": {
                "bold": true,
                "color": "#1a2fc0",
                "border": {
                  "bottom": "0.3 solid #1a2fc0"
                }
              }
            }
          ]
        },
        "footer": {
          "height": 7.5,
          "elements": [
            {
              "type": "text",
              "x": 0,
              "y": 0,
              "w": 110,
              "h": 7,
              "text": "{region} 소계",
              "style": {
                "border": "0.15 solid #b9c1cd",
                "bold": true,
                "align": "center",
                "background": "#f7f8fb"
              }
            },
            {
              "type": "field",
              "x": 110,
              "y": 0,
              "w": 14,
              "h": 7,
              "expr": "sum(qty)",
              "format": "#,##0",
              "style": {
                "border": "0.15 solid #b9c1cd",
                "align": "right",
                "bold": true,
                "background": "#f7f8fb"
              }
            },
            {
              "type": "text",
              "x": 124,
              "y": 0,
              "w": 24,
              "h": 7,
              "text": "",
              "style": {
                "border": "0.15 solid #b9c1cd",
                "background": "#f7f8fb"
              }
            },
            {
              "type": "field",
              "x": 148,
              "y": 0,
              "w": 32,
              "h": 7,
              "expr": "sum(amount)",
              "format": "#,##0",
              "style": {
                "border": "0.15 solid #b9c1cd",
                "align": "right",
                "bold": true,
                "background": "#f7f8fb"
              }
            }
          ]
        }
      }
    ],
    "detail": {
      "height": 6,
      "altBackground": "#fafbfd",
      "elements": [
        {
          "x": 0,
          "y": 0,
          "w": 12,
          "h": 6,
          "type": "field",
          "expr": "rowNum",
          "style": {
            "border": "0.15 solid #b9c1cd",
            "align": "center",
            "color": "#6b7280"
          }
        },
        {
          "x": 12,
          "y": 0,
          "w": 22,
          "h": 6,
          "type": "field",
          "expr": "date",
          "format": "yyyy-MM-dd",
          "style": {
            "border": "0.15 solid #b9c1cd",
            "align": "center"
          }
        },
        {
          "x": 34,
          "y": 0,
          "w": 34,
          "h": 6,
          "type": "field",
          "expr": "customer",
          "style": {
            "border": "0.15 solid #b9c1cd"
          }
        },
        {
          "x": 68,
          "y": 0,
          "w": 42,
          "h": 6,
          "type": "field",
          "expr": "product",
          "style": {
            "border": "0.15 solid #b9c1cd"
          }
        },
        {
          "x": 110,
          "y": 0,
          "w": 14,
          "h": 6,
          "type": "field",
          "expr": "qty",
          "format": "#,##0",
          "style": {
            "border": "0.15 solid #b9c1cd",
            "align": "right"
          }
        },
        {
          "x": 124,
          "y": 0,
          "w": 24,
          "h": 6,
          "type": "field",
          "expr": "price",
          "format": "#,##0",
          "style": {
            "border": "0.15 solid #b9c1cd",
            "align": "right"
          }
        },
        {
          "x": 148,
          "y": 0,
          "w": 32,
          "h": 6,
          "type": "field",
          "expr": "amount",
          "format": "#,##0",
          "style": {
            "border": "0.15 solid #b9c1cd",
            "align": "right",
            "bold": true
          }
        }
      ]
    },
    "summary": {
      "height": 78,
      "elements": [
        {
          "type": "text",
          "x": 0,
          "y": 2,
          "w": 110,
          "h": 8,
          "text": "총 합계",
          "style": {
            "bold": true,
            "align": "center",
            "background": "#eef1f6",
            "border": "0.2 solid #8a94a6",
            "fontSize": 10
          }
        },
        {
          "type": "field",
          "x": 110,
          "y": 2,
          "w": 14,
          "h": 8,
          "expr": "sum(qty)",
          "format": "#,##0",
          "style": {
            "bold": true,
            "align": "right",
            "background": "#eef1f6",
            "border": "0.2 solid #8a94a6"
          }
        },
        {
          "type": "text",
          "x": 124,
          "y": 2,
          "w": 24,
          "h": 8,
          "text": "",
          "style": {
            "bold": true,
            "align": "center",
            "background": "#eef1f6",
            "border": "0.2 solid #8a94a6"
          }
        },
        {
          "type": "field",
          "x": 148,
          "y": 2,
          "w": 32,
          "h": 8,
          "expr": "sum(amount)",
          "format": "#,##0",
          "style": {
            "bold": true,
            "align": "right",
            "background": "#eef1f6",
            "border": "0.2 solid #8a94a6",
            "fontSize": 10
          }
        },
        {
          "type": "chart",
          "x": 0,
          "y": 16,
          "w": 112,
          "h": 60,
          "chartType": "bar",
          "title": "지역별 매출",
          "source": "groupSum(rows, \"region\", \"amount\")",
          "category": "region",
          "series": [
            {
              "expr": "amount",
              "label": "매출"
            }
          ],
          "format": "#,##0,\"천\"",
          "showValues": false
        },
        {
          "type": "chart",
          "x": 116,
          "y": 16,
          "w": 64,
          "h": 60,
          "chartType": "doughnut",
          "title": "품목군 비중",
          "source": "groupSum(rows, \"category\", \"amount\")",
          "category": "category",
          "series": [
            {
              "expr": "amount"
            }
          ]
        }
      ]
    },
    "pageFooter": {
      "height": 9,
      "elements": [
        {
          "type": "line",
          "x": 0,
          "y": 1,
          "w": 180,
          "h": 0,
          "color": "#c9d0da",
          "width": 0.2
        },
        {
          "type": "text",
          "x": 0,
          "y": 2,
          "w": 90,
          "h": 6,
          "text": "이 페이지 소계 {sum(amount, \"page\"):#,##0}원",
          "style": {
            "fontSize": 7.5,
            "color": "#4a5568"
          }
        },
        {
          "type": "text",
          "x": 90,
          "y": 2,
          "w": 90,
          "h": 6,
          "text": "{page} / {pages}",
          "style": {
            "fontSize": 7.5,
            "align": "right",
            "color": "#4a5568"
          }
        }
      ]
    }
  }
}

데이터

긴 목록은 처음 3건만 보여 줍니다.

{
  "rows": [
    {
      "no": 1,
      "date": "2026-09-28",
      "region": "대구",
      "customer": "다온상사",
      "manager": "정하준",
      "product": "노트북 15형",
      "category": "전자",
      "qty": 1,
      "price": 1290000,
      "amount": 1290000
    },
    {
      "no": 2,
      "date": "2026-07-21",
      "region": "서울",
      "customer": "새봄디자인",
      "manager": "강서윤",
      "product": "무선 키보드",
      "category": "주변기기",
      "qty": 7,
      "price": 59000,
      "amount": 413000
    },
    {
      "no": 3,
      "date": "2026-08-09",
      "region": "경기",
      "customer": "온누리건설",
      "manager": "박도윤",
      "product": "27형 모니터",
      "category": "전자",
      "qty": 5,
      "price": 349000,
      "amount": 1745000
    },
    "… 180 items"
  ]
}

이 데모의 코드

import { makeSales } from '../../samples/data';
import { salesReport } from '../../samples/reports';
import { mountViewer, select, tr, type DemoContext } from '../ui';

/** 매출 보고서: parameters, region groups with subtotals, page subtotals, charts and a security watermark. */
export const definition = salesReport;
export const sampleData = { rows: makeSales(180) };

export default function mount(ctx: DemoContext) {
  const viewer = mountViewer(ctx, { definition, data: sampleData, paramsOpen: true, fileName: '매출 보고서', toolbar: { csv: true } });
  select(ctx, tr(ctx.lang, { en: 'Rows', ko: '건수' }), [['60', '60'], ['180', '180'], ['1000', '1,000']], '180', n => {
    void viewer.setData({ rows: makeSales(Number(n)) });
  });
}