Google スプレッドシート＆Google フォーム＆GASだけでサーバーレスなリモート状況報告システム (その2)


この投稿は、
[Google スプレッドシート＆Google フォーム＆GASだけでサーバーレスなリモート状況報告システム](https://qiita.com/rihok/items/ee1e4ba8eb88f2025585)
の続きで、詳細を記載していきます。


## 1. GASのライブラリ化

下準備として、共通して使用する関数はライブラリ化しておいた方がよい場合があります。
ライブラリ化するもの、ライブラリ化を検討した方がよいものは以下の2つです。

1. 共通して使用する関数
主にスプレッドシートに関する関数を自分で使いやすくしたものや、メール送信やslackへの投稿を行う関数など、複数のファイルで何度も同じ処理を書かなくていいようにライブラリ化しています。
（なお、これらは他のGASでも使っているもので、今回特に用意したわけではなく元から使用しているものです）


2. 各種の変数
読み込むスプレッドシートのIDやシート名などは各GASファイルに書いていくとメンテナンス性が下がるため、変数としてライブラリ化した方がよいと思います。
ただしライブラリ化すると公開状態となるので、セキュリティ面で慎重に実装する必要があります。



##  2. 全員の状況を一覧表示する

GASで全員の状況を一覧表示するwebページを作ります。

GASでは、サーバーを必要とせずにwebページを公開することができます。
GASスクリプト内でhtmlファイルを作成し、doGet関数でGETアクセスを受け取ったら表示するようにセットします。

これらのやり方は、以下を参考にさせていただきました。
[Google Apps Script でHTMLファイルを作って表示。](https://qiita.com/taromorimotohf/items/5e52cb9062600e8ccac3)

### Vue.jsを使う
Vue.jsを使用するため、htmlのヘッダに以下を追記しておきます。
`<script src="https://unpkg.com/vue"></script>`

なお今回はunpkgを使用していますが、どのVueを使用するかは以下のVue.js公式ドキュメントで確認してください。
[Vue.js インストール `<script>` 直接組み込み](https://jp.vuejs.org/v2/guide/installation.html#lt-script-gt-%E7%9B%B4%E6%8E%A5%E7%B5%84%E3%81%BF%E8%BE%BC%E3%81%BF)

### JSコード

```<script>
var vm = new Vue({
  el: "#app",
  data: {
    items: [], // 取得したデータを格納する
  },
  methods: {
    // loadData内のgetSheetData()が成功した場合に呼ばれる関数
    initData: function(returnData) {
      console.log("データが取得できた");
      if(returnData == null) {
        console.log("データが取得できなかった");
        return;
      }
      this.items = returnData;
    },
    // created時に呼ばれる関数
    loadData: function() {
      google.script.run
      .withSuccessHandler(this.initData)
      .withFailureHandler(function(arg) {
        alert("データの取得に失敗しました");
      }).getSheetData();
    },
  },
  created: function() {
    this.loadData();
  }
});
</script>
```


このコードは、Vue.jsを使用して社員の出勤状況を読み出すコードです。

具体的にはgetSheetData()でスプレッドシートから社員の出勤退勤状況を読み出します。
ただしJSからスプレッドシートに直接アクセスすることはできないので、この関数はJSファイルの中ではなく、GASのコード内に書きます。これがgetSheetData関数です。

この関数にJSからアクセスするために [google.script.run(リファレンス)](https://developers.google.com/apps-script/guides/html/reference/run) を使用します。
google.script.runから実行するとGAS側のgetSheetData()が実行され結果を返すので、JSはその結果を受けて、成功だったらwithSuccessHandlerの引数で指定された関数を実行し、失敗だったらwithFailureHandlerの引数で指定された関数を実行します。
上のコードでは、成功時はinitData()関数を実行し、失敗時はアラートを出します。

まとめると

1. google.script.runでgetSheetData()を実行
2. getSheetData()内で処理を行う
3. getSheetData()が結果をreturn
4. google.script.runに戻ってきて、getSheetData()の実行結果を取得
5. 成功だったらwithSuccessHandlerの引数 initData() を実行
6. 失敗だったらwithFailureHandlerの引数 アラート表示 を実行

となります。

### html
出勤退勤状況を読み出したらそれをhtmlに表示するためのコードを追加します。
Vue.jsを使用しているので、bodyに`<div id="app">`を追加して、その中に以下のコードを追加します。

```
<div class="items">
    <div class="item" v-for="item in items" v-bind:class=item.statusClass> <!-- 状態はdivにclassで指定しておく -->
        <div class="person">
            <div class="info">
                <div class="name">{{ item.name }}</div> <!-- 名前 -->
                <div class="team">{{ item.team }}</div> <!-- 部署 -->
            </div>
            <div class="icon"><img class="icon" v-bind:src=item.icon /></div> <!-- アイコン画像のパス -->
        </div>
        <div class="statuses">
            <div class="status" v-bind:class=item.statusClass><a href="https://docs.google.com/forms/d/e/[入力フォームのファイルID]/viewform" target="_blank">{{ item.status }}</a></div> <!-- 状態表示 兼 入力フォームへのリンクボタン -->
        </div>
    </div>
</div>
```
JSでは取得したデータをitemsに代入しているため、itemsをVue.jsで出力します。
itemには、名前・部署・アイコン・状態などが入っています。次で詳細を説明します。

## 3. 一覧表示に必要な社員情報を管理

Googleスプレッドシートで表を作ります。
普通に、表を作るだけです。

![spreadsheet_sample.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73231/8e85934a-8e5d-189e-0f88-926a2d4f9845.png)

### 編集
変更があればここを直接編集します。
また後述しますが、フォームから状況を入力したら、ここの「状況」欄にフォームで選択した状況が自動的に入力されます。

### 読み込み
JSは、getSheetData()が呼ばれたらこのデータを読み込みます。
その結果を以下のようなPersonクラスのオブジェクトに変換します。

```
var Person = function(data) {
  console.log('data:' + data[0]);
  let ITEM_KEYS = [{id:0, name:"personId", displayName:"personId"}, // ID
                   {id:2, name:"name", displayName:"名前"}, // 名前
                   {id:3, name:"team", displayName:"部署ID"}, // 部署ID
                   {id:4, name:"icon", displayName:"アイコン"}, // アイコン
                   {id:5, name:"status", displayName:"状況"}, // 状況
                  ];
  this[ITEM_KEYS[i].name] = data[i];
  }
}
```
このPersonを配列にしてJSに返すと、JS側でこのデータをオブジェクトして使用できるようになります。

※部署に関してはIDで指定していますが、同じスプレッドシート上に対応表を作っておいて、実行時に置換します。


以降の項目については次回に続きます。

[4. 状況を選択して打刻](https://qiita.com/rihok/private/42d8db51c3e8f7c56f46#4-%E7%8A%B6%E6%B3%81%E3%82%92%E9%81%B8%E6%8A%9E%E3%81%97%E3%81%A6%E6%89%93%E5%88%BB)
[5. 連携](https://qiita.com/rihok/private/42d8db51c3e8f7c56f46#5-%E9%80%A3%E6%90%BA)
[6. デバッグ](https://qiita.com/rihok/private/42d8db51c3e8f7c56f46#6-%E3%83%87%E3%83%90%E3%83%83%E3%82%B0)
[7. まとめ](https://qiita.com/rihok/private/42d8db51c3e8f7c56f46#%E3%81%BE%E3%81%A8%E3%82%81)