프런트 엔드만으로 견적서, 납품서, 청구서를 일괄 생성하는 웹 앱



법인이든 개인 사업주이든, 타사와의 거래에 있어서는 장표 생성이 빠뜨릴 수 없습니다. 그때마다 일부러 Excel을 열어 방안지를 만들고, , , 라고 하는 것은 엔지니어 되는 것 하고 싶지 않아요. 그래서 단일 json 파일에서 견적서, 납품서, 송장을 일괄 생성할 수 있는 툴을 만들어 보기로 했습니다.

데모 사이트



h tps://s ぢ오오미즈타마. 기주 b. 이오 / 쿠오 타오 온 /

리포지토리



htps : // 기주 b. 코 m / s Tsuo Omizutama / 쿠오 타오 온

유의한 것



빌드 불필요한 움직임



바삭바삭하게 만들고 바삭바삭하게 움직이는 것을 목표로 했기 때문에, 프레임워크나 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;
  }
}

좋은 웹페이지 즐겨찾기