← 모든 레시피

포장 명세서

상자에 넣는 포장 명세서를 만듭니다. 행이 아무리 많아도 종이를 넘기지 않도록 상한을 두고, 긴 품명을 한 줄로 자르고, 칸 안에 작은 그림을 넣는 법을 배웁니다.

이 템플릿 가져오기

여기서 배우는 것

  • max-rows
  • wrap-off
  • cell-image
  • node-nesting
  • cell-bg

편집기로 만들기

  1. 반복 표를 만들고 최대 행 수를 정합니다. 상한을 넘는 행은 버리고 응답의 warnings 로 알려 드립니다 — 조용히 자르면 상자에 빠진 물건이 생깁니다.
  2. 품명이 길면 줄이 늘어 표가 종이를 넘깁니다. 표 전체 줄바꿈을 끄면 한 줄로 두고 넘치는 만큼 잘라 … 를 붙입니다.
  3. 넘친 글자를 그냥 흘리지 않는 이유는, 종이에서는 옆 칸 위로 겹쳐 인쇄되고 그것이 오류로 보이지 않기 때문입니다.
  4. 특정 칸만 줄바꿈을 되살리고 싶으면 그 칸을 고르고 칸 줄바꿈을 켭니다. 칸이 정하면 칸이 이깁니다.
  5. 손으로 짜는 표에서는 칸에 그림을 넣을 수 있습니다. 취급 주의 표시처럼 작은 아이콘에 씁니다.
  6. 주소 묶음은 사각형 안에 라벨을 담아 만듭니다. 부모를 옮기면 안에 든 것이 함께 움직이므로 배치를 한 번에 바꿀 수 있습니다.

스키마 · API 로 만들기

  1. props.max 가 이 표가 그릴 최대 행 수입니다. 0 이면 여러분이 정한 상한은 없지만 저희 상한은 그대로입니다 — 표 하나는 500행, 한 렌더의 모든 표를 합해 2,000행까지입니다. 표가 여럿이면 그 합이 먼저 끊기니 표 하나만 보고 계산하면 안 됩니다. 넘는 행은 버리고 warnings 로 알려 드립니다.
  2. props.wrap 을 "off" 로 두면 표 전체가 한 줄로 잘립니다. 칸에서 되살리려면 cells[].wrap 을 "on" 으로 둡니다.
  3. cells[].src 는 data:image/ 로 시작하는 값만 받습니다. 칸에서는 던지지 않고 그 칸만 비우며 경고합니다 — 그림 하나 때문에 명세서 전체를 잃지 않기 위해서입니다.

완성 문서

아래 JSON 이 위 두 순서가 만드는 바로 그 문서입니다. 저희 테스트가 이 문서를 검증하고 경고 없이 렌더되는지 확인하므로, 그대로 붙여 넣어 쓰셔도 됩니다.

예시
{
  "v": 1,
  "unit": "px",
  "page": {
    "size": "a4",
    "orientation": "portrait",
    "margin": {
      "t": 48,
      "r": 48,
      "b": 56,
      "l": 48
    },
    "header": "",
    "footer": "{{ data.order }} · [[page]] / [[pages]]"
  },
  "fonts": [],
  "styles": [
    {
      "id": "s_h1",
      "fontFamily": "Liberation Sans",
      "fontSize": 22,
      "fontWeight": 700,
      "italic": false,
      "color": "#111111",
      "bg": "transparent",
      "align": "left",
      "valign": "top",
      "lineHeight": 1.5,
      "border": "none",
      "radius": 0,
      "opacity": 1
    },
    {
      "id": "s_l",
      "fontFamily": "Liberation Sans",
      "fontSize": 12,
      "fontWeight": 400,
      "italic": false,
      "color": "#333333",
      "bg": "transparent",
      "align": "left",
      "valign": "top",
      "lineHeight": 1.5,
      "border": "none",
      "radius": 0,
      "opacity": 1
    },
    {
      "id": "s_tbl",
      "fontFamily": "Liberation Sans",
      "fontSize": 11,
      "fontWeight": 400,
      "italic": false,
      "color": "#111111",
      "bg": "transparent",
      "align": "left",
      "valign": "middle",
      "lineHeight": 1.5,
      "border": "none",
      "radius": 0,
      "opacity": 1
    }
  ],
  "nodes": [
    {
      "id": "n_title",
      "parent": "",
      "order": 0,
      "type": "label",
      "x": 0,
      "y": 0,
      "w": 400,
      "h": 28,
      "show": "",
      "styleId": "s_h1",
      "props": {
        "text": "Packing slip",
        "src": "",
        "fit": "",
        "thickness": 0,
        "stroke": "",
        "fill": "",
        "repeat": "",
        "as": "",
        "break": "",
        "keep": "",
        "padding": 0,
        "padY": 0,
        "padX": 0,
        "align": "",
        "valign": "",
        "wrap": "",
        "bind": "",
        "headerHeight": 0,
        "rowHeight": 0,
        "max": 0,
        "columns": [],
        "rows": 0,
        "cells": [],
        "chartKind": "",
        "codeKind": "",
        "ecc": "",
        "fieldKind": "",
        "fieldName": "",
        "options": [],
        "required": false,
        "readonly": false,
        "html": ""
      },
      "name": "Title"
    },
    {
      "id": "n_addr",
      "parent": "",
      "order": 1,
      "type": "rect",
      "x": 400,
      "y": 0,
      "w": 297,
      "h": 96,
      "show": "",
      "styleId": "s_l",
      "props": {
        "text": "",
        "src": "",
        "fit": "",
        "thickness": 1,
        "stroke": "#dfe3e8",
        "fill": "#fafbfc",
        "repeat": "",
        "as": "",
        "break": "",
        "keep": "",
        "padding": 0,
        "padY": 0,
        "padX": 0,
        "align": "",
        "valign": "",
        "wrap": "",
        "bind": "",
        "headerHeight": 0,
        "rowHeight": 0,
        "max": 0,
        "columns": [],
        "rows": 0,
        "cells": [],
        "chartKind": "",
        "codeKind": "",
        "ecc": "",
        "fieldKind": "",
        "fieldName": "",
        "options": [],
        "required": false,
        "readonly": false,
        "html": ""
      },
      "name": "Ship-to block"
    },
    {
      "id": "n_addr_1",
      "parent": "n_addr",
      "order": 2,
      "type": "label",
      "x": 12,
      "y": 10,
      "w": 273,
      "h": 18,
      "show": "",
      "styleId": "s_l",
      "props": {
        "text": "{{ data.shipTo.name }}",
        "src": "",
        "fit": "",
        "thickness": 0,
        "stroke": "",
        "fill": "",
        "repeat": "",
        "as": "",
        "break": "",
        "keep": "",
        "padding": 0,
        "padY": 0,
        "padX": 0,
        "align": "",
        "valign": "",
        "wrap": "",
        "bind": "",
        "headerHeight": 0,
        "rowHeight": 0,
        "max": 0,
        "columns": [],
        "rows": 0,
        "cells": [],
        "chartKind": "",
        "codeKind": "",
        "ecc": "",
        "fieldKind": "",
        "fieldName": "",
        "options": [],
        "required": false,
        "readonly": false,
        "html": ""
      },
      "name": "Recipient"
    },
    {
      "id": "n_addr_2",
      "parent": "n_addr",
      "order": 3,
      "type": "label",
      "x": 12,
      "y": 30,
      "w": 273,
      "h": 0,
      "show": "",
      "styleId": "s_l",
      "props": {
        "text": "{{ data.shipTo.address }}",
        "src": "",
        "fit": "",
        "thickness": 0,
        "stroke": "",
        "fill": "",
        "repeat": "",
        "as": "",
        "break": "",
        "keep": "",
        "padding": 0,
        "padY": 0,
        "padX": 0,
        "align": "",
        "valign": "",
        "wrap": "",
        "bind": "",
        "headerHeight": 0,
        "rowHeight": 0,
        "max": 0,
        "columns": [],
        "rows": 0,
        "cells": [],
        "chartKind": "",
        "codeKind": "",
        "ecc": "",
        "fieldKind": "",
        "fieldName": "",
        "options": [],
        "required": false,
        "readonly": false,
        "html": ""
      },
      "name": "Address"
    },
    {
      "id": "n_addr_3",
      "parent": "n_addr",
      "order": 4,
      "type": "label",
      "x": 12,
      "y": 70,
      "w": 273,
      "h": 18,
      "show": "",
      "styleId": "s_l",
      "props": {
        "text": "Order {{ data.order }}",
        "src": "",
        "fit": "",
        "thickness": 0,
        "stroke": "",
        "fill": "",
        "repeat": "",
        "as": "",
        "break": "",
        "keep": "",
        "padding": 0,
        "padY": 0,
        "padX": 0,
        "align": "",
        "valign": "",
        "wrap": "",
        "bind": "",
        "headerHeight": 0,
        "rowHeight": 0,
        "max": 0,
        "columns": [],
        "rows": 0,
        "cells": [],
        "chartKind": "",
        "codeKind": "",
        "ecc": "",
        "fieldKind": "",
        "fieldName": "",
        "options": [],
        "required": false,
        "readonly": false,
        "html": ""
      },
      "name": "Order number"
    },
    {
      "id": "n_items",
      "parent": "",
      "order": 5,
      "type": "table",
      "x": 0,
      "y": 120,
      "w": 697,
      "h": 220,
      "show": "",
      "styleId": "s_tbl",
      "props": {
        "text": "",
        "src": "",
        "fit": "",
        "thickness": 1,
        "stroke": "#c9ced6",
        "fill": "#f3f5f7",
        "repeat": "",
        "as": "",
        "break": "",
        "keep": "",
        "padding": 0,
        "padY": 5,
        "padX": 8,
        "align": "",
        "valign": "middle",
        "wrap": "off",
        "bind": "data.items",
        "headerHeight": 26,
        "rowHeight": 22,
        "max": 40,
        "columns": [
          {
            "header": "SKU",
            "cell": "{{ item.sku }}",
            "width": 140,
            "align": "left"
          },
          {
            "header": "Product",
            "cell": "{{ item.name }}",
            "width": 397,
            "align": "left"
          },
          {
            "header": "Qty",
            "cell": "{{ item.qty }}",
            "width": 160,
            "align": "right"
          }
        ],
        "rows": 0,
        "cells": [],
        "chartKind": "",
        "codeKind": "",
        "ecc": "",
        "fieldKind": "",
        "fieldName": "",
        "options": [],
        "required": false,
        "readonly": false,
        "html": ""
      },
      "name": "Line items"
    },
    {
      "id": "n_care",
      "parent": "",
      "order": 6,
      "type": "table",
      "x": 0,
      "y": 360,
      "w": 340,
      "h": 90,
      "show": "",
      "styleId": "s_tbl",
      "props": {
        "text": "",
        "src": "",
        "fit": "",
        "thickness": 1,
        "stroke": "#c9ced6",
        "fill": "#f3f5f7",
        "repeat": "",
        "as": "",
        "break": "",
        "keep": "",
        "padding": 0,
        "padY": 8,
        "padX": 10,
        "align": "",
        "valign": "middle",
        "wrap": "",
        "bind": "",
        "headerHeight": 0,
        "rowHeight": 44,
        "max": 0,
        "columns": [
          {
            "header": "",
            "cell": "",
            "width": 110,
            "align": "center"
          },
          {
            "header": "",
            "cell": "",
            "width": 230,
            "align": "left"
          }
        ],
        "rows": 2,
        "cells": [
          {
            "r": 0,
            "c": 0,
            "span": 1,
            "rowspan": 1,
            "text": "",
            "align": "left",
            "valign": "",
            "wrap": "",
            "pad": -1,
            "padY": -1,
            "padX": -1,
            "src": "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMjAgNjAiPjxyZWN0IHdpZHRoPSIxMjAiIGhlaWdodD0iNjAiIHJ4PSI4IiBmaWxsPSIjMWYyOTM3Ii8+PHRleHQgeD0iNjAiIHk9IjM4IiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIyMCIgZmlsbD0iI2ZmZiIgdGV4dC1hbmNob3I9Im1pZGRsZSI+TE9HTzwvdGV4dD48L3N2Zz4=",
            "fit": "contain",
            "bg": "#ffffff",
            "head": false,
            "border": ""
          },
          {
            "r": 0,
            "c": 1,
            "span": 1,
            "rowspan": 1,
            "text": "Handle with care — do not lay the box flat.",
            "align": "left",
            "valign": "",
            "wrap": "",
            "pad": -1,
            "padY": -1,
            "padX": -1,
            "src": "",
            "fit": "",
            "bg": "",
            "head": true,
            "border": ""
          },
          {
            "r": 1,
            "c": 0,
            "span": 1,
            "rowspan": 1,
            "text": "↑",
            "align": "center",
            "valign": "",
            "wrap": "",
            "pad": -1,
            "padY": -1,
            "padX": -1,
            "src": "",
            "fit": "",
            "bg": "",
            "head": false,
            "border": ""
          },
          {
            "r": 1,
            "c": 1,
            "span": 1,
            "rowspan": 1,
            "text": "This side up.",
            "align": "left",
            "valign": "",
            "wrap": "",
            "pad": -1,
            "padY": -1,
            "padX": -1,
            "src": "",
            "fit": "",
            "bg": "",
            "head": false,
            "border": ""
          }
        ],
        "chartKind": "",
        "codeKind": "",
        "ecc": "",
        "fieldKind": "",
        "fieldName": "",
        "options": [],
        "required": false,
        "readonly": false,
        "html": ""
      },
      "name": "Handling"
    }
  ]
}

요청 본문입니다. template 자리에 위 문서를, data 자리에 아래 데이터를 넣습니다.

요청
{
  "template": "(the document above)",
  "data": {
    "order": "SO-2026-8841",
    "shipTo": {
      "name": "Hanbit Corp. warehouse",
      "address": "118 Seongsui-ro, Seongdong-gu, Seoul, 3F"
    },
    "items": [
      {
        "sku": "BM-0001",
        "name": "brewmypdf mug (white, 350ml, individually boxed)",
        "qty": 12
      },
      {
        "sku": "BM-0002",
        "name": "Sticker set",
        "qty": 40
      },
      {
        "sku": "BM-0003",
        "name": "Notebook A5",
        "qty": 25
      }
    ]
  }
}