LoginSignup
38
37

More than 1 year has passed since last update.

フロントエンドだけで見積書・納品書・請求書を一括生成するWebアプリ

Last updated at Posted at 2021-06-04

 2021-06-04 at 14.24.40.png

法人であれ個人事業主であれ、他社との取引においては帳票生成が欠かせません。その度にわざわざ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"
  }
}

技術的知見

ドラッグ&ドロップでファイル読み込み

ダイアログから選択だけでなく、ドラッグ&ドロップでもファイルを読み込めるように実装しました。

 2021-06-04 at 14.31.35.png

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;
  }
}

38
37
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
38
37