法人であれ個人事業主であれ、他社との取引においては帳票生成が欠かせません。その度にわざわざExcelを開いて方眼紙を作って、、、なんてことはエンジニアたるものやりたくないですよね。そこで、単一のjsonファイルから見積書・納品書・請求書を一括生成できるツールを作ってみることにしました。
デモサイト
https://studio-mizutama.github.io/Quotation/
リポジトリ
https://github.com/studio-mizutama/Quotation
心掛けたこと
ビルド不要で動く
サクッと作ってサクッと動かすことを目標にしたため、フレームワークやAltJSは使わずに素のJavaScriptだけで開発しました。
再利用可能
自社の情報をconfig/config.js
にまとめることで、他の人も再利用しやすいアプリになるように作りました。
config/config.js
const company =
{
"name": "<Your company name>",
"zipCode": "",
"address": "",
"tel": "",
"logoPath": "./images/logo.svg",
"sealPath": "./images/seal.svg",
"bank": "**銀行",
"branch": "**支店",
"typeOfAccount": "普通",
"accountNumber": "111-1111111",
"accountHolder": ""
};
export default company;
テキストベースでデータを管理
テキストベース(今回はjsonファイル)でデータを管理することで、git等を使ってバージョン管理がしやすくなります。脱Excelの一番大きなメリットです。
jsonファイルフォーマット
{
"details": [
{
"description": "項目1",
"quantity": 1,
"unit": "式",
"price": 30000
},
{
"description": "項目2",
"quantity": 5,
"unit": "式",
"price": 10000
}
],
"client": {
"name": "株式会社クライアント",
"title": "Webサイト構築"
},
"dateAndNumbers": {
"no": "2021-05-30-01",
"quotationDate": "2021-05-30",
"validUntil": "2021-06-10",
"deliveryDue": "2021-06-30",
"paymentMethod": "月末締め翌月末払い",
"deliveryDate": "2021-06-30",
"invoiceDate": "2021-06-30",
"paymentDue": "2021-07-31"
}
}
技術的知見
ドラッグ&ドロップでファイル読み込み
ダイアログから選択だけでなく、ドラッグ&ドロップでもファイルを読み込めるように実装しました。
index.html
<h1 id="h1">jsonファイルを選択してください。</h1>
<input type="file" id="input-file" accept="application/json">
main.js
/**
* @param {number} 1: 見積書 2:納品書 3:請求書
*/
let type = 1;
/**
* @param {boolean}
*/
let display = false;
const input = document.getElementById("input-file");
input.addEventListener("change", function() {
result = input.files;
main(result,type);
});
document.addEventListener("DOMContentLoaded",() => {
const dropArea = document.getElementById("drop-area");
dropArea.addEventListener("dragover",(e) => {
e.preventDefault();
dropArea.classList.add("drag");
});
dropArea.addEventListener("dragleave",() => {
dropArea.classList.remove("drag");
});
dropArea.addEventListener("drop",(e) => {
e.preventDefault();
dropArea.classList.remove("drag");
result = e.dataTransfer.files;
main(result,type);
});
});
/**
* メイン処理を実行する関数
* @param {FileList} result
* @param {number} type
*/
const main = function(result,type){
display = true;
const reader = new FileReader();
reader.readAsText(result[0]);
reader.addEventListener("load", function() {
const json = JSON.parse(reader.result);
//略
input.style.display = "none";
});
}
印刷と同じ表示でプレビュー
印刷プレビューとほぼ同じ見た目で画面表示できるようにCSSを書きました。
index.html
<div class="sheet" id="drop-area">
<div class="margin-container"></div>
</div>
style.css
@page {
size: A4;
margin: 0;
}
@media print {
body {
width: 210mm;
}
html, body {
height: 100vh;
margin: 0 !important;
padding: 0 !important;
overflow: hidden;
}
}
.sheet {
width: 210mm;
height: 296mm;
page-break-after: auto;
position: relative;
}
.margin-container {
margin: 5mm;
width: 200mm;
position: absolute;
top: 0;
left: 0;
}
@media screen {
body {
background: #eee;
}
.sheet {
background: white;
box-shadow: 0 .5mm 2mm rgba(0,0,0,.3);
margin: auto;
}
}