바코드 라벨
상세 밴드를 3열로 찍는 라벨 용지. 라벨마다 Code128과 QR·DataMatrix·PDF417을 벡터로 그립니다.
보고서 정의 (JSON)
{
"name": "자산 관리 라벨",
"page": {
"size": "A4",
"margins": [
12,
12,
12,
12
]
},
"font": {
"family": "Nanum Gothic",
"size": 8
},
"bands": {
"pageHeader": {
"height": 8,
"elements": [
{
"type": "text",
"x": 0,
"y": 0,
"w": 120,
"h": 6,
"text": "자산 관리 라벨 · (주)세컨드코리아",
"style": {
"bold": true,
"fontSize": 9
}
},
{
"type": "text",
"x": 120,
"y": 0,
"w": 66,
"h": 6,
"text": "{page} / {pages}",
"style": {
"align": "right",
"color": "#6b7280"
}
}
]
},
"detail": {
"height": 37,
"columns": 3,
"columnGap": 3,
"canGrow": false,
"elements": [
{
"type": "rect",
"x": 0,
"y": 1,
"w": 60,
"h": 34,
"radius": 1.5,
"color": "#9aa3b2",
"width": 0.25
},
{
"type": "field",
"x": 2,
"y": 3,
"w": 36,
"h": 5.5,
"expr": "name",
"style": {
"bold": true,
"fontSize": 9.5,
"wrap": false,
"shrinkToFit": true,
"padding": [
0,
1,
0,
1
]
}
},
{
"type": "field",
"x": 2,
"y": 9,
"w": 36,
"h": 4.5,
"expr": "assetNo",
"style": {
"fontSize": 7,
"color": "#4a5568",
"padding": [
0,
1,
0,
1
]
}
},
{
"type": "text",
"x": 2,
"y": 13.5,
"w": 36,
"h": 4.5,
"text": "{dept} · {location}",
"style": {
"fontSize": 7,
"color": "#4a5568",
"padding": [
0,
1,
0,
1
]
}
},
{
"type": "text",
"x": 2,
"y": 18,
"w": 36,
"h": 4.5,
"text": "취득 {format(acquired, \"yyyy.MM.dd\")}",
"style": {
"fontSize": 7,
"color": "#4a5568",
"padding": [
0,
1,
0,
1
]
}
},
{
"type": "barcode",
"x": 40,
"y": 3,
"w": 18,
"h": 18,
"expr": "\"https://freereport.app/a/\" + assetNo",
"format": "qr",
"visible": "kind == \"qr\""
},
{
"type": "barcode",
"x": 40,
"y": 3,
"w": 18,
"h": 18,
"expr": "assetNo",
"format": "datamatrix",
"visible": "kind == \"datamatrix\""
},
{
"type": "barcode",
"x": 38,
"y": 5,
"w": 21,
"h": 14,
"expr": "assetNo + \"|\" + dept",
"format": "pdf417",
"visible": "kind == \"pdf417\""
},
{
"type": "field",
"x": 38,
"y": 21,
"w": 22,
"h": 3.5,
"expr": "kind == \"qr\" ? \"QR\" : kind == \"datamatrix\" ? \"DataMatrix\" : \"PDF417\"",
"style": {
"fontSize": 5.5,
"color": "#9aa3b2",
"align": "center",
"padding": 0
}
},
{
"type": "barcode",
"x": 3,
"y": 24,
"w": 54,
"h": 10,
"expr": "assetNo",
"format": "code128"
}
]
}
}
}데이터
긴 목록은 처음 3건만 보여 줍니다.
{
"rows": [
{
"assetNo": "SK-2026-0001",
"name": "노트북 15형",
"dept": "개발팀",
"location": "본사 7층",
"acquired": "2026-01-01",
"kind": "qr"
},
{
"assetNo": "SK-2026-0002",
"name": "27형 모니터",
"dept": "개발팀",
"location": "본사 7층",
"acquired": "2026-02-02",
"kind": "datamatrix"
},
{
"assetNo": "SK-2026-0003",
"name": "레이저 프린터",
"dept": "경영지원팀",
"location": "본사 6층",
"acquired": "2026-03-03",
"kind": "pdf417"
},
"… 21 items"
]
}이 데모의 코드
import type { ReportDefinition, Style } from '@freereportjs/core';
import { mountViewer, select, tr, type DemoContext } from '../ui';
/**
* A 3-across label sheet: the detail band prints rows side by side (`columns: 3`), so each row is
* one asset tag. The 2D symbol is chosen per row with `visible`; every code is drawn as vectors.
*/
const small: Style = { fontSize: 7, color: '#4a5568', padding: [0, 1, 0, 1] };
const kind = (k: string) => `kind == "${k}"`;
export const definition: ReportDefinition = {
name: '자산 관리 라벨',
page: { size: 'A4', margins: [12, 12, 12, 12] },
font: { family: 'Nanum Gothic', size: 8 },
bands: {
pageHeader: {
height: 8,
elements: [
{ type: 'text', x: 0, y: 0, w: 120, h: 6, text: '자산 관리 라벨 · (주)세컨드코리아', style: { bold: true, fontSize: 9 } },
{ type: 'text', x: 120, y: 0, w: 66, h: 6, text: '{page} / {pages}', style: { align: 'right', color: '#6b7280' } },
],
},
detail: {
height: 37,
columns: 3,
columnGap: 3,
canGrow: false,
elements: [
{ type: 'rect', x: 0, y: 1, w: 60, h: 34, radius: 1.5, color: '#9aa3b2', width: 0.25 },
{ type: 'field', x: 2, y: 3, w: 36, h: 5.5, expr: 'name', style: { bold: true, fontSize: 9.5, wrap: false, shrinkToFit: true, padding: [0, 1, 0, 1] } },
{ type: 'field', x: 2, y: 9, w: 36, h: 4.5, expr: 'assetNo', style: small },
{ type: 'text', x: 2, y: 13.5, w: 36, h: 4.5, text: '{dept} · {location}', style: small },
{ type: 'text', x: 2, y: 18, w: 36, h: 4.5, text: '취득 {format(acquired, "yyyy.MM.dd")}', style: small },
// one 2D symbol per label: QR, DataMatrix or PDF417
{ type: 'barcode', x: 40, y: 3, w: 18, h: 18, expr: '"https://freereport.app/a/" + assetNo', format: 'qr', visible: kind('qr') },
{ type: 'barcode', x: 40, y: 3, w: 18, h: 18, expr: 'assetNo', format: 'datamatrix', visible: kind('datamatrix') },
{ type: 'barcode', x: 38, y: 5, w: 21, h: 14, expr: 'assetNo + "|" + dept', format: 'pdf417', visible: kind('pdf417') },
{ type: 'field', x: 38, y: 21, w: 22, h: 3.5, expr: 'kind == "qr" ? "QR" : kind == "datamatrix" ? "DataMatrix" : "PDF417"', style: { fontSize: 5.5, color: '#9aa3b2', align: 'center', padding: 0 } },
{ type: 'barcode', x: 3, y: 24, w: 54, h: 10, expr: 'assetNo', format: 'code128' },
],
},
},
};
const ITEMS = [
['노트북 15형', '개발팀', '본사 7층'], ['27형 모니터', '개발팀', '본사 7층'], ['레이저 프린터', '경영지원팀', '본사 6층'],
['사무용 의자', '영업팀', '본사 6층'], ['높이조절 책상', '디자인팀', '본사 7층'], ['네트워크 스위치', '전산실', '서버실'],
['프로젝터', '회의실', '본사 6층'], ['태블릿', '영업팀', '부산지사'],
] as const;
const KINDS = ['qr', 'datamatrix', 'pdf417'] as const;
/** Asset rows; `kind` picks the 2D symbol ("mixed" cycles through all three). */
export function makeAssets(n: number, symbol: 'mixed' | (typeof KINDS)[number] = 'mixed') {
return Array.from({ length: n }, (_, i) => {
const [name, dept, location] = ITEMS[i % ITEMS.length];
return {
assetNo: `SK-2026-${String(i + 1).padStart(4, '0')}`,
name, dept, location,
acquired: `2026-${String((i % 9) + 1).padStart(2, '0')}-${String((i % 27) + 1).padStart(2, '0')}`,
kind: symbol === 'mixed' ? KINDS[i % 3] : symbol,
};
});
}
export const sampleData = { rows: makeAssets(21) };
export default function mount(ctx: DemoContext) {
const state = { n: 21, symbol: 'mixed' as Parameters<typeof makeAssets>[1] };
const viewer = mountViewer(ctx, { definition, data: sampleData, zoom: 'page', fileName: '자산 라벨' });
const reload = () => void viewer.setData({ rows: makeAssets(state.n, state.symbol) });
select(ctx, tr(ctx.lang, { en: '2D code', ko: '2차원 코드' }), [['mixed', tr(ctx.lang, { en: 'Mixed', ko: '섞어서' })], ['qr', 'QR'], ['datamatrix', 'DataMatrix'], ['pdf417', 'PDF417']], 'mixed', v => { state.symbol = v; reload(); });
select(ctx, tr(ctx.lang, { en: 'Labels', ko: '라벨 수' }), [['9', '9'], ['21', '21'], ['60', '60']], '21', v => { state.n = Number(v); reload(); });
}