新卒一年目がGASで日報自動出力アプリケーションを作るまで（2/2）

## おさらい
<https://qiita.com/nagamine-slg/items/120ed37b40ea1db01646>
の記事で、今日のカレンダーの予定を一覧で出した

## 今回の目的
始業前の予定を保存し、終業時の実績と比較し、まとめて出力する

## 完成形

こんなかんじになります
![スクリーンショット 2017-12-16 14.37.46.png](https://qiita-image-store.s3.amazonaws.com/0/217058/3d2fa63d-6f07-30ca-b7d9-3e4dd929a6e4.png)



## データの保存
さてどうやって保存しようか。DB作るのも面倒だし、Googleアカウント持っているなら誰でも使えるSpreadSheetにしよう

### SpreadSheetを作成する

```JavaScript:main.gs

function createSheet (){
  Sheet = SpreadsheetApp.create("nippo");
}
  
```

かんたん。ついでに<https://kujirahand.com/blog/index.php?GAS%E3%81%A7%E6%96%B0%E8%A6%8F%E3%82%B9%E3%83%97%E3%83%AC%E3%83%83%E3%83%89%E3%82%B7%E3%83%BC%E3%83%88%E3%82%92%E4%BD%9C%E3%82%8B%E3%81%A8%E3%81%8D>を参考にちょいと書き足し

```JavaScript:main.gs

function createSheet (){
  //ユーザーのメールアドレスをキーにシートのIDを格納
  var KEY_NIPPO_SHEET_ID = Session.getActiveUser().getEmail(); 
  var sheet_id = PropertiesService.getScriptProperties().getProperty(KEY_NIPPO_SHEET_ID); 
  
  if (sheet_id == null) {
  // 初めて使うユーザー
  sheet = SpreadsheetApp.create("nippo_sheet");
  sheet_id = sheet.getId();
  PropertiesService.getScriptProperties().setProperty(KEY_NIPPO_SHEET_ID, sheet_id);
  } else {
  // 2回目以降のユーザー
  sheet = SpreadsheetApp.openById(sheet_id);
  }
}

```

これで何枚も同じシートが作成されることはない。さて、データの保存をしよう。

### まずはデータの格納

保存の前に今まで羅列してただけのデータを配列にして格納したい。

```JavaScript:main.gs

// 略

  var event_ary = [] //データ保存のため新規追加
  
  for(var i=0; i < events.length; i++){
    //終日イベントかどうか判別
    if (events[i].isAllDayEvent()) {
    //終日イベントの場合はなにもしない
    } else {
      event_list_str = event_list_str + "イベント名：" + events[i].getTitle() + "<br>";
      event_list_str = event_list_str + "イベントID：" + events[i].getId() + "<br>";
      event_list_str = event_list_str + "開始時間：" + events[i].getStartTime() + "<br>";
      event_list_str = event_list_str + "終了時間：" + events[i].getEndTime() + "<br>";
      event_list_str = "<p>" + event_list_str + "所要時間：" + ((events[i].getEndTime() - events[i].getStartTime())/3600000) + "h</p>";
      event_ary.push([events[i].getTitle(), events[i].getId(), events[i].getStartTime(), events[i].getEndTime(),((events[i].getEndTime() - events[i].getStartTime())/3600000)]) //データ保存のため新規追加
    }
  }
  saveCalData(event_ary)//データ保存のため新規追加

// 略
  
  ```
  
  こんな感じ。あとはとりあえずシートに書き込めばよい。
  
  ```JavaScript:main.gs
  
  
function saveCalData (event_ary,after){
  
  if (after == 1) {
  var sheet_name = "実績";
  } else {
  var sheet_name = "予定";
  }
  
  // createSheetからID引っ張ってくる
  SpreadSheet = SpreadsheetApp.openById(createSheet());
  // シート作る
  var nippo_sheet = SpreadSheet.getSheetByName(sheet_name);
  if (nippo_sheet == null){
    nippo_sheet = sheet.insertSheet(sheet_name);    
  }
  
  if(nippo_sheet.getRange(1,1).getValue() == "") {
    nippo_sheet.clear();
    nippo_sheet.getRange(1,1,event_ary.length,5).setValues(event_ary);
  }
}

```

ひとまず、これで書きこむことはできた。HTML側からsaveCalData()の間にafterフラグを作ってつないだ。

## 予実での表示

これがめんどくさい。前提として、getValueやsetValueで一つずつセルをチェックするとめちゃくちゃ重いので（これをやって前のアプリケーションは失敗した）、可能な限りgetValue・setValueを少なくしたい。ということで、せっかく2つシートを分けたのでそれぞれ1回で2次元配列で格納して扱うこととした。

```JavaScript:main.gs

function calcCal () {
  
  var after = 0
  Logger.log("【予定】\n"+ getSheetData(after)+"\n");
  after = 1
  Logger.log("【予定】\n"+ getSheetData(after)+"\n");
}

function getSheetData (after) {
  
  if (after == 1) {
  var sheet_name = "実績";
  } else {
  var sheet_name = "予定";
  }
  
  SpreadSheet = SpreadsheetApp.openById(getSheetId());
  var nippo_sheet = SpreadSheet.getSheetByName(sheet_name);
  var lastrow = nippo_sheet.getLastRow() ;
  var lastcolumn = nippo_sheet.getLastColumn() ; 
  var data = nippo_sheet.getRange(1,1,lastrow,lastcolumn).getValues();
  return data
}

```

こんなかんじ。ちょいと面倒だけど、IDで対応させて予定と実績を表示させたい。


## 出力

```JavaScript:main.gs

function calcCal () {
  var nippo_txt = ""
  var sum_time = 0
  var after = 0
  var before_data = getSheetData(after);
  after = 1
  var after_data = getSheetData(after);
  for (var i = 0; i < after_data.length; i++) {
   nippo_txt = nippo_txt + "<p>" + after_data[i][0] + "（予定：-- h / 実績：" + after_data[i][4] + "h）</p>"
   sum_time = sum_time + after_data[i][4];
  }
   nippo_txt = nippo_txt + "<p>合計稼働時間：" + sum_time + "h</p>";
 return nippo_txt 
}

```

これで実績は出る。予定と対応させると…


```JavaScript:main.gs

function calcCal () {
  var nippo_txt = ""
  var sum_time = 0
  var after = 0
  var before_data = getSheetData(after);
  after = 1
  var after_data = getSheetData(after);
  for (var i = 0; i < after_data.length; i++) {    
    for (var j = 0; j < before_data.length; j++) {
      var index = before_data[j].indexOf(after_data[i][1]);
      if (index == 1) {
        before_time = before_data[j][4];
      }
    }
    nippo_txt = nippo_txt + "<p>" + after_data[i][0] + "（予定："+ before_time +" h / 実績：" + after_data[i][4] + "h）</p>"
    sum_time = sum_time + after_data[i][4];
  }
  nippo_txt = nippo_txt + "<p>合計稼働時間：" + sum_time + "h</p>";
  return nippo_txt 
}

```
こんなところだろうか。実行するとこんな感じになります。

![スクリーンショット 2017-12-16 14.37.46.png](https://qiita-image-store.s3.amazonaws.com/0/217058/3d2fa63d-6f07-30ca-b7d9-3e4dd929a6e4.png)


## 課題

予実の分析ができなかったり、まだきちんとした日報のフォーマットになっていないのでそこらへんを直したい。

ただ、実際に仕事した時間をカレンダーに記録するだけで予実管理がこうも簡単にできるのは便利なことだと思う。

今後もGASなどを用いて自動化・効率化を進めていきたい。

あと、文法とか細かいことも気にしていきたい（JSちゃんと書いてる人からしたら殴りたくなる書き方満載なはずなので）