#はじめに
上手にスケジュールを立てるにはまず自分がどの作業にどれくらい時間を使っているのかを把握するところから!と言うことで、ちまちま作業記録をGoogleカレンダーに付けていたのですが、開始時間を忘れてしまったり、そもそもつけるのを忘れてしまったり…。そして何よりめんどくさい…。
ということで、GASでボタンを押すだけで作業記録が取れるようにタイムカード的なものを作ってみました。
- 必要項目を入力してstartボタンを押下し、作業開始
- もくもくと作業する
- 作業が終了したらstopボタンを押下し、作業終了
するとこんな感じでgoogleカレンダーに登録されます。楽ちん!
#使うもの
使用するのは下記の3つだけです。
- Googleスプレッドシート
- Googleカレンダー
- Google Apps Script(GAS)
#実装
それでは早速実装していきましょう!
##まずは下準備
###1. スプレッドシートを新規作成し、記録をつけたいカレンダーの情報をまとめておく
GASを使って特定のGoogleカレンダーに予定(今回の場合は記録)を登録するためにはカレンダーIDが必要になります。
私は予定によってカレンダーをかなり細かく分けており、記録をつける際もカレンダーを分けたかったので、新しいスプレッドシートを作成して記録をつけたいカレンダーの名前とIDをまとめておきました。
ここで名前に設定したものがカレンダーのプルダウンで表示されます。
ちなみにカレンダーIDはGoogleカレンダーを開いて、使いたいカレンダー横の3点リーダーをクリックして、
設定と共有を開き、
カレンダーの統合から取得できます。
###2. 1.で作成したスプレッドシートからスクリプトエディタを開いて、必要なファイルを作成する
1.で作成したスプレッドシートのメニュー内、拡張機能>Apps Scriptからエディタを開きます。
コード.gsは最初から用意されていますが、それ以外に必要なファイルはファイル横の+ボタンから任意で追加作成します。
下準備はこれで完了です!次は作成したファイルにコードを書いていきます。
##コードを書く
###GAS
スプレッドシートやカレンダーの操作等、Googleのサーバーにアクセスする処理は.gsファイルに記述していきます。
// 公開したWebアプリにアクセスがあった場合に実行
function doGet() {
// 表示させるhtmlを指定
const temp = HtmlService.createTemplateFromFile("index");
// スプレッドシートからカレンダーの情報を取得
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheet = ss.getActiveSheet();
const calData = sheet.getRange(2, 1, sheet.getLastRow()-1, 2).getValues();
temp.calData = calData;
return temp
.evaluate()
.setTitle('タイムカード')
.addMetaTag('viewport', 'width=device-width, initial-scale=1');
}
// カレンダーに記録を登録
function addCal(calId,calTtl,start,end,calDesc){
const calendar = CalendarApp.getCalendarById(calId);
const title = calTtl;
const startTime = new Date(start);
const endTime = new Date(end);
const option = {
description: calDesc
}
calendar.createEvent(title, startTime, endTime, option);
}
doGet(e)
関数は特定のイベントが発生したときに自動で実行されるシンプルトリガーの一種で、ユーザーがWebアプリにアクセスした際に実行されます。
※以下は上記ソースコードからの抜粋です
// スプレッドシートからカレンダーの情報を取得
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheet = ss.getActiveSheet();
const calData = sheet.getRange(2, 1, sheet.getLastRow()-1, 2).getValues();
temp.calData = calData;
この関数内でスプレッドシートからカレンダーの情報を取得し、テンプレートのプロパティに設定しておきます。
こうすることでHTMLに記述した<? ... ?>
のようなスクリプトレットを使用して参照することができます。
スクリプトレットについてはこちらをご参照ください。
###HTML
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<!-- cssを記述したHTMLファイルの読み込み -->
<?!= HtmlService.createHtmlOutputFromFile('reset').getContent(); ?>
<?!= HtmlService.createHtmlOutputFromFile('css').getContent(); ?>
</head>
<body>
<div class="wrap">
<h1 id="heading" class="heading">作業開始する?</h1>
<div id="time" class="time"></div>
<select required id="cal">
<option value="" hidden>カレンダー</option>
<!-- スプレッドシートの情報からカレンダーを追加 -->
<? for(let i = 0; i < calData.length; i++){?>
<option value="<?= calData[i][1] ?>"><?= calData[i][0] ?></option>
<?}?>
</select>
<input type="text" id="ttl" placeholder="タイトル">
<textarea id="desc" placeholder="説明"></textarea>
<div class="btn">
<button type="button" id="startBtn" class="btn__item">start</button>
<button type="button" id="stopBtn" class="btn__item">stop</button>
</div>
</div>
<!-- jsを記述したHTMLファイルの読み込み -->
<?!= HtmlService.createHtmlOutputFromFile('js').getContent(); ?>
</body>
</html>
※以下は上記ソースコードからの抜粋です
<!-- cssを記述したHTMLファイルの読み込み -->
<?!= HtmlService.createHtmlOutputFromFile('reset').getContent(); ?>
<?!= HtmlService.createHtmlOutputFromFile('css').getContent(); ?>
プロジェクト内のcssやjsを記述したHTMLファイルもスクリプトレットを使用して読み込みます。
###Javascript
<script>
const startBtn = document.getElementById('startBtn');
const stopBtn = document.getElementById('stopBtn');
const heading = document.getElementById('heading');
const time = document.getElementById('time');
const cal = document.getElementById('cal');
const ttl = document.getElementById('ttl');
const desc = document.getElementById('desc');
startBtn.disabled = true;
stopBtn.disabled = true;
// 他の作業を開始していない状態でカレンダーの選択とタイトルの入力がされたらスタートボタンのdisabledをfalseに変更
// 説明の入力は任意
document.addEventListener('change', () => {
if(!cal.value || !ttl.value || !stopBtn.disabled) return;
startBtn.disabled = false;
})
// スタートボタンを押下した際の挙動
startBtn.addEventListener('click', () => {
const startTime = new Date().toLocaleString();
time.textContent = startTime;
heading.textContent = '作業開始!';
startBtn.disabled = true;
stopBtn.disabled = false;
});
// ストップボタンを押下した際の挙動
stopBtn.addEventListener('click', () => {
const calId = cal.value;
const calTtl = ttl.value;
const startTime = time.textContent;
const endTime = new Date().toLocaleString();
const calDesc = desc.value;
// コード.gsに定義したaddCal()を呼び出して入力された内容を渡す
google.script.run.addCal(calId,calTtl,startTime,endTime,calDesc);
reset();
});
// 初期化
const reset = () => {
startBtn.disabled = true;
stopBtn.disabled = true;
heading.textContent = '作業開始する?';
time.textContent = '';
cal.selectedIndex = 0;
ttl.value = '';
desc.value = '';
}
</script>
※以下は上記ソースコードからの抜粋です
// ストップボタンを押下した際の挙動
stopBtn.addEventListener('click', () => {
const calId = cal.value;
const calTtl = ttl.value;
const startTime = time.textContent;
const endTime = new Date().toLocaleString();
const calDesc = desc.value;
// コード.gsに定義したaddCal()を呼び出して入力された内容を渡す
google.script.run.addCal(calId,calTtl,startTime,endTime,calDesc);
reset();
});
google.script.run
はクライアント側からサーバー側の関数を呼び出すAPIです。
stopBtn
を押下したらカレンダーに記録をつけたいので、このAPIを使用してコード.gsに定義したaddCal()
を呼び出します。
###css
<style>
input,
select,
textarea {
padding: 5px 10px;
margin-top: 5px;
width: 300px;
}
select:invalid {
color: #757575;
}
::placeholder {
color: #757575;
}
button {
border: none;
}
button:disabled {
opacity: .5;
}
.wrap {
display: flex;
flex-direction: column;
align-items: center;
margin-top: 50px;
}
.ttl {
font-size: 20px;
}
.time {
min-height: 85px;
display: flex;
justify-content: center;
align-items: center;
}
.btn {
display: flex;
margin-top: 20px;
width: 300px;
}
.btn__item {
flex: 1;
padding: 12px;
text-align: center;
font-size: 14px;
color: #fff;
background: #798ebf;
border-radius: 10px;
cursor: pointer;
}
.btn__item + .btn__item {
margin-left: 12px;
}
</style>
reset.htmlはリセットcssなので省略します。私はA Modern CSS Resetを使用しました!
##いざ、デプロイ!
エディタ右上のデプロイ>新しいデプロイを開き、種類はウェブアプリを選択します。
それから、説明文、実行ユーザーとアクセスユーザーを設定してデプロイします。
アクセス許可を求められるので、アカウントを選択して許可してあげます。
赤枠のURLにアクセスして問題なくページが表示されていれば完成です!やったー!
##トラブルシューディング
あれ?登録できたけど時間がずれてるぞ?と思ったら…
タイムゾーンがずれている可能性があるので、一旦スクリプトエディタに戻って歯車マークのプロジェクトの設定を開きます。
「appsscript.json」マニフェスト ファイルをエディタで表示するにチェックを入れてエディタに戻ると、appsscript.jsonが追加されているので開きます。
{
"timeZone": "America/New_York",
"dependencies": {},
"exceptionLogging": "STACKDRIVER",
"runtimeVersion": "V8",
"webapp": {
"executeAs": "USER_DEPLOYING",
"access": "MYSELF"
}
}
timeZone
がAmerica/New_York
になっていますね。日本在住の方は下記のようにAsia/Tokyo
、それ以外の方はお住まいの地域のタイムゾーンに変更してあげましょう。
{
"timeZone": "Asia/Tokyo",
"dependencies": {},
"exceptionLogging": "STACKDRIVER",
"runtimeVersion": "V8",
"webapp": {
"executeAs": "USER_DEPLOYING",
"access": "MYSELF"
}
}
保存して再度デプロイしてみてください!
#おわりに
サーバーサイドの知識がなくても簡単にサクサクっとWebアプリを公開できるし、Googleのアプリも操作できるし、GASって便利なやつですね。
他にもいろいろなことができそうなので、もう少し深堀して勉強してみたいです。
私のスケジューリングが上手になることを祈りつつ…完!
#参考
GASでWebページを表示するdoGet関数のスクリプトについて丁寧に解説
HTML Service: Templated HTML
GASでWebアプリを作ろう① | LogicalCreation
GASでウェブアプリケーション公開方法と実行・アクセスユーザー設定を解説 | AutoWorker〜Google Apps Script(GAS)とSikuliで始める業務改善入門