Show / Hide Table of Contents

設計和實現請假系統的步驟

主要流程

flowchart LR
    A["員工登入綁定"]
    B["員工申請休假"]
    C["主管批准休假"]
    D["通知團隊"]
    A --> B --> C --> D

次要流程

  • 查詢紀錄
  • 取消請假

(本章節將不會探討次要流程的設計)

使用意圖設計申請休假

先創建辭典

leave_type

  • 特休;特休假
  • 病假
  • 事假
  • 其他

另外仍有防疫照顧假、喪假、防疫隔離假、謀職假、婚假、產檢假、產假、安胎假、育嬰留職停薪、陪產假、公傷病假、公假、家庭照顧假、生理假等可自行添加。

1.創建詞槽

詞槽 引用詞典 別名
leave leave_type 請假
reason @ANY 請假原因
leave_from @TIME 請假開始時間
leave_end @TIME 請假結束時間

2.將說法填入

我想請{leave}從{leave_from}到{leave_end}
我想從{leave_from}開始請假
我想請假從{leave_from}到{leave_end}
我想請假
我想請{leave}

3.如果要加上確認

確認要再添加yes以及no的意圖,建立完成後,接續問法如下

您好再向您確認一下以下資訊是否正確。
請假名稱:${#entities.leave.value}
請假開始時間:${%extractTime(#entities.leave_from.norm,'yyyy-MM-dd HH:mm:ss','')}
請假結束時間:${%extractTime(#entities.leave_end.norm,'yyyy-MM-dd HH:mm:ss','')}

如果命中yes意圖則會導向完成。 如果命中no意圖則會直接結束對話。 如果命中其他意圖會進行其他意圖對話。

4.完成

提交主管審核,得透過resource使用API對外交互。

您好,將為您提交請假申請給主管審核。
請假名稱:${#entities.leave.value}
請假開始時間:${%extractTime(#entities.leave_from.norm,'yyyy-MM-dd HH:mm:ss','')}
請假結束時間:${%extractTime(#entities.leave_end.norm,'yyyy-MM-dd HH:mm:ss','')}

如何向對外交互

此範例將由Google Apps Script作為範例。

我們可以先透過Login的方式,定義是用者的權限。 我們可以透過下一章的LINE平台-帳號連結

我們在帳號連結得到的資料是

username password nonce user_id

新增一個欄位叫manager這邊放上主管的user_id

username password nonce user_id manager

直接自己把自己連接的userId填寫到manager即可,在此略過建立主管、主管註冊、主管登入等步驟。

也就是說你可以參考以下填寫。

username password nonce user_id manager
howard 123456 xxxx U1234XXX U1234XXX

我們在上面第四點的完成部分"您好,將為您提交請假申請給主管審核。",所以必須將獲得的資料建立在另一個Spreadsheets,於是我們新增第二個工作表。欄位如下。

id user_id leave leave_from leave_end reason audit

其中audit為true or false,為當前假期是否審核過。

於是在程式碼.gs由此寫下

function searchUser(userId) {
  var id = '{{你的Spreadsheet ID}}';
  var spreadsheet = SpreadsheetApp.openById(id);
  var sheet = spreadsheet.getSheets()[0];
  var data = sheet.getDataRange().getValues();

  for (var i = 1; i < data.length; i++) {
    var storeUserId = data[i][3];
    if (storeUserId === userId) {
      return { success: true, user: data[i] };
    }
  }
  return { sucess: false };
}

function formatTimestamp(timestamp) {
  var date = new Date(timestamp * 1000);
  var year = date.getFullYear();
  var month = ('0' + (date.getMonth() + 1)).slice(-2);
  var day = ('0' + date.getDate()).slice(-2);
  var hours = ('0' + date.getHours()).slice(-2);
  var minutes = ('0' + date.getMinutes()).slice(-2);
  var seconds = ('0' + date.getSeconds()).slice(-2);

  var formattedDate = year + '-' + month + '-' + day + ' ' + hours + ':' + minutes + ':' + seconds;
  return formattedDate;
}

function sendMessageToManager(userId, user, lineToken, leave, leave_from, leave_end, reason, leave_id) {
  const username = user[0];
  const managerId = user[4];
  const endpoint = 'https://api.line.me/v2/bot/message/push';
  var message = {
    to: managerId, messages: [
      {
        type: 'template',
        altText: '員工請假通知',
        template: {
          type: 'buttons',
          text: `員工帳號:${username}
請假:${leave}
請假開始:${formatTimestamp(leave_from)}
請假結束:${formatTimestamp(leave_end)}
請假原因:${reason}`,
          actions: [
            { type: 'postback', label: '核准請假', data: `/allowed_leave "${leave_id}" ` }
          ]
        }
      }
    ]
  };
  var options = {
    method: 'post',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': lineToken
    },
    payload: JSON.stringify(message)
  };
  var response = UrlFetchApp.fetch(endpoint, options);
  Logger.log('LINE push message sent. Response code: ' + response.getResponseCode());
}

function createLeave(userId, leave, leave_from, leave_end, reason, audit) {
  var id = '{{你的Spreadsheet ID}}';
  var spreadsheet = SpreadsheetApp.openById(id);
  var sheet = spreadsheet.getSheets()[1];
  var uniqueID = Utilities.getUuid();
  var rowData = [uniqueID, userId, leave, leave_from, leave_end, reason, audit];
  sheet.appendRow(rowData);
  return { success: true, id: uniqueID };
}

function updateLeaveAudit(leaveId, notify, lineToken) {
  if (leaveId) {
    var id = '{{你的Spreadsheet ID}}';
    var spreadsheet = SpreadsheetApp.openById(id);
    var sheet = spreadsheet.getSheets()[1];
    var data = sheet.getDataRange().getValues();
    for (var i = 1; i < data.length; i++) {
      var storeId = data[i][0];
      if (storeId === leaveId) {
        let audit = data[i][6];
        if (audit === false) {
          var cell = sheet.getRange("G" + (i + 1));
          cell.setValue(true);
          var userId = data[i][1];
          if (notify && lineToken) {
            const leave = data[i][2];
            const leave_from = data[i][3];
            const leave_end = data[i][4];
            const reason = data[i][5];
            const r = searchUser(userId);
            const endpoint = 'https://api.line.me/v2/bot/message/push';
            var message = {
              to: userId, messages: [
                {
                  type: 'text',
                  text: `員工帳號:${r.user[0]} 已審核請假
請假:${leave}
請假開始:${formatTimestamp(leave_from)}
請假結束:${formatTimestamp(leave_end)}
請假原因:${reason}`
                }
              ]
            };
            var options = {
              method: 'post',
              headers: {
                'Content-Type': 'application/json',
                'Authorization': lineToken
              },
              payload: JSON.stringify(message)
            }; var response = UrlFetchApp.fetch(endpoint, options);
            Logger.log('LINE push message sent. Response code: ' + response.getResponseCode());
          }
        } else {
          return { success: false }
        }
        break;
      }
    }
  }
  return { success: true }
}
function doPost(e) {
  var param = JSON.parse(e.postData.contents);
  let action = param.action;
  var result = {};
  if (action === 'createLeave') {
    let userId = param.userId;
    let leave = param.leave;
    let leave_from = param.leave_from;
    let leave_end = param.leave_end;
    let reason = param.reason;
    let notify = param.notify;
    let lineToken = param.lineToken;
    let audit = false;
    result = createLeave(userId, leave, leave_from, leave_end, reason, audit);
    if (userId && notify && lineToken) {
      const r = searchUser(userId);
      if (r.user[4] && notify && lineToken) {
        sendMessageToManager(userId, r.user, lineToken, leave, leave_from, leave_end, reason, result.id);
      }
    }
  }else if (action === 'updateLeave') {
    let id = param.id;
    let notify = param.notify;
    let lineToken = param.lineToken;
    result = updateLeaveAudit(id, notify, lineToken);
  }
  Logger.log(result);
  return ContentService.createTextOutput(JSON.stringify(result))
    .setMimeType(ContentService.MimeType.JSON);
}

分別新增二個action分別是createLeave、updateLeave

  • createLeave:新增請假原因,其中notify跟lineToken是因為在測試領域的時候,不應該通知主管,需整合機器人流程才可執行。lineToken包含"Bearer "
  • updateLeave:將指定id的leave中的audit轉為true

新增好兩個action後,繼續完成領域資源。

領域資源設定

建立變數分別是

名稱 屬性
success bool
notify bool
reason string
leave_end datetime
leave_from datetime
leave string
user_id string
line_token string

建立資源

資源名稱: saveLeave
URL:script.google.com/macros/s/{{生產部屬的ID}}/exec
Method: POST
Content-Type: JSON

參數

鍵 path
user_id userId
leave
leave_from
leave_end
reason
notify
line_token lineToken
{
    "action": "createLeave",
    "userId": "",
    "leave": "",
    "leave_from": "",
    "leave_end": "",
    "reason": "",
    "notify": "notify",
    "lineToken": ""
}

notify是指要不要通知主管。

回傳值

JSON Path 鍵
success success

DMflow 領域完成資源

回到DMflow做流程

1.可以先在config.lineToken 新增line token,以Bearer xxxx(此範例未將Bearer拆開)

2.新增變數

名稱 屬性
success bool
notify bool
user_id string
leave_id string

3.建立資源

資源名稱: updateLeave
URL:script.google.com/macros/s/{{生產部屬的ID}}/exec
Method: POST
Content-Type: JSON

參數

鍵 path
leave_id id
notify
line_token lineToken
{
    "action": "updateLeave",
    "notify": false,
    "lineToken": "",
    "id": ""
}
notify是指要不要通知使用者審核已經過了。

回傳值

JSON Path 鍵
success success

4.領域設定

開啟請假領域並添加傳遞變數分別為

鍵 前綴 值
notify constant true
lineToken config lineToken
userId sys_user userId

5.新增allowed_leave 場景

DMflow allowed_leave場景

ID 3 資源節點

選取updateLeave
參數:
  notify->constant true
  leave_id->conversation._params.0
  line_token->config.lineToken
回傳值:
  success->success

Start->ID 3 條件節點

條件為
  conversation._params.0 已填充
  sys_user.platform = constant @line

ID 6 回覆節點

文本:已審核成功
取消等待用戶回覆

ID 8 回覆節點

文本:該員工已經審核過了
取消等待用戶回覆

ID 3->ID 6 條件節點

條件為
  conversation.success = constant true

ID 3->ID 8 條件節點

條件為
  conversation.success = constant false

並在主節點,隨便放下調用節點,並選取請假領域即可。

6.更新並發布

實際畫面:

使用者要求請假

DMflow 使用者要求請假

審核者畫面

DMflow 審核者畫面

最後若是此範例完畢,記得管理部屬作業將該程序封存,讓程序下線,避免已經綁定信用卡的使用者造成不必要的費用問題。

聯絡資訊

信箱: service@dmflow.chat

DMflow.chat 官網: DMflow.chat (於2024-05-18更改網域至DMflow.chat,此文檔將不再維護請至DMflow.chat文檔查看新版文檔)

  • Edit this page
In this article
Back to top Copyright © DMflow Docs On-premise
We would like to use third party cookies and scripts to improve the functionality of this website.ApprovePrivacy Policy