🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Google Apps Script

Google Apps ScriptはGoogleの製品と第三者のサービスでタスクを自動化するためのJavaScriptのクラウドのスクリプト言語です。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

2回答

1692閲覧

【GAS】勤怠管理システムを作成する上で、spreadsheet上で、出勤と退勤時間が同じ行に反映されない問題を解決したい。

YousukeTanaka

総合スコア79

Google Apps Script

Google Apps ScriptはGoogleの製品と第三者のサービスでタスクを自動化するためのJavaScriptのクラウドのスクリプト言語です。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

0クリップ

投稿2021/01/07 12:43

編集2021/01/09 07:36

やりたいこと

勤怠管理システムをgasで作成しています。htmlで「出勤」と「退勤」ボタンを用意し、それぞれをクリックすれば、自動的にspreadsheetにその日付とスタッフID,出勤時間、退勤時間が記録される仕組みです。

問題点

出勤ボタンをクリックすると、特定の行に、値は入りますが、出勤と退勤で行が異なる問題に直面しています。
これを修正し、出勤ボタンを押した時には、
0. 本日の日付
0. スタッフのID
0. 出勤時間

退勤ボタンを押した時には、
0. 退勤時間

が同じ行で表示されるようにしたいと考えています。
イメージ説明

コード

html

1<!DOCTYPE html> 2<html> 3 <head> 4 <base target="_top"> 5 <meta charset="UTF-8"> 6 <meta viewport="width=device-width, initial-scale=1"> 7 <meta http-equiv="X-UA-Compatible" content="IE=edge"> 8 <?!=HtmlService.createHtmlOutputFromFile('css').getContent(); ?> 9 </head> 10 <body> 11 <div class="main"> 12 <div class="container"> 13 <div class="row"> 14 <div class="col-md-8 col-md-offset-2"> 15 <div class="row"> 16 <div class="col-md-6"> 17 <canvas width="300" height="260"> 18 Canvas not supported 19 </canvas> 20 <h1 id="time"></h1> 21 </div> 22 <div class="col-md-6"> 23 <form action="https://script.google.com/macros/s/AKfycbxPBqLtX3253ejqzTihglqYt8SifoZK9CmZwXPePj_niFIhnD9W/exec" method="post"> 24 <label for="staffId" class="form-label">Staff ID</label> 25 <input type="text" class="form-control mb-3" id="staffId" name="staffId"> 26 <button type="submit" id="attend-btn" class="btn btn-primary mb-3 btn-lg" name="attend" value="出勤時間" onclick="attendTime()">出勤</button> 27 <button type="submit" id="leave-btn" class="btn btn-primary mb-3 btn-lg" name="leave" value="退勤時間" onclick="leaveTime()">退勤</button> 28 </form> 29 </div> 30 </div> 31 </div> 32 </div> 33 </div> 34 </div> 35 <?!= HtmlService.createHtmlOutputFromFile("js").getContent(); ?> 36 </body> 37</html>

js

1<script> 2 google.script.run.withSuccessHandler.attendTime(); 3 google.script.run.withSuccessHandler.leaveTime(); 4</script>

gas

1//doGetでindex.htmlを表示する 2function doGet(){ 3 const htmlOutput = HtmlService.createTemplateFromFile("index").evaluate(); 4 return htmlOutput; 5} 6 7 8//doGetでindex.htmlに入力された値を取得してスプシへ移行 9function doPost(e){ 10 const ss = SpreadsheetApp.openById('@@@@@@@'); 11 // スプレッドシートの中のシート名を指定して変数に格納。 12 const recordSheet = ss.getSheetByName('データ'); 13 14 //結果 15 const date = Utilities.formatDate(new Date(), 'Asia/Tokyo', 'yyyy/MM/dd'); 16 const id = e.parameters.staffId; 17 const array = [date,id,attendTime(),leaveTime()]; 18 recordSheet.appendRow(array); 19 20 //送信後に返されるページ 21 //var resultpage = HtmlService.createTemplateFromFile("result"); 22 //return resultpage.evaluate(); 23 24} 25 26//関数 attendTime() の定義 27function attendTime(){ 28 const attendTime = Utilities.formatDate(new Date(), 'Asia/Tokyo', 'HH:mm'); 29 return attendTime; 30} 31 32//関数 leaveTime の定義 33function leaveTime(){ 34 const leaveTime = Utilities.formatDate(new Date(), 'Asia/Tokyo', 'HH:mm'); 35 return leaveTime; 36}

様々な方にご助言いただき、少しづつ修正しここまで来ており、もう少しなのですがお力をお貸しいただければ幸いです。。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2021/01/07 14:57

私、DOMの操作に詳しくないので、質問したいのですが、 btn.addEventListener というのは、 btnのリスナーを設定するということでしょうか? この場合、 attend-btn において、イベントclickが発火したら、 という意味のコードは、 attend-btn.addEventListener としないといけないと思ったのですが、じっさいどうなのでしょうか?
YousukeTanaka

2021/01/08 00:09

あっ、その通りです。この点は誤りでした。修正します。
kikukiku

2021/01/08 02:36

つまり、google.script.runは使えないのではないかということです。
YousukeTanaka

2021/01/08 02:43

すいません。書き忘れていましたが、htmlはgoogleのscirptエディターから表示されるため、googleサーバー上にあると考えています。ただ、わかりづらくてすいません。修正します。
kikukiku

2021/01/08 02:56

であるならば、下記のようにそのまま実装してみて、 動くものを作ってみてはいかがでしょうか? それから、今作っているものと比較すれば、間違えがわかると思います。 https://tonari-it.com/gas-web-app-google-script-run/
退会済みユーザー

退会済みユーザー

2021/01/08 07:35

すいません、もう一つ質問がございます。 js.html の方でのsetTime関数の引数が一つだったり2つだったりしてますが、 これは何らかの方法で引数の数によって 一個だったら、その引数はleaveTimeなんだよ と指定しているのでしょうか?
YousukeTanaka

2021/01/08 09:21

この辺実は、私も自信がありません。出勤時に、その日の日程と出勤時間、退勤時に退勤時間のみを渡したく、そのように設定した次第です。ちょうど業務が終わりつつありますので、帰宅後また試そうと思っています。
kikukiku

2021/01/08 09:51

引数1つと、引数2つでメソッド名を変えて動作を確認した方が良いですね。
退会済みユーザー

退会済みユーザー

2021/01/08 10:59

お疲れ様です。 解決というわけではないですが、 何点か気になった点を挙げてみます。 まず、index.htmlから。 <form action="https://script.google.com/macros/s/@@@@@@/exec" method="post"> となっていますが、postの場合、 gasのコードに、doPost(e) を作成しないといけないと思いました。 この場合、javascriptのコードもすでに記述しておりますし、 構成を変えずに考え方を変えた方がよいのかなと思いましたので、 postではなく、ボタンを押したら、任意のコードが動くというやり方に変えた方がよいと思いました。 次にjs.htmlの方ですが、 Utilities.formatDate(new Date(), 'Asia/Tokyo', 'yyyy/MM/dd'); というのは、どこで宣言されているのか見えなかったのと、 もしかすると、gasで使っていたコードから引っ張ってきたのかな? と予想して、こちらは違うものに置き換えた方がよいと思いました。 私、ユーティリティの類に全然詳しくないのですが、もうここは思い切って let fuck = new Date(); date = "" + fuck.getFullYear() + "/" + ("0" + String(Number(fuck.getMonth()) + 1)).slice(-2) + "/" + ("0" + fuck.getDate()).slice(-2); みたいな感じを提案してみます。 あと、同じくjs.htmlについてですが、 javascriptの変数名に"-"が使えなかった気がするので、 こちらも"-"を使用しない変数名にした方がよいと思っていますが、 間違っていたらすいません。 js.htmlには、まだ気になる点がございます。 引数の数で任意の動作を行わせるような処理を組み込まなければいけない構想には、 見えなかったので、 google.script.run.withSuccessHandler().setTime("id",date.toString(),attendTime.toString(),""); とか、 google.script.run.withSuccessHandler().setTime("id",date.toString(),"",leaveTime.toString()); という指定の方法が楽だと考えました。 次にgas.gsについてですが、 doGet(e)の最初のsetTime()は、いらないんじゃなかろうかと思いました。 それと、 sheet.getRange(2,1,row - 1).setValue("gal") だと、仮にrowが10だとすると、 A2からA10まで"gal"で埋め尽くされてしまう気がいたします。 ここは、 sheet.appendRow( [ date, id, attendTime, leaveTime]); のようにシンプルな方がやりたいことに近いのではなかろうかと思った次第です。 ながながと書いてしまいました。 ここまで読んでくれてありがとうございました。
YousukeTanaka

2021/01/09 07:15

ありがとうございます。ご指摘を受け、大幅にコードを変更しました。結果、スプレッドシートに時間が反映されました。ただし、一点問題があります。出勤時間の登録を行うと、退勤時間も出勤時間として登録されてしまうため、出勤時間の入力と退勤時間の入力を分けたいのですが、良いアイデアはありますでしょうか?
退会済みユーザー

退会済みユーザー

2021/01/09 07:21 編集

予想でしかないですが、書き込む際の引数に問題があるとかですかね? もしお時間いただけるのであれば、 書き直したコードを投稿してもらってもよいでしょうか?
YousukeTanaka

2021/01/09 07:29 編集

たった今、投稿いたしました。質問内容、コードを全面的に修正しております。
guest

回答2

0

ベストアンサー

途中経過みてないので、現状のコードと↓について回答します。

ありがとうございます。ご指摘を受け、大幅にコードを変更しました。結果、スプレッドシートに時間が反映されました。ただし、一点問題があります。出勤時間の登録を行うと、退勤時間も出勤時間として登録されてしまうため、出勤時間の入力と退勤時間の入力を分けたいのですが、良いアイデアはありますでしょうか?

  • パラメータのとりかた

が、根本的に間違っています。

const id = e.parameters.staffId;

e.parameter.staffId か e.parameters.staffId[0] です。

  • パラメータを判定していない。

post 時にどちらのボタンを押したのか、全く考慮がなく、常に↓のように"現在時間から取得できる時分"を 2 回書き込みしたのでは、現時点の時刻が二重に記入されるのは自明です。

const array = [date,id,attendTime(),leaveTime()];

javascript

1let array = []; 2if(e.parameter.attend) { 3 array = [date,id,attendTime()]; 4} else { 5 array = [date,id,"",attendTime()]; // 全く同じ処理をする attendTime と leaveTime は無意味です。この関数は getHoursAndMinutesAsString とかいう名前が適切です。 6}

このようにしてはじめて別の行に退勤が記録できるという、望んだ形態ではないが一歩進んだかたち、が実現できます。

投稿2021/01/10 21:08

papinianus

総合スコア12705

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

確認してみました。
私からの、提案を挙げてみます。

現在、時間を取得していく流れとしては、

  1. html上で表示したフォームからpostメソッドで、gasを呼び出す。
  2. doPostの動きとして、attendTime(),leaveTime()を処理して、その結果をシートに書き込む。

という流れになっています。
その際、

const array = [date,id,attendTime(),leaveTime()]; recordSheet.appendRow(array);

の部分で、時間を取得して、
出勤時間と思われるセルと退勤時間と思われるセルに、
その時の時間を書きこんでいるように見えます。

postされた値をdoPost関数で判別して、処理を振り分ければよいと思われます。

例えばこんなのどうでしょうか?

let bottunId = /*送信されたパラメータのIdを取得、出勤が押されたのか、退勤が押されたのか?*/; let array; switch(bottunId){ case "attend-btn": /*出勤時間が押された時の処理*/ array = [date,id,attendTime(),""]; break; case "leave-btn": /*退勤ボタンが押された時の処理*/ array = [date,id,"",leaveTime()]; break; }

caseで指定される文字列は、
htmlのフォーム中のbutton タグで指定した文字列になります。

papinianus様もおっしゃっておりますが、
attendTime()
leaveTime()
の中身は全く同じなので、二つ用意する必要は今のところないと思われます。
関数の名前を変えて自分の感覚に近い物にすり合わせて、
後のメンテが楽な形をとってた方がよいと思われます。
例えば、getTime()という名前の関数にしてしまうなどです。

なお、
javascript.htmlの方で、
google.script.run.withSuccessHandler.attendTime();
google.script.run.withSuccessHandler.leaveTime();
という形でgas側の関数を呼び出しておりますが、
こちらのコード呼び出しは時間を取得したとして、
その値を使って何かをしているわけではないので、
削除してかまわないと思います。

簡潔明瞭な提案とはいいがたいですが、
これをもとに一考いただければ幸いです。

投稿2021/01/12 00:08

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2021/01/12 04:09

そもそもの質問である、 【GAS】勤怠管理システムを作成する上で、 spreadsheet上で、出勤と退勤時間が同じ行に反映されない問題を解決したい。 に応えていないことに気づきました。 そうなると、上記提案は何の答えにもなっていないので、 改めて返事をしたいと思います。 ざっくり答えちゃうと、 スプレッドシートのデータを取得して、 該当するセルを書き直す、 という感じでよいとも思われます。 おそらく、それが出来ていないための質問だと思いますので、 どのようにすればよいのかまとめて報告できればと思っております。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問