設計手冊
遇到問題了嗎?不用擔心,答案都在這。
全站搜尋

Javascript 工作引擎

所有表單都可以觸發 Ragic 的伺服器端 JavaScript 工作流程引擎來執行複雜的業務邏輯,如計算成本和發布庫存餘額。基本上,任何 Ragic現有功能無法覆蓋的複雜業務邏輯都可以透過伺服器端程式來實現。 程式引擎基於標準的 Nashorn Java 程式引擎,它包含在 Java 平台中。Nashorn 支援 ECMAScript 5.1,所以最好避免使用 ECMAScript 6 語法。此外,由 Java 處理並傳遞至 JavaScript 的數據(例如陣列)可能會受到一些特定限制,導致無法直接使用像 join、map 等 JavaScript 方法,然而,若在 workflow 中直接定義一個 JavaScript 陣列並將資料存入其中,則可以正常使用這些 JavaScript 方法。同樣地,瀏覽器專屬的 API 例如: setTimeout、setInterval、alert、document......等等,也無法在此使用。

var query = db.getAPIQuery(pathToForm);
var entry = query.getAPIResult();
var values = entry.getFieldValues(fieldId); // 回傳的是一個陣列

var str = values.join(','); //不可用,會出錯

var ary = [];
for(var i = 0; i < values.length; i ++) {
  ary.push(values[i]);
}
var str = ary.join(','); //可用

JavaScript 工作流程的功能

Ragic 的試算表設計介面可以處理大部分資料管理工作,如建立、編輯和查詢記錄。然而,手動資料維護可能會變得有點耗時和繁瑣。這時,Ragic 用戶會開始考慮如何自動化這些過程。 在 Ragic 內部,有一個非常強大的程式引擎,可以撰寫在伺服器端運行的 JavaScript,用來檢索試算表上的資料,進行修改,甚至可以一次點擊建立多個紀錄。典型的使用場景包括更新庫存,根據另一筆紀錄建立新資料(例如從報價建立銷售訂單,從Sales lead建立聯絡人),或者用資料庫資料做資料檢查。 有五種主要方式來運行您的 JavaScript 工作流程:

  1. 動作按鈕
  2. Post-workflow
  3. Pre-workflow
  4. Daily Workflow
  5. Approval Workflow

還有一個 Global Workflow,您可以在其中放置多個工作流程程式共享的常用 JavaScript 函數定義。

相關名詞定義

在workflow中,有幾個專有名詞會常出現,我們將這些名詞定義如下:假如我們表單中的某筆資料,URL為https://www.ragic.com/testAP/testForm/1/3

名詞 定義
APName testAP,使用者的資料庫名稱
Path /testForm,這張表單所在的頁籤,前面的斜線不可省略
SheetIndex 1,這張表單在頁籤內的索引
pathToForm /testForm/1,即為Path跟SheetIndex的組合,通常當作一個參數使用
rootNodeId、recordId

3,這筆資料(也稱做紀錄)的 ID,也可以透過 getNewNodeId(keyFieldId) 或 getOldNodeId(keyFieldId) 來取得

Key field

這張表單的主鍵,keyFieldId 就是主鍵欄位的 ID,可在資料庫欄位定義文件中找到,或是使用 entry.getKeyFieldId() 來取得

Field

欄位即是 Field,fieldId 是欄位的 ID,fieldName 是欄位的名稱,fieldId 可以在資料庫欄位定義文件中找到,或是在設計模式中選取欄位後,進入「欄位設定」=>「基本」,在欄位名稱下方的七碼數字即為 fieldId

Subtable

子表格,可以想像成是一般的表單下面還有一張表單,也有自己的 keyFieldId、fieldId、rootNodeId

subtableId

子表格的 ID,可在資料庫欄位定義文件中找到,可以想像成是子表格的 keyFieldId

subtableRowIndex 子表格資料的索引,通常會用迴圈來指定
subtableFieldId

子表格欄位的 ID,可在資料庫欄位定義文件中找到,可以想像成是子表格的 fieldId

subtableRootNodeId

子表格紀錄的ID,可以透過 getSubtableRootNodeId(subtableId, subtableRowIndex) 來取得,可以想像成是子表格的rootNodeId

顯示訊息

您可以像這樣顯示一個彈出訊息。請注意,訊息僅在回應狀態為 "WARN" 時顯示。預設情況下,回應物件中的訊息將不會顯示,因為通常對最終用戶沒有幫助。要特別注意的是動作按鈕不支援setStatus('CONFIRM')。

response.setStatus('WARN');
response.setMessage(message);

另外因為 workflow 不支援 console 或 alert 等 JavaScript 指令,所以如果您想進行除錯,可以透過 log.setToConsole(true) 與 log.println(message) 來顯示。

var message = "hello ragic";
log.setToConsole(true); //叫出console區塊
log.println(message); //印出hello ragic

動作按鈕

這是運行 JavaScript 工作流程最常見和最清晰的方式,通常是我們的首選推薦。您可以在工作表的sheet scope中撰寫程式,並配置動作按鈕來執行程式,當用戶點擊將顯示在右下方“動作”面板中的按鈕時。要加上 sheet scope 程式,只需右鍵點擊一個工作表,然後選擇JavaScript Workflow

並從頂部下拉選單中選擇sheet scope

然後,您可以轉到表單頁面設計中,加上一個類型為JS Workflow動作按鈕,並引用您撰寫的 JavaScript 函數。

請注意,您可以使用 {id} 作為函數呼叫的參數來傳遞當前記錄的紀錄 ID,例如:

setStatus({id})

當然,我們會在接下來的章節中介紹如何撰寫這些函數。

Post-workflow

Post-workflows 在記錄儲存後立即執行。通過 Post-workflow,可以方便地自動化您希望對剛儲存的紀錄進行的變更,而這些變更是公式無法完成的。或者,您可以對其他相關工作表的紀錄進行修改,例如更新庫存餘額。要加上 Post-workflow,只需右鍵點擊一個工作表,然後選擇JavaScript Workflow

然後從頂部下拉選單中選擇Post-workflow。 一個典型的 Post-workflow 如下所示:

var recordId = param.getNewNodeId(keyFieldId);
var query = db.getAPIQuery(pathToForm);
var record = query.getAPIEntry(recordId);

// 對檢索到的紀錄進行所需操作

請參閱我們的 API 參考 和本文件的其他部分,了解您可以做的事情。還請注意,如果您在列表頁面上修改資料,Post-workflow 將不會執行。

Pre-workflow

Pre-workflows 在記錄儲存之前執行,因此可以用作檢查的一種方式,以檢查輸入的資料是否符合資料庫中的資料。通常,大多數檢查可以通過我們的前端正則表達式檢查,或自由文本欄位的唯一核取方塊來完成。但對於更複雜的後端檢查,有時需要 Pre-workflow。 要加上 Pre-workflow,只需右鍵點擊一個工作表,然後選擇JavaScript Workflow

然後從頂部下拉選單中選擇Pre-workflow。 這裡有一個簡單的例子:假設我們有一個列表,

我們希望確保儲存的價格不是負數。

/**

 * 主鍵欄位: 1000004

 * 欄位名稱欄位 ID
 * - - - - - - - - - - - --------
 * ID : 1000001
 * 價格 : 1000002
 * 名稱 : 1000003
 * 是否可用 : 1000005

 */
function showMsg(str) {
  // 設定狀態為 'INVALID' 或 'ERROR' 以取消儲存。
  response.setStatus('INVALID');
  response.setMessage(str);
}

function ifThePriceIsNegative() {
  // 取得要儲存的價格。
  var newPrice = param.getNewValue(1000002);
  // 將 newPrice 字串轉換為整數。
  if(parseInt(newPrice) < 0) {
    return true;
  }
}

// 如果價格為負數,則不儲存。
if(ifThePriceIsNegative()) {
  showMsg('價格為負數!!');
}

現在嘗試儲存負數價格,我們會得到

值得注意的是,在 Ragic 中撰寫 Pre-workflow 時,不能使用 entry.getFieldValue(因為 Ragic 還沒有儲存)。請嘗試使用 param 來取得舊值和新值。

Daily Workflow

Daily Workflows 每天運行一次。這對於需要每天更新結果的修改非常有用,例如根據當前日期更新公式結果。要加上 Daily Workflow,只需右鍵點擊一個標籤,然後選擇Global Javascript Workflow

然後從頂部下拉選單中選擇Daily Workflow

默認情況下,Daily Workflow 在 UTC 19:00 運行。您可以在公司設定中更改執行時間和時區: 1. 前往帳戶設定

2. 點擊公司設定

3. 選擇公司當地時區Daily Workflow 執行時間並儲存。

如果您的公司設定中沒有公司當地時區Daily Workflow 執行時間,請聯絡我們來為您更新。

Approval Workflow

Approval Workflows 在簽核建立、簽核、拒絕、取消或完成後立即執行。 要加上 Post-workflow,只需右鍵點擊一個工作表,然後選擇JavaScript Workflow

然後從頂部下拉選單中選擇Approval Workflow。 您可以透過以下方法取得記錄 ID:

var recordId = approvalParam.getEntryRootNodeId();

approvalParam 是簽核工作流程範圍內的預定義變數。您可以透過以下方法取得簽核操作:

var action = approvalParam.getApprovalAction();

在取得上述資料後,您可以根據需求進行自訂:

var query = db.getAPIQuery(pathToForm);
var entry = query.getAPIEntry(recordId);
if (action === 'CANCEL') {
  entry.setFieldValue(STATUS_FIELD, "簽核已取消!");
}else if (action === 'FINISH') {
  entry.setFieldValue(STATUS_FIELD, "簽核已完成!");
}else if (action === 'CREATE') {
  entry.setFieldValue(STATUS_FIELD, "簽核已建立!");
}else if (action === 'REJECT') {
  entry.setFieldValue(STATUS_FIELD, "簽核已拒絕!");
}else {
  entry.setFieldValue(STATUS_FIELD, "簽核已批准!");
}
entry.save();

Global Workflow

Global Workflow 是您可以撰寫的 JavaScript 工作流程模組,其他工作流程函數可以引用它。它不會自己執行,但可以在上面列出的任何類型的工作流程中引用。這是一個很好的地方來放置可能需要在多個工作表中重複的程式。要加上 Global Workflow,只需右鍵點擊一個標籤,然後選擇Global Javascript Workflow

取得一筆資料

有兩種不同的方式來取得用戶正在查看的當前記錄(適用於動作按鈕)或用戶剛儲存的紀錄(適用於 Pre-workflow 和 Post-workflow)。

動作按鈕

表單頁面動作按鈕透過配置動作按鈕來呼叫您在 sheet scope 中定義的函數。當您定義動作按鈕呼叫的函數時,您可以傳遞參數 {id},即點擊動作按鈕所在記錄的 ID,來在工作流程中使用。 您可以在動作按鈕工作流程 中看到範例。

Pre-workflow

您可以透過以下方法取得記錄 ID:

var recordId = param.getNewNodeId(keyFieldId);

param 是一個預定義變數,您可以在 Pre-workflow 和 Post-workflow 中使用它。

在取得記錄 ID 之後,這是取得記錄(entry)的方式:

var query = db.getAPIQuery(pathToForm);
var entry = query.getAPIEntry(id);

Post-workflow

對於 Post-workflow,您可以使用與 Pre-workflow 相同的方法。但是,還有一種方便的方法來檢索剛剛儲存的紀錄:

var entry=param.getUpdatedEntry();

如果表單頁面上有文字遮罩欄位,默認情況下您將獲得遮罩值。您可以透過以下方式取得未遮罩的值:

var query = db.getAPIQuery(pathToForm);
query.setUpdateMode();
query.setIgnoreAllMasks(true); // 取消所有遮罩欄位的遮罩。
var entry = query.getAPIEntry(id);

您可以使用 query.addIgnoreMaskDomain(fieldId_of_the_masked_field) 而不是query.setIgnoreAllMasks(true) 來僅取消特定欄位的遮罩。有關如何在以下部分中更新資料的更多介紹,請參閱更新資料

查詢資料

如果您想透過過濾條件取得多筆紀錄: 您可以使用addFilter(fieldId, operator, value) 來加上過濾條件,並使用getAPIResultsFull() 來取得記錄列表。或是您也可以針對同一個欄位做兩次addFilter,這樣就可以做AND過濾。以下是您可以使用的操作符列表:

操作符名稱 操作符值
等於 =
正則表達式 regex
大於或等於 >=
小於或等於 <=
大於 >
小於 <
包含 like

單一條件

使用一次addFilter篩出符合條件的紀錄

var colA = "1000002"; //欄位A
var query = db.getAPIQuery("/workflow-demo/1");
query.addFilter(colA, '=', 'Green');
var results = query.getAPIResultsFull(); // results為所有欄位A為Green的資料
var entry = results.next();
while(entry) {
  // do something
  entry = results.next();
}

複合條件(AND)

使用多次addFilter篩出符合條件的紀錄

var colA = "1000002"; //欄位A
var colB = "1000004"; //欄位B
var query = db.getAPIQuery("/workflow-demo/1");
query.addFilter(colA, '=', 'Green');
query.addFilter(colB, '=', 'Yes');
var results = query.getAPIResultsFull(); // results為所有欄位A為Green且欄位B為Yes的資料
var entry = results.next();
while(entry) {
  // do something
  entry = results.next();
}

複合條件(OR)

使用多次addFilter篩出符合條件的紀錄

var colA = "1000002"; //欄位A
var query = db.getAPIQuery("/workflow-demo/1");
query.addFilter(colA, '=', 'Green');
query.addFilter(colA, '=', 'Red');
var results = query.getAPIResultsFull(); // results為所有欄位A為Green或欄位A為Red的資料
var entry = results.next();
while(entry) {
  // do something
  entry = results.next();
}

範圍查詢

var colA = "1000006"; //欄位A
var query = db.getAPIQuery("/workflow-demo/1");
query.addFilter(colA, '>', '20');
query.addFilter(colA, '<', '40');
var results = query.getAPIResultsFull(); // results為所有欄位A大於20且欄位A小於40的資料
var entry = results.next();
while(entry) {
  // do something
  entry = results.next();
}

請注意,當您透過日期或日期時間進行過濾時,它們需要以下列格式表示:yyyy/MM/ddyyyy/MM/dd HH:mm:ss。 您還可以透過呼叫 setFullTextSearch(String queryTerm) 來使用全文搜尋作為查詢過濾條件,而不是 addFilter()。

更新資料

範例連結

讓我們從一個簡單的範例開始,檢索當前記錄作為物件,使用按鈕更新其值,然後將其儲存回資料庫。以下是範例表單的外觀:

我們希望設計一些按鈕,通過點擊按鈕執行簡單的伺服器端 JavaScript 工作流程來更改我們的狀態欄位值。以下是按鈕後面的程式碼:

/**

 * AP_Name:wfdemo
 * 主鍵欄位: 1000013

 * 名稱 ID
 * - - - - - - - - - - - --------
 * No.: 1000011
 * 狀態: 1000012

 */
function setStatus(recordId, status) {

var STATUS_FIELD = 1000012; // 狀態欄位的欄位ID
var query = db.getAPIQuery("/workflow-demo/2"); // 取得工作表的查詢物件
var entry = query.getAPIEntry(recordId);// 取得當前記錄的物件

// 設定當前記錄的狀態值
if (status) {
  entry.setFieldValue(STATUS_FIELD, status);
}
else { // 用於切換
  var newStatus = entry.getFieldValue(STATUS_FIELD) == 'On' ? 'Off' : 'On'; // 取得欄位的當前值
  entry.setFieldValue(STATUS_FIELD, newStatus);
}

// 儲存記錄到資料庫
entry.save();
}

在撰寫 JavaScript 工作流程時,變數

db 是預定義的,您可以在任何地方參考它。通常,我們會呼叫方法getAPIQuery(pathToForm) 來取得工作表的查詢物件。然後,您可以透過在工作表物件上使用 getAPIEntry(recordId) 檢索記錄,並使用setFieldValue(fieldId,value) 設定欄位的值,或者使用getFieldValue(fieldId) 檢索記錄中的值。請注意,當加上日期值時,它必須是以下列格式之一:

yyyy/MM/dd

yyyy/MM/dd HH:mm:ss

HH:mm:ss

如果您正在從多選欄位檢索值,其中可能有多個值,請使用 getFieldValues(fieldId) 以陣列形式檢索所有值。您還可以呼叫 setFieldValue(fieldId,value,true) 並在末尾加上一個 true 參數來指定您正在“加上”一個選項到當前的值列表,而不是覆蓋現有值。請注意,這些操作僅適用於多選欄位。

如果您想複製一個多選欄位值並覆蓋到另一個多選欄位,您不能僅僅使用 getFieldValues(fieldId)setFieldValue(fieldId,value,true)。這裡有一段程式碼供您參考:


var multipleSelectionFieldValue = entry.getFieldValues(1013251); // 1013251 是一個多選欄位 
var targetMultipleSelectionField = "";

for (var i = 0; i < multipleSelectionFieldValue.length; i++) {
  if (i == 0) {
    targetMultipleSelectionField = targetMultipleSelectionField + multipleSelectionFieldValue[i];
  } 
  else {
    targetMultipleSelectionField = targetMultipleSelectionField + "|" + multipleSelectionFieldValue[i];
  }
}

entry.setFieldValue(1013252, targetMultipleSelectionField, false); // 1013251 是另一個多選欄位 

請注意,您需要檢索每個選項,並使用垂直條字元(|)格式化這些選項,就像您在從 Excel 或 CSV 文件導入現有資料時所做的一樣。

如果您要將值設定為文件上傳欄位,您可以使用 setFieldFile(int fieldId, String fileName, String fileContent) 來建立一個具有您提供的 fileName 和 fileContent 的文件。Ragic 將會儲存此文件到指定欄位,這樣文件就可以在用戶界面上下載。

完成後,只需在記錄物件上呼叫 save() 將其儲存回資料庫。

建立記錄

建立記錄與更新資料非常相似。不同的是,您需要呼叫 query.insertAPIEntry() 來建立新資料。與 getAPIEntry() 一樣,它也會回傳一個紀錄物件,您可以使用 setFieldValue 來加上欄位值。呼叫 entry.save() 之後,記錄將被建立。

這是一個簡單的範例,修改了記錄更新範例來建立新資料:

/**

 * AP_Name:wfdemo
 * 主鍵欄位: 1000013

 * 名稱 ID
 * - - - - - - - - - - - --------
 * No.: 1000011
 * 狀態: 1000012

 */
function setStatus(recordId, status) {
  var STATUS_FIELD = 1000012; // 狀態欄位的欄位ID
  var query = db.getAPIQuery("/workflow-demo/2"); // 取得工作表的查詢物件
  var entry = query.insertAPIEntry();// 建立新資料物件

  // 建立新資料到資料庫
  entry.save();
}

子表格

範例連結

如果您在工作表中有子表格,您也可以使用我們的 API 來檢索資料或進行編輯,像以下範例。表單看起來像這樣:

這個工作流程將遍歷子表格中的每一行,找到本年度的總金額(根據子表格中的日期欄位)、金額最多的一年總額,並確定哪一年具有最高總額。這被設計為一個 Post-workflow,因此這三個只讀欄位將在記錄儲存後由工作流程填寫。

/**

 * AP_Name:wfdemo
 * 主鍵欄位: 1000006

 * 日期子表格主鍵: 1000007

 * 欄位名稱 欄位 ID
 * - - - - - - - - - - - --------
 * No. : 1000001
 * 名稱: 1000002
 * 日期: 1000003
 * 金額 : 1000004
 * 本年度總額: 1000010
 * 最高年度總額 : 1000009
 * 最高總額年份 : 1000008

 */

var KEY_FIELD = 1000006;
var AMOUNT_SUBTABLE_ID= 1000007;
var DATE_FIELD= 1000003;
var AMOUNT_FIELD= 1000004;
var MAX_YEAR_FIELD= 1000008;
var MAX_TOTAL_FIELD = 1000009;
var THIS_YEAR_TOTAL_FIELD = 1000010;

var query = db.getAPIQuery("/workflow-demo/1");

var entry = query.getAPIEntry(param.getNewNodeId(KEY_FIELD));
var subtableSize = entry.getSubtableSize(AMOUNT_SUBTABLE_ID);

var yearTotal = {}
for (var i = 0; i < subtableSize; i++) {
  var year = parseInt(entry.getSubtableFieldValue(AMOUNT_SUBTABLE_ID, i, DATE_FIELD).substr(0, 4));
  var amount = parseInt(entry.getSubtableFieldValue(AMOUNT_SUBTABLE_ID, i, AMOUNT_FIELD));
  if (year in yearTotal) {
    yearTotal[year] += amount;
  } else {
    yearTotal[year] = amount;
  }
}

var maxYear;
for (var year in yearTotal) {
  if (!maxYear || yearTotal[maxYear] < yearTotal[year]) {
    maxYear = year;
  }
}

entry.setFieldValue(MAX_YEAR_FIELD, maxYear);
entry.setFieldValue(MAX_TOTAL_FIELD, yearTotal[maxYear]);
entry.setFieldValue(THIS_YEAR_TOTAL_FIELD, yearTotal[new Date().getFullYear()]);
entry.save();

基本想法是使用 getSubtableSize(subtableId) 取得記錄的子表格行數,並使用 getSubtableFieldValue(subtableId,subtableRowIndex,subtableFieldId) 檢索它們的值。當您開始編輯工作流程程式時,應該能在自動生成的註釋中找到子表格 ID 和欄位 ID 資訊。 您還可以使用 setSubtableFieldValue(subtableFieldId,subtableRootNodeId,value) 將值設定到子表格欄位。subtableRootNodeId 用於指定您所指的子表格行。要查找現有子表格行的 subtableRootNodeId,您可以使用以下呼叫 getSubtableRootNodeId(subtableId,subtableRowIndex),它將回傳包含 subtableRootNodeId 的整數。 如果需要向子表格加上一行,可以使用負數 subtableRootNodeId 例如 -100,這樣所有設定到相同負數 subtableRootNodeId 的值將應用到同一新子表格行,而設定到不同負數 subtableRootNodeId 例如 -101 的值將建立具有這不同值集的另一行。

Pre-workflow 和 Post-workflow

如果您希望在 Pre-workflow 和 Post-workflow 中取得值,請參考以下範例:

var list = param.getSubtableEntry(AMOUNT_SUBTABLE_ID);
var arr = list.toArray();
response.setStatus('WARN');
for (var i = 0; i < arr.length; i++) {
  response.setMessage('日期: '+arr[i].getNewValue(DATE_FIELD)+', 金額: '+arr[i].getNewValue(AMOUNT_FIELD)+'\r\n');
}

訪問所有紀錄

目前我們提供兩種方式讓您遍歷 query 中的每筆紀錄,分別是使用 getAPIResultsFull 與 getAPIResultList 兩種方法。

方法名稱 描述
getAPIResultsFull 利用 while 迴圈逐筆取得資料,對於記憶體負擔較小,適合用來處理大量資料。
getAPIResultList 一次性地將所有資料抓進記憶體,較為直觀,但對記憶體負擔較大。
  //getAPIResultsFull 範例
  var query = db.getAPIQuery("/workflow-demo/1");
  var results = query.getAPIResultsFull();
  var entry = results.next();
  while(entry) {
    // do something
    entry = results.next();
  }

  //getAPIResultList 範例
  var query = db.getAPIQuery("/workflow-demo/1");
  var results = query.getAPIResultList();
  for(var i = 0; i < results.length; i ++) {
    var entry = result[i];
    // do something
  }

複製記錄

範例連結:從這裡複製複製到這裡

複製記錄是我們遇到的最常見的工作流程程式之一。我們撰寫了一個非常簡單的函數來簡化這類操作。假設我們希望查看這個工作表中的一筆紀錄:

透過點擊按鈕,在這個工作表中生成一筆紀錄:

以下是這個動作按鈕的程式碼:

/**

 * AP_Name:wfdemo
 * 主鍵欄位: 1000022

 * S1 子表格主鍵: 1000023
 * T1 子表格主鍵: 1000029

 * 欄位名稱欄位 ID
 * - - - - - - - - - - - --------
 * A: 1000014
 * C: 1000015
 * B: 1000016
 * D: 1000017
 * S1 : 1000018
 * S2 : 1000019
 * S3 : 1000020
 * S4 : 1000021
 * T1 : 1000024
 * T2 : 1000025
 * T3 : 1000026

 */

function copyEntry(nodeId) {
  db.entryCopier(JSON.stringify({
    THIS_PATH:"/workflow-demo/3",
    THIS_NODEID:nodeId,
    NEW_PATH:"/workflow-demo/4",
    COPY:{
      1000030:1000014,// A
      1000031:1000015,// C
      1000032:1000018,// S1
      1000033:1000020 // S3
    }
  }),response);
}

在這裡,您可以看到我們可以透過一個簡單的函數呼叫entryCopier 來完成複製操作。entryCopier 接受一個 JSON字串作為其參數。只需輸入源工作表、目標工作表、我們正在複製的紀錄,以及最重要的是,哪些欄位應映射到哪些欄位。完成映射後,您可以非常輕鬆地建立動作按鈕來從一個工作表複製記錄到另一個工作表。讓我們看另一個範例。 這裡,我們希望將 Lin 從 "CopyFrom" 複製到 "CopyTo",並將狀態設定為 new。此外,我們還希望記錄建立日期(請忽略本範例中的 $DATE 欄位的使用)。

/**
 * 欄位名稱欄位 ID
 * - - - - - - - - - - - --------
 * From-ID: 1000001
 * From-Name: 1000002
 * To-ID: 1000004
 * To-Name: 1000005
 * 狀態: 1000007
 * 註冊日期: 1000008
 */

function copyEntry(nodeId) {
  db.entryCopier(JSON.stringify({
    THIS_PATH:"/entrycopier/1",
    THIS_NODEID:nodeId,
    NEW_PATH:"/entrycopier/2",
    COPY:{
      // 目標欄位:源欄位
      1000004:1000001, 
      1000005:1000002, 
    }
  }),response);
  // 取得剛才複製的紀錄的 rootNodeId
  var newEntryRootNodeId = response.getRootNodeId();
  // 我們需要建立一個 ApiQuery 來查詢 '/entrycopier/2'
  var toApiQuery = db.getAPIQuery('/entrycopier/2');
  // 取得剛才複製的紀錄
  var newEntry = toApiQuery.getAPIEntry(newEntryRootNodeId);
  newEntry.setFieldValue(1000007, "New");
  var current = new Date();
  newEntry.setFieldValue(1000008, current.getFullYear()+'/' + (current.getMonth()+1) + '/' + current.getDate());
  newEntry.save();
}

接下來,設定動作按鈕並儲存。

然後,只需點擊動作按鈕即可顯示結果。

刪除記錄

您可以使用 query.deleteEntry(nodeId) 來刪除紀錄,若您有多筆紀錄需要刪除,則可透過 query.getAPIResultList() 來遍歷整個 query 刪除資料。

  var query = db.getAPIQuery(pathToForm);
  query.addFilter(1000001, '=', 'To Be Deleted'); //篩出 1000001 的值為 To Be Deleted 的所有紀錄
  var results = query.getAPIResultList();
  for(var i = 0; i < results.length; i ++) { //將篩出的紀錄全數刪除
    var entry = results[i];
    query.deleteEntry(entry.getRootNodeId());
  }

若您要刪除的紀錄大於 1000 筆,則須搭配 setLimitSize 使用,query 預設一次僅能處理 1000 筆資料。

  //假設有 3000 筆資料需要刪除

  var limitSize = 1500; //每個 query 的上限
  var query = db.getAPIQuery(pathToForm);
  query.addFilter(1000001, '=', 'To Be Deleted'); //篩出 1000001 的值為 To Be Deleted 的所有紀錄
  query.setLimitSize(limitSize); //非必要,此為設定 query 最大上限,預設為 1000
  var results = query.getAPIResultList();

  while(results.length > 0) {
    for(var i = 0; i < results.length; i ++) {
      var entry = results[i];
      query.deleteEntry(entry.getRootNodeId());
    }

    //每過 1000 筆資料後重新抓取 query
    var query = db.getAPIQuery(pathToForm);
    query.addFilter(1000001, '=', 'To Be Deleted');
    query.setLimitSize(limitSize);
    results = query.getAPIResultList();
  }

檢查用戶權限

您可以根據將要執行程式的用戶所在的群組進行一些條件處理。一個用戶可以在多個用戶群組中,所以通常我們可以透過呼叫 user.isInGroup(groupName) 來判斷用戶是否在該用戶群組中。以下是一個典型的使用範例,這段程式設計為 Pre-workflow,但 user 物件和 isInGroup 呼叫可以在所有類型的工作流程中使用,除了 Daily Workflow,它是由系統觸發的。

if(!user.isInGroup('SYSAdmin')){// 檢查用戶是否為 SYSAdmin
  response.setStatus('INVALID');// 如果不是,則不儲存記錄
  response.setMessage('您沒有權限進行此操作。');// 並顯示一筆訊息
}

發送電子郵件通知

有時候您可能希望根據一組條件發送電子郵件通知,或者您希望真正自訂您的通知訊息內容。您可以為此撰寫伺服器端 JavaScript 工作流程。這是發送電子郵件的程式碼,非常簡單:


// 省略...先檢索記錄物件

var name=entry.getFieldValue(1001426);
var email=entry.getFieldValue(1001428);
var title=entry.getFieldValue(1001386);

mailer.compose(
  email,// 收件人
  null, // 副本
  'support@example.com',// 回覆地址
  'Acme, Inc.',// 顯示的發件人
  title,
  '嗨 '+name+',

我們已收到您的銷售訂單,'+   '並將很快處理您的訂單。

'+   '您可以在 https://www.ragic.com/example/1 查看您的訂單詳情。

'+   '謝謝。


最好的祝福,

Sophia, 銷售經理

Acme, Inc.' ); // mailer.attach(myURL); // 您可以使用 .attach 來附加來自 URL 的內容 mailer.send();

請注意,如果您希望將電子郵件發送給多個收件人,只需用逗號分隔每個電子郵件地址。對於附件,您可以使用 mailer.attach(myURL); 來附加 Ragic 上的紀錄,使用記錄的 URL。例如,這是 Ragic 上的紀錄 URL(始終忽略哈希後的 URL):

https://www.ragic.com/wfdemo/workflow-demo/2/9

這是其 HTML 友善列印版 URL:

https://www.ragic.com/wfdemo/workflow-demo/2/9.xhtml

這是其 Excel 版本 URL:

https://www.ragic.com/wfdemo/workflow-demo/2/9.xlsx

您還可以使用郵件合併 URL,例如,cid 是郵件合併的 ID,當嘗試下載郵件合併文件時,您可以在 URL 中取得 cid:

https://www.ragic.com/wfdemo/workflow-demo/2/9.custom?rn=9&cid=1

我們對您可以發送的電子郵件數量有限制。因此請合理發送!如果您對電子郵件發送配額有任何疑問,請發送電子郵件至 support@ragic.com

建立和取消簽核

您可以透過在工作表中加上 Post-workflow 程式來啟動或取消記錄的簽核。首先,在設計模式中設定簽核步驟。

現在,在 Post-workflow 中設定簽核詳細資訊

function autoStartApprover() {
  var signers = [];
  signers.push({
    'stepIndex':'0',
    'approver':'kingjo@ragic.com',
    'stepName':'START'
  });
  signers.push({
    'stepIndex':'1',
    'approver':'HR0000@hr.hr',
    'stepName':'HR'
  });

  approval.create(JSON.stringify(signers));
}

autoStartApprover();

結果

{
  'stepIndex':'0',
  'approver':'kingjo@ragic.com',
  'stepName':'START'
}

是您應提供的參數格式。

stepIndex : 用於指明簽核的步驟,從零開始。 approver :用於指明誰可以簽核此步驟。 stepName : 用於設定簽核步驟名稱。

如果參數格式有誤或您提供的簽核人不符合設計模式中設定的規則,簽核將不會建立。

在這個範例中,如果您給第二步提供參數如下:

{
  'stepIndex':'1',
  'approver':'kingjo@ragic.com',
  'stepName':'HR'
}

那麼它將失敗,因為 kingjo@ragic.com 不在 HR 群組中。我們還提供了三種特殊格式,用於根據您的公司樹動態決定簽核人員。您可以參考此連結了解更多資訊。

$DS : 簽核人將設定為用戶的直屬主管。 $SS :簽核人將設定為用戶主管的主管。 $DSL : 簽核人將設定為前一個簽核人的主管。參數格式如下:

{
  'stepIndex':'1',
  'approver':'$DSL',
  'stepName':''
}

當使用這些特殊格式時,您不需要提供非空的 stepName。注意:如果特殊格式中的用戶不符合您在設計模式中設定的規則,該簽核將不會建立。

發送手機應用通知

除了電子郵件通知,您還可以發送手機應用通知。如果用戶在其行動裝置上安裝了 iOS 應用或 Android 應用,則會向其發送通知。電子郵件引用的是您在 Ragic 帳戶中註冊的用戶電子郵件地址。例如:

mailer.sendAppNotification("mike@example.com","測試手機通知");

如果您希望用戶在點擊此通知時被重定向到指定記錄,您應提供要重定向到的表單路徑(例如:/forms/1)和記錄 ID。呼叫應如下所示:

mailer.sendAppNotification("mike@example.com","測試手機通知","/forms/1",12);

簽核和其他記錄資訊

您可以首先對從 db.getAPIQuery 取得的查詢物件發出以下命令,以包括完整的紀錄資訊:

query.setIfIncludeInfo(true);

然後您可以透過以下方式取得記錄的簽核資訊:

entry.getFieldValue('_approve_status');// 取得當前簽核狀態
entry.getFieldValue('_approve_next');// 取得下一個應簽核此記錄的人
entry.getFieldValue('_create_date');// 取得記錄的建立日期
entry.getFieldValue('_create_user');// 取得記錄的建立用戶電子郵件

簽核狀態將顯示 F 表示已簽核,REJ 表示拒絕,P 表示處理中。

下載和上傳檔案

發送 HTTP 請求

您可以向 URL 發送 HTTP GET/POST/DELETE/PUT 請求並取得回傳結果:

util.getURL(String urlstring)
util.postURL(String urlstring,String postBody)
util.deleteURL(String urlstring)
util.putURL(String urlstring,String putBody)

變數 util 是預定義的。 如果您需要忽略當前 HTTP 請求的 SSL 憑證檢查,可以在發送請求前加上以下程式碼:

util.ignoreSSL()

此外,您可以呼叫 util.setHeader(String name,String value) 設定 HTTP 標頭。util.removeHeader(String name) 用於移除標頭。

下載和上傳檔案

您可以透過URL下載檔案並且取得檔案名稱:

util.downloadFile(fileUrl);
//fileUrl:檔案的來源URL
//該方法回傳的值:下載下來的檔名 

當您將檔案下載至資料庫後,可以使用setFieldValue將檔名填回檔案欄位,即可在表單中預覽或是將檔案下載至本機。

var fileFieldId = 1000087;
var fileName = util.downloadFile(fileUrl);
entry.setFieldValue(1000087, fileName);
entry.save();

您也可以上傳檔案至目標網址並取得檔案名稱:

util.postFile(sourceFileUrl, destinationUrl)
//sourceFileUrl:檔案的來源URL
//destinationUrl:檔案要上傳的目標URL
//該方法回傳的值:上傳到資料庫的檔名

關於取得完整檔案、圖片連結的方法可以參閱這篇教學

呼叫其他表單的 workflow

使用 workflow 修改其他表單的資料時,預設是不會觸發該表單的 workflow。如果您需要觸發該表單的 post-workflow 或是 pre-workflow,可以使用以下程式碼:

var query = db.getAPIQuery(pathToForm);
var entry = query.getAPIEntry(recordId);
//執行某些動作...

entry.setIfExecuteWorkflow(true);
entry.save();

API 參考

此處列出的預定義系統全域變數可以直接訪問,無需定義。

db


getAPIResult()

遍歷查詢時取得第一筆紀錄

getAPIResultsFull()

取得查詢的紀錄,透過next()方法來取得下一筆資料,搭配while迴圈即可逐筆取得資料

getAPIResultList()

取得查詢的紀錄數組

getAPIEntry(int rootNodeId)

通過節點 ID 取得記錄

getKeyFieldId()

檢索此查詢所在工作表的主鍵欄位 ID。

getFieldIdByName(String fieldName)

根據指定名稱取得欄位 ID。如果有多個相同名稱的欄位,將回傳第一個獨立的欄位 ID。

insertAPIEntry()

向查詢中插入新資料,該方法回傳新資料

addFilter(int fieldId, String operand, String value)

按指定條件過濾資料

setIfIgnoreFixedFilter(boolean ifIgnoreFixedFilter)

設定是否忽略目標工作表的固定過濾條件

setOrder(int orderField, int orderDir)

按指定欄位 ID 和排序方向對查詢資料進行排序,參數orderDir 設定為 1 表示升序排序,設定為 2 表示降序排序,設定為 3 表示次要升序排序,設定為 4 表示次要降序排序。

deleteEntry(int nodeId)

通過節點 ID 刪除資料

deleteEntryToRecycleBin(int nodeId)

通過節點 ID 將資料刪除到回收站

setLimitSize(int limitSize)

預設情況下,ScriptAPIQuery 每次查詢回傳 1000 筆紀錄,您可以使用 setLimitSize 更改每次查詢回傳的紀錄數量。然而,我們不建議每次查詢回傳過多的紀錄,因為這可能會佔用過多記憶體並影響性能。我們建議使用下一個方法 setLimitFrom 進行分頁。

setLimitFrom(int limitFrom)

此方法用於遍歷 ScriptAPIQuery 的所有記錄。設定 limitFrom 將告訴 ScriptAPIQuery 從偏移量開始回傳記錄,以便您遍歷 ScriptAPIQuery 的所有記錄,因為 ScriptAPIQuery 預設每次查詢回傳 1000 筆紀錄。您應該檢查回傳的紀錄數量是否等於回傳列表的大小,以確定是否存在下一頁。

setGetUserNameAsSelectUserValue(boolean b)

設定為 false 時,查詢將檢索用戶的電子郵件作為選擇用戶欄位的值,而不是使用者名稱。

recalculateAll(String Path)

針對某張表單的所有資料的所有欄位進行公式重算。

recalculateAll(String Path, String FieldId...)

針對某張表單的所有資料的指定欄位進行公式重算,第二個參數開始皆為 FieldId,可以用逗號分隔以輸入多個 FieldId。

setLogRecalcCostTime(boolean b)

設定為True就能在「Workflow 表單公式重算執行時間紀錄」中顯示,使用 db.recalculateAll() 公式重算一張表單所花費的時間。

entry


getFieldValue(int fieldId)

透過欄位 ID 取得欄位值。不包括子表格欄位。

getFieldIdByName(String fieldName)

透過指定名稱取得欄位 ID。如果有多個相同名稱的欄位,將回傳第一個欄位值。

getKeyFieldId()

檢索此工作表的主鍵欄位 ID。

getFieldValueByName(String fieldName)

透過欄位名稱取得欄位值。不包括子表格欄位。如果有多個相同名稱的欄位,將回傳第一個欄位值。

getFieldValues(int fieldId)

將多選欄位中的所有欄位值作為陣列取得。不包括子表格欄位。

getRootNodeId()

取得資料的根節點 ID

getRootfieldId()

取得資料的根欄位 ID

getSubtableSize(int subtableRootfieldId)

透過子表格的根欄位 ID 取得子表格的大小。

getSubtableRootNodeId(int subtableRootfieldId, int rowNumber)

透過子表格的根欄位 ID 和子表格中的行號取得根節點 ID。

getJSON()

取得整個紀錄的 JSON 表示。

setFieldValue(int fieldId, String value)

為指定欄位設定值。對於子表格欄位,您需要使用 setSubtableFieldValue()。

setFieldValue(int fieldId, String value, boolean appendValue)

為多選欄位設定值,參數 appendValue 必須為 true。對於子表格欄位,您需要使用 setSubtableFieldValue()。

setFieldFile(int fieldId, String fileName, String fileContent)

僅適用於文件上傳或圖形欄位。將建立一個具有您提供的 fileContent 的文件上傳並儲存到指定欄位。對於子表格欄位,您需要使用 setSubtableFieldFile()。

setFieldFile(int fieldId, String fileName, String fileContent, boolean appendValue)

若要不覆蓋檔案欄位原本的檔案,參數 appendValue 必須為 true

setSubtableFieldValue(int fieldId, int subtableRootNodeId, String value)

為子表格欄位設定值,您可以透過方法 getSubtableRootNodeId 取得參數 subtableRootNodeId

setSubtableFieldValue(int fieldId, int subtableRootNodeId, String value, boolean appendValue)

為多選子表格欄位設定值,參數 appendValue 必須為 true

setSubtableFieldFile(int fieldId, int subtableRootNodeId, String fileName, String fileContent)

僅適用於子表格的文件上傳或圖形欄位。將建立一個具有您提供的 fileContent 的文件上傳並儲存到指定欄位。

setSubtableFieldFile(int fieldId, int subtableRootNodeId, String fileName, String fileContent, boolean appendValue)

若要不覆蓋檔案欄位原本的檔案,參數 appendValue 必須為 true

deleteSubtableRowByRowNumber(int subtableRootfieldId, int rowNumber)

透過根欄位 ID 和子表格中的行號刪除子表格行。

deleteSubtableRowAll(int subtableRootfieldId)

刪除指定子表格中的所有行

deleteSubtableRow(int subtableRootfieldId, int subtableRootNodeId)

透過根欄位 ID 和子表格的根節點 ID 刪除子表格行

loadAllLinkAndLoad()

載入資料中連結和載入配置的所有載入欄位的值。

recalculateAllFormulas()

重新計算資料中包含公式的所有欄位。

recalculateFormula(int fieldId)

重新計算指定欄位的公式。
注意:如果兩個或多個欄位共享相同的 fieldId,請改用 recalculateFormula(int fieldId, String cellName)。

recalculateFormula(int fieldId, String cellName)

使用 cellName 參數確定欄位的儲存格位置(如 A1,C2,H21 等),重新計算指定欄位的公式。此方法適用於具有相同 fieldId 的多個欄位。

loadAllDefaultValues(ScriptUser user)

載入設定了預設值的所有欄位的值,參數 user 是預定義的。

loadDefaultValue(int fieldId, ScriptUser user)

載入指定欄位的預設值,參數 user 是預定義的。

lock()

鎖定資料

unlock()

解鎖資料

save()

儲存資料

setCreateHistory(boolean createHistory)

設定資料是否需要建立歷史記錄

isCreateHistory()

資料是否設定為建立歷史記錄

setIfExecuteWorkflow(boolean executeWorkflow)

設定資料是否需要執行工作流程(Pre-workflow 和 Post-workflow)

setIgnoreEmptyCheck(boolean ignoreEmptyCheck)

設定是否忽略不為空的欄位檢查

setRecalParentFormula(boolean recalParentFormula)

如果此工作表是由另一工作表的子表格建立的,或者被另一工作表引用,這意味著此工作表具有父工作表,則可以呼叫此方法設定是否需要重新計算父工作表。

setIfDoLnls(boolean)

如果該工作表連結到此工作表(源工作表),則將觸發另一工作表上的同步。您應該始終在源工作表中加上此方法以觸發另一工作表上的同步。

response


getStatus()

取得回應的狀態。可為 SUCCESS、WARN、CONFIRM、INVALID、ERROR

setStatus(String status)

設定回應的狀態。可為 SUCCESS、WARN、CONFIRM、INVALID、ERROR

setMessage(String plainMessage)

設定程式執行時顯示的訊息。此功能可多次呼叫,所有設定的訊息將同時顯示。

numOfMessages()

回傳已設定的訊息數量。

setOpenURL(String url)

僅限於已安裝的工作表範圍。儲存編輯後將使用者重定向到指定的 URL。

setOpenURLInNewTab(boolean b)

設定是否在新標籤頁中打開 URL。預設為 true。

user


getEmail()

取得用戶的電子郵件地址

getUserName()

取得用戶的全名

isInGroup(String groupName)

回傳用戶是否在具有 groupName 的用戶群組中

mailer


compose(String to,String cc,String from,String fromPersonal,String subject,String content)

撰寫一封要發送的電子郵件訊息。to 和 cc 參數可以包含多個電子郵件地址,只需用逗號分隔。

send()

發送剛撰寫的訊息。

sendAsync()

非同步發送剛撰寫的訊息。請注意,sendAsync 每次程式執行僅能呼叫一次。

attach(String url)

將文件附加到訊息。URL 應為完整的 https:// 開頭的 URL。

setSendRaw(boolean b)

設定內容是否不轉換為 HTML。如果內容已經是 HTML,請將其設定為 true。

sendAppNotification(String email,String message)

如果用戶安裝了 Ragic iOS 應用或 Android 應用,向該用戶發送行動應用通知。

sendAppNotification(String email,String message,String pathToForm,int nodeId)

如果用戶安裝了 Ragic iOS 應用或 Android 應用,向該用戶發送行動應用通知。用戶在點擊此通知時將被重定向到指定的紀錄。"pathToForm" 應為 "/forms/1" 格式,不包含帳戶名,包含標籤資料夾和工作表索引。

util


getURL(String urlstring)

以 GET 方法呼叫 URL

postURL(String urlstring,String postBody)

以 POST 方法呼叫 URL。

deleteURL(String urlstring)

以 DELETE 方法呼叫 URL。

putURL(String urlstring,String putBody)

以 PUT 方法呼叫 URL。

downloadFile(String fileUrl)

將 fileUrl 回傳的檔案下載至資料庫中的 upload 資料夾

downloadFile(String fileUrl, String postBody)

將 fileUrl 回傳的檔案下載至資料庫中的 upload 資料夾

setHeader(String name,String value)

設定 HTTP 標頭,將在後續的 URL 呼叫中使用。

ignoreSSL()

忽略當前 HTTP 請求的 SSL 憑證檢查

removeHeader(String name)

移除後續 URL 呼叫中使用的 HTTP 標頭。

logWorkflowError(String text)

在工作流程日誌中記錄字串文字日誌訊息,您可以在資料庫維護頁面中找到它。

account


getUserName(String email)

根據電子郵件地址取得用戶的全名。

getUserEmail(String userName)

根據使用者名稱取得電子郵件地址。

reset()

程式執行完畢後,清除所有與帳戶相關的快取並重新載入頁面。

getTimeZoneOffset()

取得此帳戶的時區時差,以毫秒為單位。

getTimeZoneOffsetInHours()

取得此帳戶的時區時差,以小時為單位。

param


getUpdatedEntry()

僅適用於 Post-workflow。回傳剛建立或更新的紀錄。

getNewNodeId(int fieldId)

回傳指定欄位的新值寫入後的節點 ID(整數)。

getOldNodeId(int fieldId)

回傳指定欄位的新值寫入前的節點 ID(整數)。

getNewValue(int fieldId)

回傳指定欄位的新值寫入後的值。

getOldValue(int fieldId)

回傳指定欄位的新值寫入前的值。

getNewValues(int fieldId)

類似於 getNewValue,但可以同時訪問多個值,這在處理多選欄位時非常有用。

getOldValues(int fieldId)

類似於 getOldValue,但可以同時訪問多個值,這在處理多選欄位時非常有用。

getSubtableEntry(int fieldId)

回傳一個參數列表,可以操作子表格中的每筆紀錄。

isCreateNew()

回傳資料是否新建立。

approval


create(String[] wfSigner)

僅適用於 Post-workflow。wfSigner 是一個包含特定 JSON 格式物件的陣列。

  {
    'stepIndex': 簽核的步驟 - 從 0 開始, 
    'approver' : 簽核人的電子郵件, 
    'stepName' : 簽核人的姓名或職稱, 
  }

  範例 "單步驟簽核人" : 
  wfSigner push({
    'stepIndex':'1',
    'approver':'kingjo@ragic.com',
    'stepName':'Jo'
  })

請注意,wfSigner 應滿足您在設計模式中設定的簽核。 例如,如果在設計模式中的第二步僅有 "HR00@gmail.com" 一個候選人,您應提供一個包含 approver: HR00@gmail.com 和 stepIndex : 1 的 JSON。

cancel()

僅適用於 Post-workflow。取消資料中的簽核。

approvalParam


getEntryRootNodeId()

取得資料的根節點 ID

getApprovalAction()

取得簽核的操作。可為 CREATE、APPROVE、FINISH、CANCEL、REJECT

回最上面 目錄

馬上註冊
免費試用 Ragic!

用 Google 帳號註冊

立即科技 Ragic, Inc.
02-7728-8692
info@ragic.com
台北市中正區南昌路二段81號9樓