通过自定义将kintone数据生成excel

cnDevNet发表于:2022年07月21日 10:57:56更新于:2024年06月19日 13:47:21

Index

概要

之前我们给大家演示了如何预览kintone中excel数据的自定义开发(kintone excel预览插件

大家都觉得很有用。但是excel的需求实在太多,还有一些用户来留言,希望能实现将kintone数据直接生成excel。

那这次我们就来研究下这种需求如何实现吧。

需求

我们经常会有这样的问题:虽然通过kintone创建了订单,送货单,合同类应用,实现了无纸化办公,但是有时候还是需要能将数据打印出来提供给客户,或者存档等。

虽然kintone自带打印功能,但是无法对打印样式进行一个编排。这时候我们可以设想,如果有这么一个开发,只需要我们提供excel模版,然后能自动填入kintone上的应用数据到这个excel模版,

并且可以下载打印。那是不是就完美的满足了我们的需求。

演示效果


kintone应用准备

导入应用

导入我们事先准备好的模版应用:excel生成

添加数据

添加一条数据。其中“模版”字段使用源码中的template.xlsx

开发

开发使用到的库

之前excel预览使用的是sheetjs,这次我们使用另一个比较常用的excel库exceljs。他同样比较受欢迎。当然使用sheetjs也是能实现的。

exceljs也是符合双端规范的一个库。所以他也提供了Browserify的导入方式

cdn地址:https://cdn.jsdelivr.net/npm/exceljs@4.3.0/dist/exceljs.min.js

代码说明

绑定kintone事件

kintone.events.on('app.record.detail.show', (event) => {
  const record = event.record
  const file = record.Template.value
  if (file.length > 0) {
    if (checkXls(file[0].name)) {
      loadDownload(file[0], record)
    }
  }
  return event
})

判断是否为excel文件

const checkXls = (file) => {
  const reg = /\.xl(s[xmb]|t[xm]|am|s)$/g
  return reg.test(file)
}

读入excel模版数据

const readWorkbookFromRemoteFile = async (url, record) => {
  const xhr = new XMLHttpRequest()
  xhr.open('get', url, true)

  xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest')
  xhr.responseType = 'arraybuffer'
  xhr.onload = async (e) => {
    if (xhr.status == 200) {
      const blob = await FillData(xhr, record)
      const a = document.createElement('a')
      const url = window.URL.createObjectURL(blob)
      a.href = url
      a.download = 'new.xlsx'
      a.click()
      window.URL.revokeObjectURL(url)
    }
  }
  xhr.send()
}

将kintone数据转化成exceljs的Workbook对象

const FillData = async (xhr, record) => {
  let data = new Uint8Array(xhr.response)
  const workbook = new ExcelJS.Workbook()
  await workbook.xlsx.load(data)
  const worksheet = workbook.getWorksheet('Sheet1')

  const CustomerNameCell = worksheet.getCell('C4')
  const AddressCell = worksheet.getCell('C7')
  const ContactCell = worksheet.getCell('C6')
  const DepartmentCell = worksheet.getCell('C5')
  const NoteCell = worksheet.getCell('C8')
  const PhoneCell = worksheet.getCell('H6')
  const ReceiveDateCell = worksheet.getCell('H5')
  const SnCell = worksheet.getCell('H4')
  const CreatorCell = worksheet.getCell('B18')
  CustomerNameCell.value = record.CustomerName.value
  AddressCell.value = record.Address.value
  ContactCell.value = record.Contact.value
  DepartmentCell.value = record.Department.value
  NoteCell.value = record.Note.value
  PhoneCell.value = record.Phone.value
  ReceiveDateCell.value = record.ReceiveDate.value
  SnCell.value = record.Sn.value
  CreatorCell.value = record.Creator.value
  let indexLine = 11
  for (const row of record.Table.value) {
    const rowValue = row.value
    const rowMap = {
      0: 'A',
      1: 'D',
      2: 'F',
      3: 'H',
    }
    Object.keys(rowValue).forEach((key, index) => {
      const cellField = rowMap[index] + indexLine
      const cell = worksheet.getCell(cellField)
      cell.value = rowValue[key].value
    })
    indexLine++
  }
  const uint8Array = await workbook.xlsx.writeBuffer()
  const blob = new Blob([uint8Array], {
    type: 'application/octet-binary',
  })
  return blob
}

生成下载按钮,下载excel

const loadDownload = (fileInfo, record) => {
  if (document.getElementById('downloadButton') !== null) {
    return
  }
  const downloadButton = document.createElement('button')
  downloadButton.id = 'downloadButton'
  downloadButton.innerText = '一键生成excel'
  downloadButton.onclick = () => {
    const fileUrl = '/k/v1/file.json?fileKey=' + fileInfo.fileKey
    readWorkbookFromRemoteFile(fileUrl, record)
  }
  kintone.app.record.getHeaderMenuSpaceElement().appendChild(downloadButton)
}

代码下载


注意事项

  • 本示例代码不保证其运行。

  • 我们不为本示例代码提供技术支持。

附件:excel生成.zip • 290.6KB • 下载

附件:template.xlsx • 26.88KB • 下载

回复(2)

  • cnDevNet

    关于excel 模版中vba代码丢失的问题。查询了下,貌似是因为这个excel导出并且重命名导致的。

    “从excel2007开始有了区分,.xlsm是含有VBA代码(宏)的,.xlsx是不含VBA代码(宏)的,默认是.xlsx,如果不想含有代码,可以保存为xlsx,即可自动删除其中VBA代码”

    那样的话可以试下,不改变其后缀扩展名,只是改名字。

    比如对其重命名时,这边只是简单的重命名为“new.xlsx” 而实际上,你可以使用以下代码,将其重命名为“new-”开头加上原来excel模版名的方式来导出。试下是否能解决你的问题。

    1
    2
    const file = record[templateField];
    const newFileName = "new-" + file.value[0].name;

    引用 SAI 的回复:

    谢谢大佬赐教唯一不足的是,excel横版中的vba代码将不会被保留

  • SAI

    谢谢大佬赐教

    唯一不足的是,excel横版中的vba代码将不会被保留