iT邦幫忙

0

kintone 外掛開發 ⑤ 簡單實作範例 part 3 - 透過 kintone plugin API 保存/取得外掛設定資料

  • 分享至 

  • xImage
  •  

在上一篇文章 kintone 外掛開發 ④ 簡單實作範例 part 2 - 製作外掛設定畫面 中,我們已經完成了外掛設定畫面的實作,讓使用者可以透過直覺的 UI 介面,自行選擇應用程式中的欄位並進行相對應的設定。

本篇將進一步說明,如何透過 kintone plugin API 將使用者所設定的內容儲存起來,並在實際應用程式中讀取這些設定,使外掛功能能夠根據這些資料正確運作。

kintone plugin API

在 kintone 提供的 JavaScript API 中,目前有下列與外掛相關的 API:

接下來的實作中,我們將會使用 kintone.plugin.app.setConfig() 來儲存外掛設定,並透過 kintone.plugin.app.getConfig() 讀取先前儲存的設定內容。

保存外掛設定資料

kintone.plugin.app.setConfig(config, successCallback)

參數

參數名稱 類型 是否必填 說明
config 物件 必填 儲存於外掛的設定資料。格式為鍵值對,例如:{ "key1": "value1", "key2": "value2" }。※ key 為 ASCII 相容字元,value 為字串。
successCallback 函式 可省略 儲存成功後執行的函式,無參數。若省略,系統將自動導回外掛清單畫面並顯示設定完成訊息。若指定此函式,則不會自動跳轉。

由於 config 的值僅支援字串格式,若需要儲存陣列、物件等資料類型,請先使用 JSON.stringify() 將其轉為字串,讀取時再透過 JSON.parse() 還原為原始格式。

可使用的畫面

  • 電腦版的外掛設定頁面

取得外掛設定資料

kintone.plugin.app.getConfig(pluginId)

參數

參數名稱 類型 是否必填 說明
pluginId 字串 必填 要取得其設定資訊的外掛ID

可使用的畫面

  • 電腦版:
    • 外掛設定頁面
    • 記錄列印畫面
    • 圖表畫面
  • 電腦版/行動版:
    • 清單一覽畫面
    • 記錄新增畫面
    • 記錄編輯畫面
    • 記錄詳細畫面

在進入外掛設定畫面時,通常會透過 getConfig() 來載入並填入先前儲存的設定資料,讓使用者可進行編輯;而在應用程式中,則須在客製化程式中引用這些設定內容,取代原先寫死的欄位代碼或其他固定值,使外掛能根據實際設定運作。

在外掛設定頁面中保存與取得資訊

保存設定

首先,為「保存」按鈕加上點擊事件的監聽器,點擊按鈕時可以先透過 console.log 檢視目前的 data 資料內容:

// 按鈕功能
saveButton.addEventListener('click', () => {
  console.log(data)
})

如上圖所示,在表格中新增三筆設定資料,點擊保存後會列印出一個陣列,包含每一列的設定物件。接下來,我們要透過 kintone.plugin.app.setConfig() 將這些設定資料儲存到 kintone:

// 按鈕功能
saveButton.addEventListener('click', () => {
  const config = {
    data: JSON.stringify(data)
  }
  kintone.plugin.app.setConfig(config)
})

如前所述,config 必須是以「鍵值對」為結構的物件,且值僅支援字串格式。因此,這裡我們使用 JSON.stringify()data 陣列轉為字串,再存入 config 中。

由於此處省略了 successCallback 參數,設定儲存成功後會自動跳轉回應用程式的外掛清單畫面,並顯示設定完成的提示訊息。

取得已保存的外掛設定

下一步,我們希望在使用者再次打開外掛設定畫面時,自動載入先前儲存的設定。這時可透過 kintone.plugin.app.getConfig(pluginId) 來取得已保存的外掛資料:

// 預設空白列資料
const defaltRowData = {
  table: '',
  conditionField: '',
  conditionValue: '',
  inputField: '',
  outputField: ''
}
let data = [defaltRowData]

// 載入已保存的設定資料
const pluginConfig = kintone.plugin.app.getConfig(PLUGIN_ID)
if (pluginConfig.data) {
  const configData = JSON.parse(pluginConfig.data)
  if (Array.isArray(configData) && configData.length > 0) {
    data = configData
  }
}

在既有的「預設空白列資料」邏輯下,我們透過 API 取得先前儲存的外掛設定資料 pluginConfig。由於我們是把表格的資料存在 data 這個屬性中,並且是以 JSON 字串形式儲存,所以這裡需要用 JSON.parse(pluginConfig.data) 將它還原為陣列。

為了讓設定表格正確載入資料,我們加上條件判斷,確認 configData 是一個陣列且長度大於 0,才會覆蓋掉原本的 data;如果沒有有效資料,則維持初始的空白列。

設定成功的話,重新進入外掛設定畫面時,就能看到表格自動載入剛才儲存的設定內容囉。

取消按鈕

最後,來幫「取消」按鈕加上功能,讓使用者點擊後可以直接返回應用程式的外掛一覽畫面:

cancelButton.addEventListener('click', () => {
  // 返回外掛程式一覽畫面
  window.location.href = '../../' + kintone.app.getId() + '/plugin/'
})

到這裡為止,整個外掛的設定畫面就算是完成囉!

改寫客製化程式碼,套用外掛設定

取得已保存的外掛設定

首先,將 customize.js 中原本的程式邏輯清除,只保留建立 change 事件所需的函式,並且記得在外層的 IIFE 中加上 PLUGIN_ID 參數與對應的引數。

接著,加入取得外掛設定的邏輯,並將設定資料暫存到 data 陣列中。這段程式碼可以直接從 config.js 中複製過來使用:

((PLUGIN_ID) => {
  'use strict'

  // 取得外掛設定資料
  let data = []
  const pluginConfig = kintone.plugin.app.getConfig(PLUGIN_ID)
  if (pluginConfig.data) {
    const configData = JSON.parse(pluginConfig.data)
    if (Array.isArray(configData) && configData.length > 0) {
      data = configData
    }
  }

  // 建立 change events 用
  function createChangeEvents(fieldCodes) {
    if (!Array.isArray(fieldCodes)) return
    
    return fieldCodes.map(fieldCode => [
      `app.record.create.change.${fieldCode}`,
      `app.record.edit.change.${fieldCode}`,
      `mobile.app.record.create.change.${fieldCode}`,
      `mobile.app.record.edit.change.${fieldCode}`,
      `app.record.index.edit.change.${fieldCode}`
    ]).flat()
  }
})(kintone.$PLUGIN_ID)

目前 data 的資料格式是以設定表格的形式儲存,每一筆設定對應一列資料。為了讓後續的處理更方便,我們可以先將這個陣列重新整理為物件的形式。以表格欄位代碼(data.table 的值)作為 key,將屬於同一表格的設定分組起來:

// 將各表格的設定資料重新整理
const tableSet = data.reduce((acc, item) => {
  acc[item.table] = acc[item.table] || []
  acc[item.table].push(item)
  return acc
}, {})

這樣處理後,我們就能很方便地針對每一個表格個別進行處理。例如:tableSet['明細'] 就會對應到屬於「明細」的所有設定資料,如下圖所示:

動態建立 kintone event handler

將各表格的設定資料分組整理完後,我們可以透過 JavaScript 的 Object.entries() 搭配 forEach(),遍歷 tableSet,針對每個表格動態註冊對應的事件處理邏輯:

// 動態建立 kintone events
Object.entries(tableSet).forEach(([tableField, settings]) => {
  // 取出要監聽變化的表格中欄位(條件欄位、欲加總數值欄位)
  const changeFields = [
    ...new Set(
      settings.flatMap(setting => [setting.conditionField, setting.inputField])
    ),
  ]
  // 取出小計欄位
  const outputFields = settings.map(setting => setting.outputField)

  // kintone events
  kintone.events.on(
    [
      'app.record.create.show',
      'app.record.edit.show',
      'mobile.app.record.create.show',
      'mobile.app.record.edit.show',
      createChangeEvents([...changeFields, tableField]).flat(),
    ],
    event => {
      const { record } = event
      const table = record[tableField].value

      // 禁止編輯小計欄位
      outputFields.forEach(field => {
        if (record[field]) record[field].disabled = true
      })

      // 初始化 subtotal
      const subtotal = Object.fromEntries(outputFields.map(field => [field, 0]))

      // 動態加總邏輯
      table.forEach(row => {
        settings.forEach(setting => {
          const category = row.value[setting.conditionField]?.value
          const price = Number(row.value[setting.inputField]?.value) || 0

          if (category === setting.conditionValue) {
            subtotal[setting.outputField] += price
          }
        })
      })

      // 將小計值寫入記錄欄位
      outputFields.forEach(field => {
        record[field].value = subtotal[field]
      })

      return event
    }
  )
})

這樣的寫法可以針對每個子表格分別處理,加總邏輯也能根據各自的設定靈活執行。完成後的實際畫面如下所示:

最後,附上改寫後的 customize.js 完整程式碼供大家參考:

((PLUGIN_ID) => {
  'use strict'

  // 取得外掛設定資料
  let data = []
  const pluginConfig = kintone.plugin.app.getConfig(PLUGIN_ID)
  if (pluginConfig.data) {
    const configData = JSON.parse(pluginConfig.data)
    if (Array.isArray(configData) && configData.length > 0) {
      data = configData
    }
  }

  // 將各表格的設定資料重新整理
  const tableSet = data.reduce((acc, item) => {
    acc[item.table] = acc[item.table] || []
    acc[item.table].push(item)
    return acc
  }, {})

  // 動態建立 kintone events
  Object.entries(tableSet).forEach(([tableField, settings]) => {
    // 取出要監聽變化的表格中欄位(條件欄位、欲加總數值欄位)
    const changeFields = [...new Set(
      settings.flatMap(setting => [setting.conditionField, setting.inputField])
    )]
    // 取出小計欄位
    const outputFields = settings.map(setting => setting.outputField)
    
    // kintone events
    kintone.events.on([
      'app.record.create.show', 'app.record.edit.show',
      'mobile.app.record.create.show', 'mobile.app.record.edit.show',
      createChangeEvents([...changeFields, tableField]).flat()
    ], event => {
      const { record } = event
      const table = record[tableField].value

      // 禁止編輯小計欄位
      outputFields.forEach(field => {
        if (record[field]) record[field].disabled = true
      })

      // 初始化 subtotal
      const subtotal = Object.fromEntries(outputFields.map(field => [field, 0]))

      // 動態加總邏輯
      table.forEach(row => {
        settings.forEach(setting => {
          const category = row.value[setting.conditionField]?.value
          const price = Number(row.value[setting.inputField]?.value) || 0

          if (category === setting.conditionValue) {
            subtotal[setting.outputField] += price
          }
        })
      })

      // 將小計值寫入記錄欄位
      outputFields.forEach(field => {
        record[field].value = subtotal[field]
      })

      return event
    })
  })

  // 建立 change events 用
  function createChangeEvents(fieldCodes) {
    if (!Array.isArray(fieldCodes)) return
    
    return fieldCodes.map(fieldCode => [
      `app.record.create.change.${fieldCode}`,
      `app.record.edit.change.${fieldCode}`,
      `mobile.app.record.create.change.${fieldCode}`,
      `mobile.app.record.edit.change.${fieldCode}`,
      `app.record.index.edit.change.${fieldCode}`
    ]).flat()
  }
})(kintone.$PLUGIN_ID)

結語

在本系列的「kintone 外掛開發」教學中,我們介紹了外掛的基本結構、打包所需的工具、kintone plugin API 的使用方式,並實際完成了一個具備設定畫面與運作邏輯的簡易外掛。

雖然篇幅有限,無法涵蓋所有進階技巧與 API,但希望透過這幾篇文章,能讓你對 kintone 外掛的開發流程有更清晰的認識,並作為進一步延伸的起點。若想了解更多細節與可能的擴充方向,建議可搭配官方文件深入參考,靈活運用這些工具與技術,打造更貼近需求的 kintone 解決方案!


圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言