LoginSignup
11
8

More than 1 year has passed since last update.

kintoneの標準機能だけでエクセル帳票の出力をやってみた

Posted at

ここでいう標準機能とはスタンダードプランのカスタマイズのみを使うということです。

目的

kintoneのレコードとして記録されたデータを帳票としてエクセルで出力したかったので、作ってみました。
帳票のエクセルは多くの人が自作できるので、そのエクセル自体をフォーマットとしてkintoneに保存しといたらどうかなと思ったのがきっかけです。

方法

アプリを2つ作ります。

  1. エクセル帳票出力:エクセルに書き込みたいデータを持っているアプリ
  2. エクセル帳票フォーマット:エクセルのフォーマットを保存しているアプリ

1から2のフォーマットを呼び出して、データを書き込み、ローカルに保存するという流れです。

条件

ブラウザはChromeです。
kintone UI ComponentとExceljsを使用しました。

スクリーンショット 2022-12-22 1.29.26.png

エクセル帳票出力

こんなのです。
kintone UI Componentでボタンをつけました。
このボタンを押すと上記の流れが起こるという仕組みです。
kintone UI Componentについては

スクリーンショット 2022-12-22 0.49.26.png

エクセル帳票フォーマット

こんなのです。
スクリーンショット 2022-12-22 0.54.32.png

seikyu_syo.xlsxは、一応フォーマットなので「御請求書」とだけ書いておきました。
そのエクセルファイルを添付ファイルでkintoneに保存したという訳です。
スクリーンショット 2022-12-22 0.58.02.png

エクセル帳票出力のカスタマイズ

ボタンをおすと
getData
dlFile
writeXlsx
saveLocal
という4つの関数が順番に動くというものです。

index.js
kintone.events.on("app.record.detail.show", function (event) {
  
  // ボタンの作成と配置
  const hmsp = kintone.app.record.getHeaderMenuSpaceElement();
  const btn = new Kuc.Button({
    text: "帳票出力",
    type: "submit",
    className: "options-class",
    id: "options-id",
    visible: true,
    disabled: false,
  });
  hmsp?.appendChild(btn);

  // ボタンを押したとき
  btn.addEventListener("click", async function () {
    new kintone.Promise(function (resolve) {
      // GETリクエストパラメータの設定
      const body = {
        app: 119, // 帳票フォーマットアプリid(それぞれ違うので変えてください)
        query: 'レコード番号 = "1"', // フォーマットを保存しているレコード番号でデータをGET
      };
      resolve(body);
    })
      .then(getData) // 帳票フォーマットアプリからレコード番号1をget
      .then(dlFile) // getしたデータにあるfileKeyをつかって、ファイルダウンロードAPIを実行してレスポンスをもらう
      .then(writeXlsx.bind(null, event)) // excelに書き込む。レコードのデータeventを第1引数として渡す
      .then(saveLocal); // レスポンスをローカルにセーブする(自分のPCにダウンロードされる)
  });
});
index.js
function getData(requestParam) {
  return new kintone.Promise(function (resolve, reject) {
    kintone.api(
      kintone.api.url("/k/v1/records", true),
      "GET",
      requestParam,
      function (resp) {
        resolve(resp); // getしたデータを次のdlFile関数に渡します
      },
      function (err) {
        console.log(err);
      }
    );
  });
}

// getData関数からデータをrespで受け取ります。
function dlFile(resp) {
  return new kintone.Promise(function (resolve, reject) {
    // fileKeyを取り出します
    const filekey = resp.records[0].添付ファイル.value[0].fileKey;
    // fileKeyをurlに設定します。
    const url = kintone.api.urlForGet("/k/v1/file", { fileKey: filekey }, true);
    // ファイルダウンロードAPI を実行します。
    const xhr = new XMLHttpRequest();
    xhr.open("GET", url);
    xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
    xhr.responseType = "blob";

    xhr.onload = function () {
      if (xhr.status === 200) {
        // エクセルのフォーマットがレスポンスとして返却されます。
        console.log(xhr.response);
        resolve(xhr.response); // エクセルのフォーマットを次のwriteXlsx関数にわたす。
      }
    };
    xhr.send();
  });
}

// レコードのデータをeventで、エクセルのフォーマットをrespで受け取る
function writeXlsx(event, resp) {
  return new kintone.Promise(async function (resolve, reject) {
    const record = event.record;
    // Workbookの作成
    const workbook = new ExcelJS.Workbook();
    await workbook.xlsx.load(resp);
    // 最初のシートを取り出す
    const worksheet = workbook.worksheets[0];

    // セルへ記入
    worksheet.getCell("A2").value = record.名前.value;
    worksheet.getCell("B2").value = record.金額.value;

    // UInt8Arrayを生成

    const uint8Array = await workbook.xlsx.writeBuffer();
    resolve(uint8Array); // 次のsaveLocal関数に渡す
  });
}


function saveLocal(uint8Array) {
  return new kintone.Promise(function (resolve, reject) {
    // Blobオブジェクトにファイルを格納
    const blob = new Blob([uint8Array], {
      type: "application/octet-binary",
    });
    const url = window.URL || window.webkitURL;

    // BlobURLの取得
    const blobUrl = url.createObjectURL(blob);

    // リンクを作成し、そこにBlobオブジェクトを設定する
    const alink = document.createElement("a");
    alink.textContent = "ダウンロード";
    alink.download = "seikyuusyo.xlsx";
    alink.href = blobUrl;
    alink.target = "_blank";

    // マウスイベントを設定
    const e = new MouseEvent("click", {
      view: window,
      bubbles: true,
      cancelable: true,
    });

    // aタグのクリックイベントをディスパッチする
    alink.dispatchEvent(e);
  });
}

結果

A2とB2セルに名前と金額フィールドに書かれていたデータが記入されたエクセルファイルがダウンロードフォルダに入りました。
スクリーンショット 2022-12-22 1.25.43.png

最後に

kintoneもjavascriptも初心者ですが
kintoneが好きなので、何かお役に立つことがあればと思って書きました。

少人数でしか使わないので成り立つようなやり方をしているかもしれません。
ご指摘頂けたら有り難いです。

11
8
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
11
8