3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

SLOGANAdvent Calendar 2017

Day 17

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

Last updated at Posted at 2017-12-16

おさらい

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

今回の目的

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

完成形

こんなかんじになります
スクリーンショット 2017-12-16 14.37.46.png

データの保存

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

SpreadSheetを作成する

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を参考にちょいと書き足し

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);
  }
}

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

まずはデータの格納

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

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)//データ保存のため新規追加

// 略
  

こんな感じ。あとはとりあえずシートに書き込めばよい。

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次元配列で格納して扱うこととした。

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で対応させて予定と実績を表示させたい。

出力

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 
}

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

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

課題

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

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

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

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

3
2
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
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?