7
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?

メンバーの勤務スケジュール&勤務実績一括管理を毎日リマインド!

Last updated at Posted at 2025-01-29

はじめに

こんにちは。普段は愛猫:cat:×2と、
わちゃわちゃ戯れている
社会人12年目のまろみいです。:dizzy:

今回は、普段の業務で何気に不便だと感じていることについて、記事にしてみました。

皆さんの会社でも、こんなことってありませんか?:woman_tone1:

チームメンバーの正確な勤務状況が分からない!

私は、現在総勢約30名の部内メンバーと共に仕事をしています💻
その中の拠点が3カ所あるグループに所属をしているのです:family_mmb:

現状として私の部署は、勤務予定を
エクセル管理表での入力管理と社内の
ホワイトボードで勤務場所を一元化しています。

(図表左下のC、Dのグループに所属しています)
コメント 2025-01-26 161627.png

勤務予定のエクセル管理表、、、、
一元管理が出来て便利!ではあるのですが、googleカレンダーへの入力と二重
入力をしているグループもいるのです。

そしてホワイトボード転記用に月初に
一度出力されてしまうと、エクセルシート
の変更は誰も見ていないという現状があるのです。:zipper_mouth:
はたまた、遠方の人は出力シートに反映ができない。。。

そこで、大変!〇〇さんの予定〇〇に
なっているけど、〇〇さん今日どこだっけ?
発生してしまいます。:fearful:

問題点
・グループによってスケジュールの変更が随時反映されていない。
・勤務状況を二重入力しているグループがいる。
・誰がどこで何をしているのかが詳細(時間単位)には分からないメンバーがいる。
・確認することに時間(手間)が発生している。

タイムリーにその日の状況が分かれば、
誰がどこで何をしているのかが一目瞭然!

お互いのスケジュール管理も出来て、
必要なタイミングで連絡も取りやすいのではないか。
そして、不要な連絡(電話)が減るのではないかと考えたわけです。

そこで、デジタルで勤務計画&勤務実績を
一括管理できないかと思いました。

実現したいイメージ:telescope:

コメント 2025-01-26 162741.png

使用したツールはこちら

-Gmail
-Googleカレンダー
-google Spread Sheet(GAS)

実行すること:①全員がGoogleカレンダーに予定を入力

コメント 2025-01-26 152148.png

②googleカレンダーのスケジュールリストを毎朝リマインド

朝の予定をチームメンバーと自分のリマインドを兼ねてメール配信したい。
内容をChat GPTに聞いてみました。:dancer_tone2:

:information_desk_person:コメント 2025-01-26 153456.png

出来たコードがこちら!
qiita.rb
   function sendDailyScheduleEmails() {
     const spreadsheetId = "スプレッドシートIDをここに"; // スプレッドシートIDを入力
     const sheetName = "シート名をここに"; // シート名を入力
     const timeZone = "Asia/Tokyo";
     const today = new Date();
     const startTime = new Date(today.getFullYear(), today.getMonth(), today.getDate(), 0, 0, 0);
     const endTime = new Date(today.getFullYear(), today.getMonth(), today.getDate(), 23, 59, 59);
     
     // スプレッドシートから対象者リストを取得
     const sheet = SpreadsheetApp.openById(spreadsheetId).getSheetByName(sheetName);
     const data = sheet.getDataRange().getValues();
     const headers = data.shift(); // ヘッダー行を除外
     
     // 各対象者のカレンダー予定を取得してメール送信
     data.forEach(row => {
       const [name, email, calendarId] = row;
       if (name && email && calendarId) {
         const calendar = CalendarApp.getCalendarById(calendarId);
         if (calendar) {
           const events = calendar.getEvents(startTime, endTime);
           let eventDetails = events.map(event => {
             return `・${event.getTitle()} (${formatDate(event.getStartTime(), timeZone)} - ${formatDate(event.getEndTime(), timeZone)})`;
           }).join("\n");

           // メール本文を作成
           const subject = `本日の予定 (${formatDate(today, timeZone)})`;
           const body = `${name}さん、\n\n以下は本日の予定です:\n\n${eventDetails || "本日の予定はありません。"}\n\nよろしくお願いいたします。`;

           // メール送信
           GmailApp.sendEmail(email, subject, body);
         }
       }
     });
   }

   // 日付フォーマット関数
   function formatDate(date, timeZone) {
     return Utilities.formatDate(date, timeZone, "yyyy/MM/dd HH:mm");
   }

   // トリガーを設定 (毎日 8:30 に実行)
   function createTrigger() {
     ScriptApp.newTrigger("sendDailyScheduleEmails")
       .timeBased()
       .atHour(8)
       .nearMinute(30)
       .everyDays(1)
       .create();
   }

:information_desk_person:コメント 2025-01-26 155207.png

出来たコードがこちら!
qiita.rb
function sendDailyScheduleEmailsToAll() {
 const spreadsheetId = "スプレッドシートIDをここに"; // スプレッドシートIDを入力
 const sheetName = "シート名をここに"; // シート名を入力
 const timeZone = "Asia/Tokyo";
 const today = new Date();
 const startTime = new Date(today.getFullYear(), today.getMonth(), today.getDate(), 0, 0, 0);
 const endTime = new Date(today.getFullYear(), today.getMonth(), today.getDate(), 23, 59, 59);

 // スプレッドシートから対象者リストを取得
 const sheet = SpreadsheetApp.openById(spreadsheetId).getSheetByName(sheetName);
 const data = sheet.getDataRange().getValues();
 const headers = data.shift(); // ヘッダー行を除外

 let allEvents = []; // 全員の予定を格納するリスト

 data.forEach(row => {
   const [name, email, calendarId] = row;
   if (name && calendarId) {
     const calendar = CalendarApp.getCalendarById(calendarId);
     if (calendar) {
       const events = calendar.getEvents(startTime, endTime);
       if (events.length > 0) {
         // 個人の予定をタイトル付きリストで表示
         let eventDetails = `\n【${name}さんの予定】\n` + events.map(event => {
           return `    - ${event.getTitle()} (${formatDate(event.getStartTime(), timeZone)} - ${formatDate(event.getEndTime(), timeZone)})`;
         }).join("\n");
         allEvents.push(eventDetails);
       }
     }
   }
 });

 // メール本文を作成
 const subject = `本日の全員の予定 (${formatDate(today, timeZone)})`;
 const body = allEvents.length > 0
   ? `以下は本日の全員の予定です:\n${allEvents.join("\n")}\n\nよろしくお願いいたします。`
   : `本日は全員の予定がありません。\n\nよろしくお願いいたします。`;

 // 全員にメールを送信
 const recipients = data.map(row => row[1]).filter(email => email); // メールアドレスのリストを作成
 if (recipients.length > 0) {
   GmailApp.sendEmail(recipients.join(","), subject, body);
 }
}

// 日付フォーマット関数
function formatDate(date, timeZone) {
 return Utilities.formatDate(date, timeZone, "yyyy/MM/dd HH:mm");
}

// トリガーを設定 (毎日 8:30 に実行)
function createTrigger() {
 ScriptApp.newTrigger("sendDailyScheduleEmailsToAll")
   .timeBased()
   .atHour(8)
   .nearMinute(30)
   .everyDays(1)
   .create();
}

そして、受信時のイメージを聞いてみるとこのように返事がありました!
コメント 2025-01-30 081604.png

ここで発生した問題点
・日時の表記をシンプルに分かりやすくしたい
・もし1人の予定が多い場合は、5件以内にしたい
・場所(会議室)も記載したい

上記3点を再度、chat GPTに聞いてコードを作成してもらいました!:writing_hand:

完成したコードがこちら!!!
qiita.rb
   function sendDailyScheduleEmailsToAll() {
     const spreadsheetId = "1zTHZS7AbCPHFrwzAsR9beqp-bl1BSNsU7zhJB3tJeJs"; // スプレッドシートID
     const sheetName = "対象者一覧"; // シート名
     const timeZone = "Asia/Tokyo";
     const maxEventsPerPerson = 5; // 各メンバーの最大表示件数
     const today = new Date();
     const startTime = new Date(today.getFullYear(), today.getMonth(), today.getDate(), 0, 0, 0);
     const endTime = new Date(today.getFullYear(), today.getMonth(), today.getDate(), 23, 59, 59);

     // スプレッドシートから対象者リストを取得
     const sheet = SpreadsheetApp.openById(spreadsheetId).getSheetByName(sheetName);
     if (!sheet) {
       Logger.log(`エラー: シート「${sheetName}」が見つかりません。`);
       return; // シートが見つからない場合は処理を中止
     }

     const data = sheet.getDataRange().getValues();
     const headers = data.shift(); // ヘッダー行を除外

     let allEvents = []; // 全員の予定を格納するリスト

     data.forEach(row => {
       const [name, email, calendarId] = row;
       if (name && calendarId) {
         const calendar = CalendarApp.getCalendarById(calendarId);
         if (calendar) {
           const events = calendar.getEvents(startTime, endTime);
           if (events.length > 0) {
             // イベントを最大表示件数に制限
             const limitedEvents = events.slice(0, maxEventsPerPerson);
             const remainingEvents = events.length - limitedEvents.length;

             let eventDetails = `\n【${name}さんの予定】\n` + limitedEvents.map(event => {
               const start = formatTime(event.getStartTime(), timeZone);
               const end = formatTime(event.getEndTime(), timeZone);
               const timeText = event.isAllDayEvent() ? "終日" : `${start}-${end}`;
               const location = event.getLocation(); // 場所を取得
               const locationText = location ? ` (場所: ${location})` : ""; // 場所が設定されている場合のみ表示
               return `    - ${event.getTitle()} (${timeText})${locationText}`;
             }).join("\n");

             // 他の予定がある場合に簡略化メッセージを追加
             if (remainingEvents > 0) {
               eventDetails += `\n    他 ${remainingEvents} 件の予定があります。`;
             }

             allEvents.push(eventDetails);
           }
         }
       }
     });

     // メール本文を作成
     const subject = `〇〇部 主要メンバー本日の予定一覧 (${formatDate(today, timeZone)})`;
     const body = allEvents.length > 0
       ? `以下は本日の予定です:\n${allEvents.join("\n")}\n\nよろしくお願いいたします。`
       : `本日はメンバーの予定がありません。\n\nよろしくお願いいたします。`;

     // 全員にメールを送信
     const recipients = data.map(row => row[1]).filter(email => email); // メールアドレスのリストを作成
     if (recipients.length > 0) {
       GmailApp.sendEmail(recipients.join(","), subject, body);
     }
   }

   // 時間フォーマット関数 (短い時刻形式)
   function formatTime(date, timeZone) {
     return Utilities.formatDate(date, timeZone, "HH:mm");
   }

   // 日付フォーマット関数
   function formatDate(date, timeZone) {
     return Utilities.formatDate(date, timeZone, "yyyy/MM/dd");
   }

   // トリガーを設定 (毎日 8:30 に実行)
   function createTrigger() {
     ScriptApp.newTrigger("sendDailyScheduleEmailsToAll")
       .timeBased()
       .atHour(8)
       .nearMinute(30)
       .everyDays(1)
       .create();
   }

③トリガーの設定

コメント 2025-01-29 135605.png

GASのコード入力画面を開き、左側の🕔トリガーをクリックし、
上記図表の赤枠の仕様に設定をします! ※ここでは午前8時~9時の設定をしています。

④主要メンバーの予定を毎朝8:30:alarm_clock:に勤務状況のリマインド配信!

コメント 2025-01-26 120621.png

ポイントは、毎朝のリマインド機能をつけることで、
主要メンバーの予定がメール配信され、最新情報を知ることが出来ることです💡

自動メール通知により、予定をチェックする手間が省け、管理がしやすくなります:relaxed:

:point_up: 退勤時は、勤怠入力も忘れずにリマインド!で業務時間管理

私たちの会社は、生産性向上に向けて、勤務時間の管理を徹底しています。
本社は、スーパーフレックスタイム制を導入し、
毎日勤怠状況を各自で上司と共有、把握することが求められています。

退勤時、毎日の勤務状態をリマインド機能で対象者全員にメール!
入力忘れによる記入漏れを防ぎます!

コメント 2025-01-29 111859.png

メールの本文に目的をしっかり伝えることで、
メンバーの皆さんへの意識付けにも繋がります。

初めの一歩👣は現状を認識することが大切です💡
全員が目的を認識し、意識付けができると行動にも繋がりやすくなります:dizzy:

まとめ 今後の改善にむけて

今回苦労したことは、トリガー⏰の設定です。
毎日同じ時刻に配信することでリマインドセットを試みましたが、
1時間単位の〇時~〇時の設定しか選択ができませんでした。
そこで、GASのコードにトリガーを埋め込んでみたら上手くいくのではないかと思い
Chat GPTに確認しながらコードへの入力を実行しました。

結果的には反映されず、設定時間の1時間のどこかのタイミングでメールが配信される
設定にしかできませんでした。2日~3日色んなパターンで試みましたが解決ができず、
まだ若干もやっとしています。引き続き、試行錯誤を繰り返します。

最終的には、定時設定でのメール配信ができるようになります!:woman_tone1:
また報告させてください:point_up:

そして、上記内容について一部メンバーに話をしたところ、
勤務時間管理のリマインドメールには、目的が書かれていたほうが意識づけになるとの
フィードバックをもらい、早速、記載することにしました!✍

フィードバック&コーチャビリティ(素直に聞き入れること)を大切にします!:thumbsup:

まろみいの紹介・記事についてはこちら!

Xはこちら☞ https://x.com/maromii_y
noteの記事はこちら!☞ https://note.com/yuri_kataoka35/all

Qiitaの 前回1回目の記事はこちら

7
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
7
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?