본문으로 건너뛰기

리포트 출력 사용법 (syn.$p)

개요

syn.$p(원본: context.$print)는 Excel/PDF 리포트 서버인 "Reportify"와 연동하기 위한 URL 생성, 그리고 리포트에 데이터를 채워 넣기 위한 작업 항목(workItem) 구성/변환 기능을 제공합니다. 실제 PDF 변환·인쇄·뷰어 렌더링(generate, renderViewer, renderPrint, getSchemeText)은 syn.Config.IsReportifyModuletrue로 설정되고, Reportify 서버(reportifyServer + reportifyPath)가 실제로 응답할 때만 동작합니다.

로드 방법

syn.js가 로드되면 전역에 syn.$p(별칭: $print)로 즉시 사용할 수 있습니다. 브라우저 환경에서 syn.Config.IsReportifyModuletrue이면 concreate() 시점에 pdfobject.min.js, print-jsprint.min.js를 지연 로드합니다(둘 다 없으면 URL 생성 이외의 렌더링 기능은 사용할 수 없습니다).

빠른 시작

// 1) Reportify 서버 요청 URL 생성 (문자열만 생성, 네트워크 호출 없음)
const url = syn.$p.getReportifyUrl('excel-to-pdf');

// 2) workItem 배열 구성 (메모리 내 데이터, 네트워크 불필요)
const workItems = [];
syn.$p.addWorkItem(workItems, {
document: 0, worksheet: 'Sheet1', datafield: 'CompanyName',
bind: 'cell', row: 1, col: 1, type: 'text'
});

주요 시나리오

Reportify 서버 URL 생성

getReportifyUrl(actionName)${reportifyServer}${reportifyPath}/${actionName} 형태로, getDocumentTemplateUrl(reportFileID)${reportifyServer}${reportifyTemplateUrl}${reportFileID} 형태로 URL 문자열을 만듭니다. 둘 다 실제 요청을 보내지 않고 문자열만 반환하므로, 백엔드 없이도 결과를 확인할 수 있습니다.

const url = syn.$p.getReportifyUrl('excel-to-pdf');
const templateUrl = syn.$p.getDocumentTemplateUrl('RPT-0001');

workItem 추가/삽입/수정/삭제

addWorkItem은 workItems 배열에 새 항목을 추가합니다. 객체 형태로 호출하는 것을 권장합니다.

syn.$p.addWorkItem(workItems, {
document: 0, worksheet: 'Sheet1', datafield: 'ReportDate',
bind: 'cell', row: 1, col: 2, type: 'text'
});

주의: addWorkItem(workItems, document, worksheet, datafield, bind, row, col, ...)처럼 두 번째 인자부터 각 필드를 개별 인자로 나열하는 방식은, 현재 소스(약 11296번째 줄)의 필수값 검증 조건이 if (document || worksheet || bind || row || col)로 되어 있어(값이 있으면 오히려 경고를 남기는 형태) 정상적인 값이 전달되어도 대부분 경고 로그만 남기고 항목이 추가되지 않습니다. 실사용 시 객체 인자 형태를 사용하십시오.

addAtWorkItem(workItems, document, worksheet, datafield, target, nextDirection)은 기존 항목을 기준으로 새 항목을 삽입합니다. 이때 target.datafield는 workItems 내에 이미 존재하는(같은 document/worksheet) 항목의 datafield와 일치해야 그 위치를 기준으로 삽입됩니다(동일 필드를 여러 셀에 반복 출력할 때 유용).

syn.$p.addAtWorkItem(workItems, 0, 'Sheet1', 'CompanyName', {
document: 0, worksheet: 'Sheet1', datafield: 'CompanyName',
bind: 'cell', row: 1, col: 3, type: 'text'
}, true);

updateWorkItem/removeWorkItem은 document/worksheet/datafield 조합으로 항목을 찾아 각각 속성 병합, 제거를 수행합니다.

데이터 소스와 workItems 바인딩

bindingWorkItems(workItems, dataSource, documentOffset)은 workItems를 복제한 뒤, dataSource의 각 키(예: header, details)를 순회하며 bind'cell'이면 단일 값을, 'item'/'list'이면 배열 데이터를 채워 넣습니다.

const dataSource = {
header: { CompanyName: 'HandStack Inc.', ReportDate: '2026-07-06' },
details: [{ ProductName: 'Widget A', Qty: 10 }]
};
const bound = syn.$p.bindingWorkItems(workItems, dataSource, 1);

리포트용 배열/폼 데이터 변환

  • calculateOffsets(totalCount, step): 다중 페이지 문서 오프셋 배열 생성.
  • transformWorkData(jsonData, keys): JSON 배열의 각 행을 지정 키 순서의 값 배열로 변환.
  • transformFormData(jsonData, offset, padding, defaultKeys): JSON 배열을 필드명+순번 형태의 평면 객체로 변환(폼 필드 자동 채움에 사용).
  • splitDataChunks(dataList, firstLength, chunkSize): 첫 페이지는 firstLength개, 이후는 chunkSize개씩 데이터를 나눔.
const offsets = syn.$p.calculateOffsets(10, 3); // [0, 3, 6, 9]
const formData = syn.$p.transformFormData(list, 1, 5, 'ProductName,Qty:0');
const chunks = syn.$p.splitDataChunks(list, 2, 3);

실전 예제 페이지

/sample/syn/print.html 예제에서 다음 항목을 실습할 수 있습니다.

  • getReportifyUrl(), getDocumentTemplateUrl() — 생성된 URL 문자열 확인
  • addWorkItem(), addAtWorkItem(), updateWorkItem(), removeWorkItem() — 메모리 내 workItems 배열의 실시간 변화 확인
  • calculateOffsets(), bindingWorkItems(), transformWorkData(), transformFormData(), splitDataChunks() — 예제 데이터로 각 변환 결과 확인

주의 사항

  • 이 예제 페이지는 실제 Reportify 서버와 연동되어 있지 않습니다. generate(), renderViewer(), renderPrint(), getSchemeText() 등 실제 PDF/Excel 렌더링·인쇄·다운로드를 수행하는 메서드는 syn.Config.IsReportifyModule = true 설정과 실행 중인 Reportify 서버(syn.$p.reportifyServer)가 있어야 동작하며, 이 샘플에서는 다루지 않습니다.
  • addWorkItem을 개별 인자(document, worksheet, ...) 형태로 호출하면 현재 소스의 조건 반전으로 인해 정상 값에도 경고만 남고 추가되지 않습니다. 객체 인자 형태를 사용하십시오.
  • addAtWorkItemtarget.datafield는 반드시 workItems 내 기존 항목(같은 document/worksheet)의 datafield와 일치해야 삽입 위치가 계산됩니다. 일치하는 항목이 없으면 경고 로그만 남고 아무 것도 삽입되지 않습니다.
  • Node.js 환경(devicePlatform === 'node')에서는 renderViewer, renderPrint, getSchemeText가 로드 시 제거되어 존재하지 않습니다.

관련 모듈

  • API 상세는 아래 API 참조 섹션을 확인하세요.

API 참조

모듈 정보

항목내용
전역 별칭syn.$p (원본: context.$print)
소스 위치2.Modules/wwwroot/wwwroot/js/syn.js (약 11135~11614번째 줄)
예제 페이지/sample/syn/print.html
의존 모듈syn.$l(eventLog), syn.$object(isNumber, isObject, isNullOrUndefined), syn.$string(isNullOrEmpty, toBoolean), syn.$w(proxyBasePath, loadScript) — 실제 렌더링 시 syn.$r(httpRequest, createBlobUrl), PDFObject, printJS도 필요
활성화 조건syn.Config.IsReportifyModuletrue여야 PDF 뷰어/인쇄 스크립트(pdfobject.min.js, print-js)가 로드됩니다. 이 문서에서 다루는 workItem 구성/변환 메서드는 이 설정과 무관하게 항상 사용할 수 있습니다.

속성

이름기본값설명
reportNamereport-${today}.pdf생성될 리포트 파일 이름.
datetimeFormat'yyyy-MM-dd'리포트 내 날짜 표시 형식.
boolTrue / boolFalse'○' / '×'리포트 내 불리언 값 표시 문자.
workItems / workActions[]generate() 호출 시 기본으로 사용하는 작업 항목/액션 배열(전역 상태). 페이지별로 별도 배열을 만들어 관리하는 것을 권장합니다.
reportifyServer'' (Node: http://localhost:8421)Reportify 서버 origin.
reportifyPath${proxyBasePath}/reportify/api/briefReportify API 기본 경로. getReportifyUrl()에 사용됩니다.
reportifyTemplateUrl${proxyBasePath}/reportify/api/index/download-template?reportFileID=문서 템플릿 다운로드 경로. getDocumentTemplateUrl()에 사용됩니다.
pageExportScheme / pageExcelToPdf'export-scheme' / 'excel-to-pdf'getReportifyUrl()에 전달할 대표 액션 이름 상수.
overwriteFontNamenull리포트 생성 시 강제로 사용할 폰트 이름.

메서드

syn.$p.getReportifyUrl(actionName)

  • 설명: Reportify 서버 API 요청 URL을 생성합니다(네트워크 호출 없음).
  • 매개변수
    이름타입필수설명
    actionNamestringYReportify API 액션 이름(예: 'excel-to-pdf', 'export-scheme').
  • 반환값: string${reportifyServer}${reportifyPath}/${actionName}
  • 예시
    const url = syn.$p.getReportifyUrl('excel-to-pdf');

syn.$p.getDocumentTemplateUrl(reportFileID)

  • 설명: 문서 템플릿 다운로드 URL을 생성합니다(네트워크 호출 없음).
  • 매개변수
    이름타입필수설명
    reportFileIDstringY다운로드할 리포트 템플릿 파일 ID.
  • 반환값: string${reportifyServer}${reportifyTemplateUrl}${reportFileID}
  • 예시
    const url = syn.$p.getDocumentTemplateUrl('RPT-0001');

syn.$p.addWorkItem(workItems, document, worksheet, datafield, bind, row, col, type, data, overtake, step)

  • 설명: workItems 배열에 새 작업 항목(문서/시트/필드와 값 바인딩 정보)을 추가합니다. 두 번째 인자 타입에 따라 두 가지 호출 방식을 지원합니다.
    • 두 번째 인자가 숫자(document)이면 이후 인자들을 개별 필드로 받는 위치 인자 방식입니다. 단, 현재 소스(약 11228번째 줄)의 검증 조건이 if (document || worksheet || bind || row || col)로 되어 있어, 정상적인(참 값) 인자를 넘겨도 매번 Warning 로그만 남고 실제로는 추가되지 않는 결함이 있습니다.
    • 두 번째 인자가 객체이면 { document, worksheet, datafield, bind, row, col, type, data, overtake, step } 형태로 한 번에 전달합니다. 이 방식은 !workObject.document || !workObject.worksheet || !workObject.bind || !workObject.row || !workObject.col 검증을 통과하면 정상적으로 추가됩니다. 실사용 시 이 방식을 권장합니다.
  • 매개변수
    이름타입필수설명
    workItemsArrayY항목을 추가할 대상 배열.
    document`number \object`Y
    worksheet, datafield, bind, row, col, type, data, overtake, step다양N (객체 호출 시 무시됨)위치 인자 방식에서 사용하는 개별 필드.
  • 반환값: 없음(workItems를 직접 변경). 필수값 누락 시 syn.$l.eventLogWarning 로그만 남깁니다.
  • 예시
    syn.$p.addWorkItem(workItems, {
    document: 0, worksheet: 'Sheet1', datafield: 'CompanyName',
    bind: 'cell', row: 1, col: 1, type: 'text'
    });

syn.$p.addAtWorkItem(workItems, document, worksheet, datafield, target, nextDirection)

  • 설명: 기존 항목을 기준으로 새 항목을 삽입합니다. 먼저 document/worksheet/datafield로 workItems 내에 항목이 존재하는지 확인(가드)한 뒤, target.document/target.worksheet/target.datafield와 일치하는 기존 항목을 다시 찾아 그 위치를 기준으로 target 정보로 만든 새 항목을 삽입합니다. 따라서 target.datafield는 workItems 내 이미 존재하는 항목의 datafield와 같아야 합니다(예: 동일 필드를 다른 셀 위치에 반복 배치).
  • 매개변수
    이름타입필수설명
    workItemsArrayY대상 배열.
    document, worksheet, datafield다양Y존재 확인용 기준 항목의 키.
    targetobjectY{ document, worksheet, datafield, bind, row, col, type, data, overtake } — 새로 삽입할 항목 정보. datafield는 workItems 내 기존 항목과 일치해야 합니다.
    nextDirectionbooleanNtrue(기본값)이면 찾은 위치 다음에, false이면 그 위치에(앞에) 삽입합니다.
  • 반환값: 없음(workItems를 직접 변경). 두 조건 중 하나라도 찾지 못하면 Warning 로그만 남기고 아무 것도 삽입하지 않습니다.
  • 예시
    syn.$p.addAtWorkItem(workItems, 0, 'Sheet1', 'CompanyName', {
    document: 0, worksheet: 'Sheet1', datafield: 'CompanyName',
    bind: 'cell', row: 1, col: 3, type: 'text'
    }, true);

syn.$p.removeWorkItem(workItems, document, worksheet, datafield)

  • 설명: document/worksheet/datafield가 일치하는 첫 번째 항목을 workItems에서 제거합니다.
  • 매개변수
    이름타입필수설명
    workItemsArrayY대상 배열.
    documentnumberY문서 번호.
    worksheetstringY워크시트 이름.
    datafield`string \Array`Y
  • 반환값: 없음(workItems를 직접 변경). 일치 항목이 없으면 Warning 로그만 남깁니다.
  • 예시
    syn.$p.removeWorkItem(workItems, 0, 'Sheet1', 'ReportDate');

syn.$p.updateWorkItem(workItems, document, worksheet, datafield, updates)

  • 설명: document/worksheet/datafield가 일치하는 항목을 찾아 updates 객체의 속성을 Object.assign으로 병합합니다.
  • 매개변수
    이름타입필수설명
    workItemsArrayY대상 배열.
    document, worksheet, datafield다양Y항목을 찾기 위한 키.
    updatesobjectY덮어쓸 속성들.
  • 반환값: 없음(workItems를 직접 변경). 일치 항목이 없으면 Warning 로그만 남깁니다.
  • 예시
    syn.$p.updateWorkItem(workItems, 0, 'Sheet1', 'ReportDate', { data: '2026-07-07' });

syn.$p.calculateOffsets(totalCount, step)

  • 설명: 0부터 totalCount 미만까지 step 간격으로 증가하는 오프셋 배열을 생성합니다. 다중 페이지/시트를 순회할 때 각 페이지의 시작 인덱스를 구하는 데 사용합니다.
  • 매개변수
    이름타입필수설명
    totalCountnumberY전체 개수.
    stepnumberY증가 간격.
  • 반환값: number[]
  • 예시
    const offsets = syn.$p.calculateOffsets(10, 3); // [0, 3, 6, 9]

syn.$p.bindingWorkItems(workItems, dataSource, documentOffset)

  • 설명: workItems를 깊은 복제한 뒤, dataSource의 각 키를 순회하며 각 항목의 bind 값에 따라 데이터를 채웁니다. bind'cell'(생략 시 기본값)이면 dataItem[item.datafield] 단일 값을, bind'item' 또는 'list'이고 dataItem이 배열이면 item.datafield(배열)의 각 필드를 매핑한 2차원 배열을 채웁니다. bind'cell:key'처럼 콜론으로 특정 dataSource 키를 한정할 수 있습니다. 처리 후 item.bind는 콜론 앞부분만 남도록 정규화됩니다.
  • 매개변수
    이름타입필수설명
    workItemsArrayY원본 작업 항목 배열(변경되지 않음, 복제본을 반환).
    dataSourceobjectY키별로 단일 객체(cell 바인딩) 또는 배열(item/list 바인딩)을 담은 데이터 소스.
    documentOffsetnumberN지정하면(0 이상) 모든 항목의 document 값을 이 값으로 덮어씁니다.
  • 반환값: Array — 데이터가 채워진 새 workItems 배열(복제본).
  • 예시
    const dataSource = {
    header: { CompanyName: 'HandStack Inc.', ReportDate: '2026-07-06' },
    details: [{ ProductName: 'Widget A', Qty: 10 }]
    };
    const bound = syn.$p.bindingWorkItems(workItems, dataSource, 1);

syn.$p.transformWorkData(jsonData, keys)

  • 설명: JSON 배열의 각 행 객체를 keys 순서에 맞춘 값 배열로 변환합니다.
  • 매개변수
    이름타입필수설명
    jsonDataArray<object>Y변환할 행 데이터 배열.
    keysstring[]Y값을 추출할 필드 이름 순서.
  • 반환값: Array<Array> — 각 행이 keys 순서의 값 배열로 변환된 2차원 배열.
  • 예시
    const workData = syn.$p.transformWorkData(data, ['DETAIL_CONTENTS', 'RESULTS']);

syn.$p.transformFormData(jsonData, offset, padding, defaultKeys)

  • 설명: JSON 배열을 필드명 + 순번 형태의 평면 객체(폼 컨트롤 자동 바인딩용)로 변환합니다. defaultKeys(문자열 'key1,key2:기본값' 또는 배열)로 항상 포함할 키와 기본값을 지정할 수 있고, 실제 데이터의 키도 자동으로 병합됩니다. padding이 데이터 길이보다 크면 남는 순번은 기본값으로 채웁니다.
  • 매개변수
    이름타입필수설명
    jsonDataArray<object>Y변환할 행 데이터 배열.
    offsetnumberN순번 시작값. 기본값 1.
    paddingnumberN최소 보장 행 수. 기본값 0(패딩 없음).
    defaultKeys`string \string[]`N
  • 반환값: object — 예: { ProductName1: 'Widget A', Qty1: 10, ProductName2: '', Qty2: '0', ... }
  • 예시
    const formData = syn.$p.transformFormData(data, 1, 5, 'ProductName,Qty:0');

syn.$p.splitDataChunks(dataList, firstLength, chunkSize)

  • 설명: 배열을 첫 페이지 firstLength개, 이후 chunkSize개씩 나눈 배열의 배열로 분할합니다. chunkSize 생략 시 firstLength와 동일하게 사용합니다.
  • 매개변수
    이름타입필수설명
    dataListArrayY분할할 원본 배열.
    firstLengthnumberY첫 청크(페이지)의 길이.
    chunkSizenumberN이후 청크의 길이. 생략 시 firstLength.
  • 반환값: Array<Array> — 분할된 청크 배열.
  • 예시
    const chunkDatas = syn.$p.splitDataChunks(dataList, 2, 3);