작업 요청사항으로 자사 판매건에 대한 견적서를 PDF파일로 만들어주는 기능에 대한 요청이 들어왔다.
일반적으로 JSPDF라는 오픈소스 라이브러리를 사용하는 듯 하다.
github.com/MrRio/jsPDF 에서 라이브러리를 받아서 사용하거나
해당 cdn을 적용
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.3.1/jspdf.umd.min.js"></script>
기본적인 사용방법은 직관적이다.
var doc = new jsPDF("p", "mm", "a4");
doc.line(10, 10, 20, 10); // 선그리기(시작x, 시작y, 종료x, 종료y)
doc.text(15, 40, '안녕하세요'); // 글씨입력(시작x, 시작y, 내용)
doc.addImage('이미지src', 'JPEG', 시작x, 시작y, 넓이, 높이); //이미지 그리기
doc.save('web.pdf'); // 다운로드 실행
기본적으로 한글지원이 되지 않기 때문에 라이브러리 내부에 한글폰트를 셋팅해 줄 필요가 있다.
구글링을 통해 맑은고딕 (ttf 파일) 다운로드
www.giftofspeed.com/base64-encoder/ 사이트에 들어가서 Base64형태로 인코딩 한후 결과값을 복사하여
var myFont = ‘결과값’;
결과값을 변수에 할당 해 놓는다.(생각보다 문자열이 길고 용량이 크기 때문에 따로 빼서 소스파일로 사용하는 것을 권장)
doc.addFileToVFS("MyFont.ttf", myFont);
doc.addFont("MyFont.ttf", "MyFont", "normal"); //내부에 폰트추가
doc.setFont("MyFont"); //폰트 할당
테이블로 문서양식을 만들 경우는 추가 라이브러리가 필요하다.
autotable이라는 라이브러리로 jspdf라이브러리 추가기능으로 사용이 가능하다.
먼저 cdn적용
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf-autotable/3.5.15/jspdf.plugin.autotable.min.js"></script>
doc.autoTable({
theme: 'grid', // 테마
tableWidth : 116, // 넓이
startX: 50, // 시작 X값
startY: 10, // 시작 Y값
margin: { left: 80, top: 10, right: 10 }, //여백
styles: { font: "MyFont", fontStyle: "normal" }, //폰트적용
body: [
[
{ content: "공급자", rowSpan: 5, styles: { halign: "center", valign: "middle" } },
{ content: "사업자번호", styles: { halign: "center" } },
{ content: "XXX-XX-XXXXX", colSpan: 3, styles: { halign: "center" } },
],
[
{ content: "상 호", styles: { halign: "center" } },
{ content: "(주)XXXX테크", styles: { halign: "center" } },
{ content: "대표자", styles: { halign: "center" } },
{ content: "XXX(인)", styles: { halign: "center" } },
],
],
});
본문은 body객체 안에 이차원배열 내 다시 객체로 컬럼 한단위씩 작성한다.
rowSpan, colSpan 값으로 행과 열의 할당범위 지정이 가능하다.
테이블 최상위 Header구분은 따로 없고 첫번째 row 디자인, 폰트 스타일 등을 통해 구현
일반적 사용법:
동적 생성을 위해서
테이블 config 내 모든 속성값을 키값으로 할당해 놓고
테이블 내 같은구조의 row 반복 생성의 경우는 반복문을 통해 객체값 생성 후 배열에 넣고 body값에 할당,
마지막으로 결과 객체를 파라미터로 넣고 실행
doc.autoTable(객체);
//pdf 출력함수
function pdf_print(esti_dt){
const { jsPDF } = window.jspdf;
//pdf 생성
const doc = new jsPDF();
const myFont = m_font;
//font설정 -> 맑은고딕
doc.addFileToVFS("MyFont.ttf", myFont);
doc.addFont("MyFont.ttf", "MyFont", "normal");
doc.setFont("MyFont");
//text 넣기
doc.setFontSize(20);
doc.text(15, 30, '개발견적서');
doc.setFontSize(10);
doc.text(15, 45, '아래와 같이 견적합니다.');
//상단 Table 넣기
doc.autoTable({
theme: 'grid',
tableWidth : 116,
startX: 50,
startY: 10,
margin: { left: 80, top: 10, right: 10 }, //여백
styles: { font: "MyFont", fontStyle: "normal" }, //폰트적용
body: [
[
{ content: "공급자", rowSpan: 5, styles: { halign: "center", valign: "middle" } },
{ content: "사업자번호", styles: { halign: "center" } },
{ content: "XXX-XX-XXXXX", colSpan: 3, styles: { halign: "center" } },
],
[
{ content: "상 호", styles: { halign: "center" } },
{ content: "(주)XXXX", styles: { halign: "center" } },
{ content: "대표자", styles: { halign: "center" } },
{ content: "XXX(인)", styles: { halign: "center" } },
],
[
{ content: "소 재 지", styles: { halign: "center" } },
{ content: "대전 유성구 배울1로 271(탑립동)", colSpan: 3, styles: { halign: "center" } },
],
[
{ content: "업 태", styles: { halign: "center" } },
{ content: "제조,도.소매", styles: { halign: "center" } },
{ content: "종 목", styles: { halign: "center" } },
{ content: "계량계측기 외", styles: { halign: "center" } },
],
[
{ content: "담 당 자", styles: { halign: "center" } },
{ content: "XXX", styles: { halign: "center" } },
{ content: "연 락 처", styles: { halign: "center" } },
{ content: "XXX-XXXX-XXXX", styles: { halign: "center" } },
],
],
});
//********************************************************** 품목 data 하단 Table
var pdf_obj = new Object;
var pdf_arr = new Array;
pdf_obj.theme = 'grid';
pdf_obj.styles = { font: "MyFont", fontStyle: "normal" };
pdf_obj.tableLineColor = '#CEF6F5';
var esti_uid = esti_dt[14];
var esti_data = select_common('gene_esti', 'gees_uid', esti_uid);
var member_data = select_common('stnd_member', 'stme_uid', esti_data[1].gees_memuid);
var item_data = select_common('gene_esti_sub', 'gees_uid', esti_uid);
var esti_header = [
{ content: "거래처명", styles: { halign: "center", valign: "middle" },
{ content: esti_data[1].stac_nm, colSpan: 4, styles: { halign: "center" } },
];
var esti_columns = [
{ content: "품 목 명", styles: { halign: "center", valign: "middle"} },
{ content: "수 량", styles: { halign: "center", valign: "middle"} },
{ content: "단 가", styles: { halign: "center", valign: "middle" } },
{ content: "세 액", styles: { halign: "center", valign: "middle" } },
{ content: "금 액(원)", styles: { halign: "center", valign: "middle" } },
];
pdf_arr.push(esti_header);
pdf_arr.push(esti_columns);
var sum_price = 0;
for(d=1; d < 25; d++){
var sub_obj = new Object;
var sub_arr = new Array;
var geessu_item = '';
var geessu_qty = '';
var geessu_sprice = '';
var geessu_vprice = '';
var geessu_tprice = '';
if(item_data[d]){
sum_price += Number(item_data[d].geessu_tprice);
geessu_item = item_data[d].geessu_item;
geessu_qty = change_float(item_data[d].geessu_qty);
geessu_sprice = change_float(item_data[d].geessu_sprice);
geessu_vprice = change_float(item_data[d].geessu_vprice);
geessu_tprice = change_float(item_data[d].geessu_tprice);
}
var esti_row = [
{ content: geessu_item, styles: { halign: "right", valign: "middle" } },
{ content: geessu_qty, styles: { halign: "right", valign: "middle" } },
{ content: geessu_sprice, styles: { halign: "right", valign: "middle" } },
{ content: geessu_vprice, styles: { halign: "right", valign: "middle" } },
{ content: geessu_tprice, styles: { halign: "right", valign: "middle" } },
];
pdf_arr.push(esti_row);
}
var price_kor = num_to_str(String(sum_price));
var total_columns = [
{ content: "합 계", styles: { halign: "center", valign: "middle" } },
{ content: "일금 "+price_kor+"정 (₩"+change_float(sum_price)+")", colSpan: 4, styles: { halign: "left" } },
];
var etc_columns = [
{ content: "참고사항", styles: { halign: "center", valign: "middle", fillColor: '#CEF6F5' } },
{ content: "견적유효기간 : "+esti_data[1].gees_duedate, colSpan: 4, styles: { halign: "left" } },
];
var final_columns = [
{ content: "담 당 자", styles: { halign: "center", valign: "middle" } },
{ content: member_data[1].stme_name, styles: { halign: "left" } },
{ content: "연 락 처", styles: { halign: "center", valign: "middle" } },
{ content: member_data[1].stme_email, styles: { halign: "left" } },
{ content: "결재방법 : "+esti_data[1].gees_case, styles: { halign: "center", valign: "middle" } },
];
pdf_arr.push(total_columns);
pdf_arr.push(etc_columns);
pdf_arr.push(final_columns);
pdf_obj.body = pdf_arr;
//**********************************************************
doc.autoTable(pdf_obj);
doc.setProperties({
title: '견적서',
});
doc.save("estimate.pdf");
}