kintone

kintoneの一覧をカスタマイズして今回と前回の値を比べてみよう!

学校の定期テストが行われる度、塾では結果を回収してデータを入力して保管している。
そのデータを生徒の情報と結び付けて、個人ごとにデータを確認できるようにしている。

しかし、時には個々のデータではなく、全体を見渡したいこともある。
これまでは集計にカスタマイズの手を入れられず、
見たい情報を得るためにCSVでkintoneのデータを吐き出してexcelで整形してから
Garoonに貼り付けるという作業を繰り返していた。

それぞれのシステムの利を活かすと言えば聞こえはいいのだが、
どうにかこれを自動化できないかと考えてしまうのがkintoner。

機能を考える

①校舎を選択
②A(元データ) :年度・学年・学期を選択
③B(比較データ):年度・学年・学期を選択
④表示ボタンを押すとAとBの比較を行い、成績が上がったか下がったかを表示

やりたいことはシンプル。
今回は初の一覧カスタマイズなので
cybozu developer networkの第7回 カスタマイズビューを利用してみよう(外部リンク)
参考にして作成を進めていこう。

アプリデザインの確認

アプリには下記のようなデータが入っている。

フィールドコードは基本一致するような作りになっているが、
英語かっこよくね?の時代があったせいで、科目名はなぜかjapaneseとかになっている笑

データを表示する一覧画面を作成

カスタマイズ一覧の作成

まずはデータを表示するための一覧画面を作成しよう。
アプリ設定の一覧から、カスタマイズにチェックを入れて一覧画面を作成する。

html部分の作成

カスタマイズにチェックを入れると、全て自作になるのである程度のhtmlの知識が必要になる。
しか~し、世はインターネッツでなんでも調べられる時代である。
テーブルを作りたいなら「html テーブル」とか調べればいいので、非常に楽だ。

今回は校舎やデータ選択のためのドロップダウン、そして表示するボタン、
さらにデータを表示する表を作成する。

校舎名:
<div class="kintoneplugin-select-outer">
 <div class="kintoneplugin-select">
<select id="school_house">
<option value="校舎A">校舎A</option>
<option value="校舎B">校舎B</option>
<option value="校舎C">校舎C</option>
</select>
</div></div><br>
元データ:
<div class="kintoneplugin-select-outer">
 <div class="kintoneplugin-select">
<select id="original_year">
<option value="2019">2019</option>
<option value="2018">2018</option>
<option value="2017">2017</option>
</select>
</div></div>
<div class="kintoneplugin-select-outer">
 <div class="kintoneplugin-select">
<select id="original_grade">
<option value="中1">中1</option>
<option value="中2">中2</option>
<option value="中3">中3</option>
</select>
</div></div>
<div class="kintoneplugin-select-outer">
 <div class="kintoneplugin-select">
 <select id="original">
<option value="(1学期中間)">(1学期中間)</option>
<option value="前期中間(1学期期末)">前期中間(1学期期末)</option>
<option value="前期期末(2学期中間)">前期期末(2学期中間)</option>
<option value="後期中間(2学期期末)">後期中間(2学期期末)</option>
<option value="後期期末(学年末)">後期期末(学年末)</option>
</select>
</div></div>
 比較データ:
<div class="kintoneplugin-select-outer">
 <div class="kintoneplugin-select">
<select id="target_year">
<option value="2019">2019</option>
<option value="2018">2018</option>
<option value="2017">2017</option>
</select>
</div></div>
<div class="kintoneplugin-select-outer">
 <div class="kintoneplugin-select">
<select id="target_grade">
<option value="中1">中1</option>
<option value="中2">中2</option>
<option value="中3">中3</option>
</select>
</div></div>
<div class="kintoneplugin-select-outer">
 <div class="kintoneplugin-select">
 <select id="target">
<option value="(1学期中間)">(1学期中間)</option>
<option value="前期中間(1学期期末)">前期中間(1学期期末)</option>
<option value="前期期末(2学期中間)">前期期末(2学期中間)</option>
<option value="後期中間(2学期期末)">後期中間(2学期期末)</option>
<option value="後期期末(学年末)">後期期末(学年末)</option>
</select>
</div></div>
 <input type="button" class="kintoneplugin-button-normal" id="getValue" value="表示">
<div id="testDiff">
<center>
<table id="resultsTable">
  <thead>
    <tr bgcolor="black">
      <th><span class="title">氏名</span></th>
      <th><span class="title">国語</span></th>
      <th><span class="title">数学</span></th>
      <th><span class="title">英語</span></th>
      <th><span class="title">社会</span></th>
      <th><span class="title">理科</span></th>
      <th><span class="title">音楽</span></th>
      <th><span class="title">美術</span></th>
      <th><span class="title">保体</span></th>
      <th><span class="title">技家</span></th>
      <th><span class="title">5科</span></th>
      <th><span class="title">9科</span></th>

    </tr>
  </thead>
  <tbody id="testDiffBody">
 </tbody>
</table>
</div>
</center>

こんな感じ。デザインが不安なのでkintoneと親和性の高いkintoneスタイルシートを利用している。
(cybozu developer network スタイルシートの利用(外部リンク)

JavaScriptでカスタマイズ

一覧画面が出来たら後はコーディングしていくだけ。
仕様を確認しながら作っていこう。

仕様確認

①一覧画面が表示されたタイミングのみ実行できる
②校舎・年度・学年・学期を選択して表示ボタンを押すと
③選択したデータをクエリにして該当するレコードを取得
④二つのデータの比較が行われ、成績が上がったら↑、下がったら↓、同じなら→を点数の横に表示する表を作成する。

ざっとこんな感じ。いつも思うけど仕様がざっくり過ぎて全然ダメなんだよな笑

①一覧画面が表示されたタイミングのみ実行できる

もちろん一覧画面というのはカスタマイズ用とそれ以外で複数存在する可能性が高いので、
特定の一覧画面でしか実行できないようにした方が良い。
先ほどの一覧作成画面に一覧IDが表示されているので、これをメモしておこう。

そしてその一覧じゃなかったらカスタマイズを実行できないようにするので、

kintone.events.on('app.record.index.show', function(event) {
        if (event.viewId !== 5335803) {
            return;
        }

このようにする。return;すればその後の処理は吹っ飛ばされて終了。

②校舎・年度・学年・学期を選択して表示ボタンを押すと

すでにドロップダウンリストやボタンはhtmlの方で実装しているが、
そこで選択された数値を取得しなければならない。
いろいろ方法はあるようだがjqueryを利用するのがらくちん。
一覧の作成画面でそれぞれの要素にidを設定しておけば、
$(‘#school_house’).val()のように書けば値を取得できる。

        document.getElementById("getValue").onclick = function() {
            var school_house = $('#school_house').val();
            var original_year = $('#original_year').val();
            var original = $('#original').val();
            var target_year = $('#target_year').val();
            var target = $('#target').val();
            var original_grade = $('#original_grade').val();
            var target_grade = $('#target_grade').val();

③選択したデータをクエリにして該当するレコードを取得

今回も安心安全のkintoneUtilityを使用する。
JavaScriptの設定でURLにkintoneUtilityを設定するのを忘れぬように。

AのデータとBのデータを両方取得しないといけないので、
どちらかが存在しない場合はエラーを発する。
Aを取得→存在するならBも取得という流れにする。

            //元データ取得
            kintoneUtility.rest.getAllRecordsByQuery({
              app: 420,
              query: '校舎名 = "' + school_house + '" and 年度 = "' + original_year + '" and term in ("' + original + '") and grade in ("' + original_grade + '")',
              isGuest: false
            }).then(function(originals) {
                //取得後データの存在をチェック
                if(originals.records.length === 0) {
                    alert('元データが存在しません。');
                    return;
                    //存在する場合は比較対象を取得
                } else {
                    kintoneUtility.rest.getAllRecordsByQuery({
                      app: 420,
                      query: '校舎名 = "' + school_house + '" and 年度 = "' + target_year + '" and term in ("' + target + '") and grade in ("' + target_grade + '")',
                      isGuest: false
                    }).then(function(targets) {
                        if(targets.records.length === 0){
                            alert('比較対象データが存在しません。');
                            return;
                        } else {

データが存在するかはlengthが0でないかをチェックすればいいので簡単だ。

④二つのデータの比較が行われ、成績が上がったら↑、下がったら↓、同じなら→を点数の横に表示する表を作成する。

ここが少し厄介だ。
表示したいのは、

氏名 国語 数学 英語 … 

のような形式だ。
氏名はそのままセットして良いが、科目については
AのデータとBのデータを比較し、A=Bなら→、A<Bなら↓、A>Bなら↑を表示する。

                            //どちらもデータが存在したので処理開始
                                    var myRecordSpace = document.getElementById('testDiffBody');
                                    myRecordSpace.innerText = '';
                                    for (var i = 0; i < originals.records.length; i++) {

                                        var record = originals.records[i];
                                        if(record.japanese.value === "") {
                                        
                                        } else {
                                        for(var ix = 0; ix < targets.records.length; ix++){
                                            var record2 = targets.records[ix];
                                            if(record.生徒コード.value === record2.生徒コード.value) {                                                var row = myRecordSpace.insertRow(myRecordSpace.rows.length);
                                               // var cell1 = row.insertCell(0);
                                                var cell2 = row.insertCell(0);
                                                var cell3 = row.insertCell(1);
                                                var cell4 = row.insertCell(2);
                                                var cell5 = row.insertCell(3);
                                                var cell6 = row.insertCell(4);
                                                var cell7 = row.insertCell(5);
                                                var cell8 = row.insertCell(6);
                                                var cell9 = row.insertCell(7);
                                                var cell10 = row.insertCell(8);
                                                var cell11 = row.insertCell(9);
                                                var cell12 = row.insertCell(10);
                                                var cell13 = row.insertCell(11);
                                               // cell1.innerText = record.生徒コード.value;
                                                cell2.innerText = record.name.value;

ここまでで氏名をセットする処理が完了。

                                                if(parseInt(record.japanese.value) === parseInt(record2.japanese.value)) {
                                                cell3.innerText = record.japanese.value + " →";    
                                                } else if(parseInt(record.japanese.value) < parseInt(record2.japanese.value)){
                                                cell3.innerText = record.japanese.value + " ↓";
                                                cell3.style.backgroundColor = "#ffccff";
                                                } else if(parseInt(record.japanese.value) > parseInt(record2.japanese.value)){
                                                cell3.innerText = record.japanese.value + " ↑";
                                                cell3.style.backgroundColor = "#ccffff";
                                                } else {
                                                cell3.innerText = record.japanese.value;    
                                                }

その先は科目ごとにこういう記述をする。
Aの国語の点数=B国語の点数なら  Aの点数+→ の表示
Aの国語の点数<Bの国語の点数なら Aの点数+↓ の表示
Aの国語の点数>Bの国語の点数なら Aの点数+↑ の表示
どれにも該当しなければ Aの国語の点数を表示

といった形だ。
ここまで出来たらあとは科目分この処理を追加していくだけ。

完成形

実際の動作

個人情報の問題で氏名を隠しているためやや見づらいが、このような形になった。

コード

テーブルをクリップボードにコピーするため、最後にclipboard.jsを使用している。

(function() {
    "use strict";
    kintone.events.on('app.record.index.show', function(event) {
        if (event.viewId !== 5335803) {
            return;
        }
        
        document.getElementById("getValue").onclick = function() {
            var school_house = $('#school_house').val();
            var original_year = $('#original_year').val();
            var original = $('#original').val();
            var target_year = $('#target_year').val();
            var target = $('#target').val();
            var original_grade = $('#original_grade').val();
            var target_grade = $('#target_grade').val();
            //元データ取得
            kintoneUtility.rest.getAllRecordsByQuery({
              app: 420,
              query: '校舎名 = "' + school_house + '" and 年度 = "' + original_year + '" and term in ("' + original + '") and grade in ("' + original_grade + '")',
              isGuest: false
            }).then(function(originals) {
                //取得後データの存在をチェック
                if(originals.records.length === 0) {
                    alert('元データが存在しません。');
                    return;
                    //存在する場合は比較対象を取得
                } else {
                    kintoneUtility.rest.getAllRecordsByQuery({
                      app: 420,
                      query: '校舎名 = "' + school_house + '" and 年度 = "' + target_year + '" and term in ("' + target + '") and grade in ("' + target_grade + '")',
                      isGuest: false
                    }).then(function(targets) {
                        if(targets.records.length === 0){
                            alert('比較対象データが存在しません。');
                            return;
                        } else {
                            //どちらもデータが存在したので処理開始
                                    var myRecordSpace = document.getElementById('testDiffBody');
                                    myRecordSpace.innerText = '';
                                    for (var i = 0; i < originals.records.length; i++) {
                                        var record = originals.records[i];
                                        if(record.japanese.value === "") {
                                        
                                        } else {
                                        for(var ix = 0; ix < targets.records.length; ix++){
                                            var record2 = targets.records[ix];
                                            if(record.生徒コード.value === record2.生徒コード.value) {                                                var row = myRecordSpace.insertRow(myRecordSpace.rows.length);
                                               // var cell1 = row.insertCell(0);
                                                var cell2 = row.insertCell(0);
                                                var cell3 = row.insertCell(1);
                                                var cell4 = row.insertCell(2);
                                                var cell5 = row.insertCell(3);
                                                var cell6 = row.insertCell(4);
                                                var cell7 = row.insertCell(5);
                                                var cell8 = row.insertCell(6);
                                                var cell9 = row.insertCell(7);
                                                var cell10 = row.insertCell(8);
                                                var cell11 = row.insertCell(9);
                                                var cell12 = row.insertCell(10);
                                                var cell13 = row.insertCell(11);
                                               // cell1.innerText = record.生徒コード.value;
                                                cell2.innerText = record.name.value;
                                                if(parseInt(record.japanese.value) === parseInt(record2.japanese.value)) {
                                                cell3.innerText = record.japanese.value + " →";    
                                                } else if(parseInt(record.japanese.value) < parseInt(record2.japanese.value)){
                                                cell3.innerText = record.japanese.value + " ↓";
                                                cell3.style.backgroundColor = "#ffccff";
                                                } else if(parseInt(record.japanese.value) > parseInt(record2.japanese.value)){
                                                cell3.innerText = record.japanese.value + " ↑";
                                                cell3.style.backgroundColor = "#ccffff";
                                                } else {
                                                cell3.innerText = record.japanese.value;    
                                                }
                                                if(parseInt(record.math.value) === parseInt(record2.math.value)) {
                                                cell4.innerText = record.math.value + " →";    
                                                } else if(parseInt(record.math.value) < parseInt(record2.math.value)){
                                                cell4.innerText = record.math.value + " ↓";
                                                cell4.style.backgroundColor = "#ffccff";
                                                } else if(parseInt(record.math.value) > parseInt(record2.math.value)){
                                                cell4.innerText = record.math.value + " ↑";
                                                cell4.style.backgroundColor = "#ccffff";
                                                } else {
                                                cell4.innerText = record.math.value;    
                                                }
                                                if(parseInt(record.english.value) === parseInt(record2.english.value)) {
                                                cell5.innerText = record.english.value + " →";    
                                                } else if(parseInt(record.english.value) < parseInt(record2.english.value)){
                                                cell5.innerText = record.english.value + " ↓";
                                                cell5.style.backgroundColor = "#ffccff";
                                                } else if(parseInt(record.english.value) > parseInt(record2.english.value)){
                                                cell5.innerText = record.english.value + " ↑";
                                                cell5.style.backgroundColor = "#ccffff";
                                                } else {
                                                cell5.innerText = record.english.value;    
                                                }
                                                if(parseInt(record.social.value) === parseInt(record2.social.value)) {
                                                cell6.innerText = record.social.value + " →";    
                                                } else if(parseInt(record.social.value) < parseInt(record2.social.value)){
                                                cell6.innerText = record.social.value + " ↓";
                                                cell6.style.backgroundColor = "#ffccff";
                                                } else if(parseInt(record.social.value) > parseInt(record2.social.value)){
                                                cell6.innerText = record.social.value + " ↑";
                                                cell6.style.backgroundColor = "#ccffff";
                                                } else {
                                                cell6.innerText = record.social.value;    
                                                }
                                                if(parseInt(record.science.value) === parseInt(record2.science.value)) {
                                                cell7.innerText = record.science.value + " →";    
                                                } else if(parseInt(record.science.value) < parseInt(record2.science.value)){
                                                cell7.innerText = record.english.value + " ↓";
                                                cell7.style.backgroundColor = "#ffccff";
                                                } else if(parseInt(record.science.value) > parseInt(record2.science.value)){
                                                cell7.innerText = record.science.value + " ↑";
                                                cell7.style.backgroundColor = "#ccffff";
                                                } else {
                                                cell7.innerText = record.science.value;    
                                                }
                                                if(parseInt(record.music.value) === parseInt(record2.music.value)) {
                                                cell8.innerText = record.music.value + " →";    
                                                } else if(parseInt(record.music.value) < parseInt(record2.music.value)){
                                                cell8.innerText = record.music.value + " ↓";
                                                cell8.style.backgroundColor = "#ffccff";
                                                } else if(parseInt(record.music.value) > parseInt(record2.music.value)){
                                                cell8.innerText = record.music.value + " ↑";
                                                cell8.style.backgroundColor = "#ccffff";
                                                } else {
                                                cell8.innerText = record.music.value;    
                                                }
                                                if(parseInt(record.art.value) === parseInt(record2.art.value)) {
                                                cell9.innerText = record.art.value + " →";    
                                                } else if(parseInt(record.art.value) < parseInt(record2.art.value)){
                                                cell9.innerText = record.art.value + " ↓";
                                                cell9.style.backgroundColor = "#ffccff";
                                                } else if(parseInt(record.art.value) > parseInt(record2.art.value)){
                                                cell9.innerText = record.art.value + " ↑";
                                                cell9.style.backgroundColor = "#ccffff";
                                                } else {
                                                cell9.innerText = record.art.value;    
                                                }
                                                if(parseInt(record.pe.value) === parseInt(record2.pe.value)) {
                                                cell10.innerText = record.pe.value + " →";    
                                                } else if(parseInt(record.pe.value) < parseInt(record2.pe.value)){
                                                cell10.innerText = record.pe.value + " ↓";
                                                cell10.style.backgroundColor = "#ffccff";
                                                } else if(parseInt(record.pe.value) > parseInt(record2.pe.value)){
                                                cell10.innerText = record.pe.value + " ↑";
                                                cell10.style.backgroundColor = "#ccffff";
                                                } else {
                                                cell10.innerText = record.pe.value;    
                                                }
                                                if(parseInt(record.home.value) === parseInt(record2.home.value)) {
                                                cell11.innerText = record.home.value + " →";    
                                                } else if(parseInt(record.home.value) < parseInt(record2.home.value)){
                                                cell11.innerText = record.home.value + " ↓";
                                                cell11.style.backgroundColor = "#ffccff";
                                                } else if(parseInt(record.home.value) > parseInt(record2.home.value)){
                                                cell11.innerText = record.home.value + " ↑";
                                                cell11.style.backgroundColor = "#ccffff";
                                                } else {
                                                cell11.innerText = record.home.value;    
                                                }
                                                if(parseInt(record._5科.value) === parseInt(record2._5科.value)) {
                                                cell12.innerText = record._5科.value + " →";    
                                                } else if(parseInt(record._5科.value) < parseInt(record2._5科.value)){
                                                cell12.innerText = record._5科.value + " ↓";
                                                cell12.style.backgroundColor = "#ffccff";
                                                } else if(parseInt(record._5科.value) > parseInt(record2._5科.value)){
                                                cell12.innerText = record._5科.value + " ↑";
                                                cell12.style.backgroundColor = "#ccffff";
                                                } else {
                                                cell12.innerText = record._5科.value;    
                                                }
                                                if(parseInt(record._9科.value) === parseInt(record2._9科.value)) {
                                                cell13.innerText = record._9科.value + " →";    
                                                } else if(parseInt(record._9科.value) < parseInt(record2._9科.value)){
                                                cell13.innerText = record._9科.value + " ↓";
                                                cell13.style.backgroundColor = "#ffccff";
                                                } else if(parseInt(record._9科.value) > parseInt(record2._9科.value)){
                                                cell13.innerText = record._9科.value + " ↑";
                                                cell13.style.backgroundColor = "#ccffff";
                                                } else {
                                                cell13.innerText = record._9科.value;    
                                                }
                                            }
                                        }
                                        
                                        }
                                    }
                            
                        }
                    }).catch(function(error2) {
                      console.log(error2);
                    });
                }
                                var clipboard = new Clipboard('.btn');
                
                clipboard.on('success', function(e) {
                  console.info('Action:', e.action);
                  console.info('Text:', e.text);
                  console.info('Trigger:', e.trigger);
                
                  e.clearSelection();
                });
                
                clipboard.on('error', function(e) {
                  console.error('Action:', e.action);
                  console.error('Trigger:', e.trigger);
                });

            }).catch(function(error) {
              console.log(error);
            });

            
        };
        
    });
    
})();