予算アプリと実績アプリの集計表をカスタマイズビューに表示する

目次

caution
警告

概要

こちらのサンプルは、予算管理アプリと実績管理アプリのデータを使って、予算/実績の差異と達成率を計算し、集計表に表示させるカスタマイズです。

カスタマイズビューという機能を利用し、ひとつの集計表にデータをまとめられるので、複数のアプリを確認したり、手動で集計したりする手間を省くことができます。
カスタマイズの適用方法は、「 適用手順」を参照してください。

完成形

デモ環境

デモ環境で実際に動作を確認できます。

ログイン情報は cybozu developer networkデモ環境で確認してください。

下準備

適用手順

今回のカスタマイズは、「実績管理」アプリが対象です。

カスタマイズビューの設定

アプリストアから「 予算・実績管理 (External link) 」を追加した場合、この設定は不要です。
また、カスタマイズビューを作成するには、kintoneの管理権限が必要です。

  1. 一覧を追加します。

  2. 新規に一覧を作成し「レコード一覧の表示形式」を「カスタマイズ」に設定します。

  3. HTML欄に次のHTMLを入力し保存します。

    1
    2
    
    <table id="view"></table>
    <div id="pager"></div>

カスタマイズビューの設定方法の詳細は、 カスタマイズする場合 | kintoneヘルプ (External link) を参照してください。
また、カスタマイズビューの使い方について、チュートリアル記事「 第7回 カスタマイズビューを利用してみよう」により詳しい解説がありますので、 興味ある方はぜひそちらも確認してください。

JavaScriptファイル/CSSファイルの追加

カスタマイズに必要なライブラリを追加します。

  1. アプリの設定画面から、「JavaScript / CSSによるカスタマイズ」を開きます。
  2. 次の内容を設定します。

    項目 設定する値
    PC用のJavaScriptファイル 次の順で、URLおよびファイルを指定します。
    • https://js.cybozu.com/jquery/2.2.4/jquery.min.js
    • https://js.cybozu.com/jqueryui/1.11.4/jquery-ui.min.js
    • jqGridのファイル
      入手方法は jqGridを参照してください。
      • jQuery.jqGrid.min.js
      • grid.locale-ja.js
    • sample_grid.js
      サンプルプログラムのコードをエディターにコピーし、文字コードを「UTF-8(BOMなし)」、拡張子を「js」にしてファイルを保存します。
      ファイル名は任意です。ここでは「sample_grid.js」としています。
    PC用のCSSファイル 次の順で、URLおよびファイルを指定します。
    • https://js.cybozu.com/jqueryui/1.11.4/themes/redmond/jquery-ui.css
    • ui.jqgrid.css(jqGridのファイルの入手方法は jqGridを参照してください)
    適用対象 カスタマイズを適用するユーザーやグループを選択します。
jqGrid
caution
警告

カスタマイズで利用しているjqGridは、v4.7.1以降MITライセンスではなくなりました。
このカスタマイズでは、 MIT (External link) / GPLv2 (External link) ライセンスのv4.7.0を利用しています( ライセンス表記 (External link) )。
v4.7.1以降を利用する際は GuriddoのHP (External link) で有償ライセンスを購入し、ライセンス条件にしたがって利用してください。
詳細は、 Cybozu CDNライセンス対応ガイド を参照してください。

jqGridは https://github.com/tonytomov/jqGrid/releases/tag/v4.7.0 (External link) の「Source code(zip)」からダウンロードしてください。
ダウンロードしたzipファイルを解凍した後、次のファイルを利用します。

  • jQuery.jqGrid.min.js:js > minifiedディレクトリの下
  • grid.locale-ja.js:js > i18nディレクトリの下
  • ui.jqgrid.css:cssディレクトリの下

サンプルプログラム

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
/*
 * カスタマイズビューのサンプルプログラム
 * Copyright (c) 2016 Cybozu
 *
 * Licensed under the MIT License
 * https://opensource.org/license/mit/
 */
jQuery.noConflict();
(($) => {

  'use strict';
  // 予算管理アプリを全レコード取得
  const fetchRecords = (app_yosan, opt_offset, opt_limit, opt_records) => {
    const offset = opt_offset || 0;
    const limit = opt_limit || 100;
    let allRecords = opt_records || [];
    const params = {app: app_yosan, query: 'order by レコード番号 asc limit ' + limit + ' offset ' + offset};
    return kintone.api(kintone.api.url('/k/v1/records', true), 'GET', params).then((resp) => {
      allRecords = allRecords.concat(resp.records);
      if (resp.records.length === limit) {
        return fetchRecords(app_yosan, offset + limit, limit, allRecords);
      }
      return allRecords;
    });
  };
  // 予実管理データのカスタマイズビュー用データの作成
  const makeYojitsuData = (records, opt_data, opt_i) => {
    let i = opt_i || 0; // レコードのカウント
    const allData = opt_data || []; // 予実の集計結果
    const appId = kintone.app.getId(); // 実績管理アプリID
    let key1, key3, key4, key5;
    key1 = records[i]['拠点'].value;
    key1 = key1.replace(/</g, '&lt;').replace(/>/g, '&gt;');
    const key2 = records[i]['予算'].value;

    const params = {app: appId, query: '拠点 = "' + key1 + '"'};
    return kintone.api(kintone.api.url('/k/v1/records', true), 'GET', params).then((resp) => {
      if (resp.records) {
        key3 = 0;
        const obj = resp.records;
        for (let j = 0; j < obj.length; j++) {
          key3 += parseInt(obj[j]['実績合計'].value, 10);
        }
        key4 = parseInt(key3, 10) - parseInt(key2, 10);
        key5 = parseInt(key3, 10) / parseInt(key2, 10) * 100;
        key5 = key5.toFixed(2);
        key5 += '%';
        allData.push({segment: key1, budget: key2, results: key3, Difference: key4, AchievementRate: key5});
      } else {
        event.error = '実績管理情報が取得できません。';
      }
      i += 1;
      if (records.length !== i) {
        return makeYojitsuData(records, allData, i);
      }
      return allData;
    });
  };
  // 差異のマイナス値を赤色に変更
  const cellDesign = () => {
    $('#view tr td').each((index, elm) => {
      if ($(this).hasClass('Difference_class')) {
        if ($(this).text().indexOf('-') > -1) {
          $(this).css('color', '#ff0000');
        }
      }
    });

  };
  // 予実管理のカスタマイズビューを取得
  const dispYojitsuCustomizeView = (records) => {
    makeYojitsuData(records).then((data) => {
      // 列の設定
      const colModelSettings = [
        {name: 'segment',
          index: 'segment',
          width: 300,
          align: 'center',
          classes: 'segment_class'},
        {name: 'budget',
          index: 'budget',
          width: 200,
          align: 'right',
          classes: 'budget_class',
          formatter: 'currency',
          sorttype: 'float'},
        {name: 'results',
          index: 'results',
          width: 200,
          align: 'right',
          classes: 'results_class',
          formatter: 'currency',
          sorttype: 'float'},
        {name: 'Difference',
          index: 'Difference',
          width: 200,
          align: 'right',
          classes: 'Difference_class',
          formatter: 'currency',
          sorttype: 'float'},
        {name: 'AchievementRate',
          index: 'AchievementRate',
          width: 150,
          align: 'center',
          classes: 'AchievementRate_class',
          sorttype: 'float'}
      ];
      // 列の表示名
      const colNames = ['拠点', '予算', '実績', '差異', '達成率'];
      $('#view').jqGrid({
        data: data,
        datatype: 'local',
        colNames: colNames,
        colModel: colModelSettings,
        rowNum: 10,
        rowList: [1, 10, 20],
        caption: '売上',
        height: 'auto',
        width: 1100,
        pager: 'pager',
        shrinkToFit: true,
        viewrecords: true,
        gridComplete: () => {
          cellDesign();
        }
      });
    });
  };
  // イベント処理
  kintone.events.on(['app.record.index.show'], (event) => {
    const app_yosan = kintone.app.getLookupTargetAppId('拠点'); // 予算管理アプリID
    fetchRecords(app_yosan).then((records) => {
      dispYojitsuCustomizeView(records);
    });
  });

})(jQuery);

注意事項

kintone JavaScript APIは非同期で実行されるため、XMLHttpRequestを使って同期処理しています。

処理中はブラウザーがフリーズする場合があります。

また、XMLHttpRequestは利用できないブラウザーもありますので、ご注意ください。

使用したAPI

  1. イベントハンドラーを登録する
  2. レコード一覧画面を表示した後のイベント
  3. アプリのIDを取得する
  4. ルックアップフィールドの参照先のアプリIDを取得する
  5. kintone REST APIリクエストを送信する
  6. APIのURLを取得する