GASとスプレッドシートでタスク管理表を作る

# これは何

こんにちは、株式会社 Acompany の竹田です。
本記事は[Acompany Advent Calendar 2022](https://qiita.com/advent-calendar/2022/acompany)の19日目の記事となります。
私が使っているタスク管理表のことを書こうと思います。

# タスク管理表の要件

私は記憶力が雑魚すぎるので、基本的に人の話やタスクを覚えておくことができません。
そこでタスク管理ツールが必須なのですが、細かい要件がいくつかあり、それらを満たすものが見つからなかった（あるのかもしれませんが）ので、自分で作ることにしました。

- 追加やステータス変更作業に時間を要しない
- 優先順位がわかりやすい
- ひと目でタスク量、内容が把握できる
- ルーティーンの業務も自動で追加される
- 今後何か追加したい要件が出てきたときにも、柔軟に対応できる

上記の要件を満たすツールとして、スプレッドシートとGASを採用しました。


# スプレッドシートを用意

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/231065/1f208636-5c45-f1cb-11a5-7d6d551dc3c2.png)

記入に時間をかけたくないので、列数は最小限に抑えます。
完了ステータスはマウスでもキーボードでも変更できるように、チェックボックスにしています。

# スクリプト

何をしているのかかいつまんで説明します。
※スクリプトが汚いかもですが、私はエンジニアではないのでご容赦を

```javascript:script.js
const ss = SpreadsheetApp.openById('XXXX'); // スプレッドシートID
const sheetTask = ss.getSheetByName('タスク');

let lastRow = sheetTask.getRange(1, 1).getNextDataCell(SpreadsheetApp.Direction.DOWN).getRow();
let lastColumn = sheetTask.getLastColumn();

let today = new Date();
let todayDate = new Date(today.getFullYear(), today.getMonth(), today.getDate());
let endDate = new Date(today.getFullYear(), today.getMonth()+1, 0);
let weekInt = today.getDay();

let calendarId = "ja.japanese#holiday@group.v.calendar.google.com"; 
let calendar = CalendarApp.getCalendarById(calendarId); 
let Events = calendar.getEventsForDay(today); 


function myTask() {
  // タスクを配列に格納
  let tasks = sheetTask.getRange(2, 1, lastRow - 1, lastColumn).getValues();

  // 日付取得
  let taskNum = [];
  for(i = 0; i < tasks.length; i ++){
    if(tasks[i][0] < todayDate && tasks[i][2] == false){
      taskNum.push(i);
    }
  }

  // 更新
  for(i = 0; i < taskNum.length; i ++){
    sheetTask.getRange(taskNum[i] + 2, 1).setValue(todayDate);
  }

  return addTask();
}

function addTask() {
  let newTasks = [];
  
  // 毎日（土日祝日以外）
  if(0 < weekInt && weekInt < 6){
    if(Events.length == 0){
      newTasks.push(
      [todayDate, '数値確認', false, '']
      );
    }
  }
  
  // 月曜日
  if(today.getDay() == 1){
    newTasks.push(
      [todayDate, 'OKR進捗確認', false, '']
      , [todayDate, '会議準備', false, '']
    );
  }
  
  // 金曜日
  if(today.getDay() == 5){
    newTasks.push([todayDate, 'Acompanyのニュースをチェック', false, 'https://acompany.tech/']);
  }

  // 月初
  if(today.getDate() == 1){
    newTasks.push([todayDate, '勤怠締め', false, '']);
  }

  // 月末
  if(todayDate.getDate() == endDate.getDate()){
    newTasks.push([todayDate, '経費精算', false, '']);
  }  

  if(newTasks.length > 0){
    sheetTask.getRange(lastRow + 1, 1, newTasks.length, 4).setValues(newTasks);
  }

}
```

`myTask`を毎日実行するようトリガー設定します。

https://codeaid.jp/gas-trigger/

# 工夫したところ

## ソートと色

ひと目で次何をしないといけないのかわかるようにしたかったため

- 条件付き書式で色を付ける
    - 期日が今日のものは赤色
    - 完了しているものはグレー
- 新しいフィルタで
    - 期日昇順
    - 完了=falseに絞る

と設定しています。
通常のフィルタだと、ページ更新したらソートがリセットされてしまうため、新しいフィルタを作るのがおすすめです。

https://www.asobou.co.jp/blog/bussiness/spread-custom

https://support.google.com/a/users/answer/9308952?hl=ja#:~:text=Google%20%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%81%A7%E3%80%81%E3%83%95%E3%82%A3%E3%83%AB%E3%82%BF,%E3%82%BB%E3%83%AB%E3%82%92%E3%82%AF%E3%83%AA%E3%83%83%E3%82%AF%E3%81%97%E3%81%BE%E3%81%99%E3%80%82&text=%5B%E6%96%B0%E3%81%97%E3%81%84%E3%83%95%E3%82%A3%E3%83%AB%E3%82%BF%E8%A1%A8%E7%A4%BA%E3%82%92%E4%BD%9C%E6%88%90,%E3%83%87%E3%83%BC%E3%82%BF%E3%82%92%E9%81%B8%E6%8A%9E%E3%81%97%E3%81%BE%E3%81%99%E3%80%82

## 期日が過ぎたら今日の日付に変更

期日に入力する値は「マジの締め切り」と「なんとなくの目安」どちらも入力しています。
別に過去の日付のまま最上部に残る仕様でもいいのですが、それだと不必要に"切羽詰まってる感"があって嫌なので、今日に変更するようにしています。
この部分です。

```javascript
function myTask() {
  // タスクを配列に格納
  let tasks = sheetTask.getRange(2, 1, lastRow - 1, lastColumn).getValues();

  // 日付取得
  let taskNum = [];
  for(i = 0; i < tasks.length; i ++){
    if(tasks[i][0] < todayDate && tasks[i][2] == false){
      taskNum.push(i);
    }
  }

  // 更新
  for(i = 0; i < taskNum.length; i ++){
    sheetTask.getRange(taskNum[i] + 2, 1).setValue(todayDate);
  }
  return addTask();
}
```

## ルーティーンのタスクを自動で追加

みなさんも実績報告やら定例準備やらいろいろあると思います。
「次何するか」となった際に、「スプレッドシートにあるタスクと、頭の中にあるルーティーンのタスクから優先順位を決める」という無駄な思考を削りたかったので、スプレッドシートに全部集約することにしました。

```javascript
function addTask() {
  let newTasks = [];
  
  // 毎日（土日祝日以外）
  if(0 < weekInt && weekInt < 6){
    if(Events.length == 0){
      newTasks.push(
      [todayDate, '数値確認', false, '']
      );
    }
  }
  
  // 月曜日
  if(today.getDay() == 1){
    newTasks.push(
      [todayDate, 'OKR進捗確認', false, '']
      , [todayDate, '会議準備', false, '']
    );
  }
  
  // 金曜日
  if(today.getDay() == 5){
    newTasks.push([todayDate, 'Acompanyのニュースをチェック', false, 'https://acompany.tech/']);
  }

  // 月初
  if(today.getDate() == 1){
    newTasks.push([todayDate, '勤怠締め', false, '']);
  }

  // 月末
  if(todayDate.getDate() == endDate.getDate()){
    newTasks.push([todayDate, '経費精算', false, '']);
  }  

  if(newTasks.length > 0){
    sheetTask.getRange(lastRow + 1, 1, newTasks.length, 4).setValues(newTasks);
  }

}
```
備考欄に作業をするページのURLを貼り付けておくと便利。

毎日のタスクが土日祝日まで登録されると鬱陶しいので、冒頭で平日のみ処理を実行するようにしています。

```javascript
  // 毎日（土日祝日以外）
  if(0 < weekInt && weekInt < 6){
    if(Events.length == 0){
      newTasks.push(
      [todayDate, '数値確認', false, '']
      );
    }
  }
```

# 完成
これでタスクを忘れることはなくなりました。
あとはタスクの処理スピードとクオリティを上げるだけですね！