UNPKG

apass-opensdk-hugong

Version:

飞书Apass低代码平台-飞书开放平台-相关的接口整合和常用的方法整合

239 lines (237 loc) 8.75 kB
const fs = require('fs') class File_ { #hg = null constructor(hg) { this.#hg = hg } getCurrentTimeFolderName() { const now = new Date(); const year = now.getFullYear(); const month = String(now.getMonth() + 1).padStart(2, '0'); const day = String(now.getDate()).padStart(2, '0'); const hours = String(now.getHours()).padStart(2, '0'); const minutes = String(now.getMinutes()).padStart(2, '0'); const seconds = String(now.getSeconds()).padStart(2, '0'); return `${year}-${month}-${day}_${hours}-${minutes}-${seconds}`; } /** * * 网络下载文件并上传到租户空间 * @param {*} url 网络文件地址 * @param {*} fileName 上传到租户空间的文件名 * @param {*} header 可选 * @returns */ async downloadFileToUpload(url, fileName, header = {}) { this.#hg.log4(`download url=${url}`) const resp = await axios({ url, method: 'get', responseType: 'stream', headers: { ...header } }); // 上传文件获取文件 token const file_info = await application.resources.file.upload(resp.data, fileName); this.#hg.log4('file_info', file_info) return file_info } /** * 下载租户空间的文件到环境tmp目录中 * @param {*} file_info { id, mime_type, name, ...} * @param {*} file_path 存储地址可选,不填写则默认当前时间戳 * @returns */ async downloadFileToTmp(file_info, file_path) { this.#hg.log4(`download input=${JSON.stringify(file_info)}`) const _file_path = file_path || `/tmp/${Date.now()}.${file_info.mime_type}` await application.resources.file.download({ id: file_info.id }, _file_path); this.#hg.log4(`download success, path=` + _file_path) return _file_path } async downloadFileByToeknToTmp(file_info, file_path) { this.#hg.log4(`download input=${JSON.stringify(file_info)}`) const _file_path = file_path || `/tmp/${Date.now()}.${file_info.mime_type}` await application.resources.file.download(file_info.token, _file_path); this.#hg.log4(`download success, path=` + _file_path) return _file_path } /** * 写入文件(默认写入环境tmp目录中) * @param {*} data 写入的内容 * @param {*} fileName 存储地址 */ saveDataToEnv(data, fileName) { fs.writeFileSync(fileName || `${Date.now()}.txt`, JSON.stringify(data), { flag: 'a' }) } /** * 读取csv文件(需要安装依赖:csv-parser) * @param {*} path * @param {*} callback(row) 每一行的回调 * @returns callback为null时,返回全部读取的结果list */ async csvRead(path, callback) { const csv = require('csv-parser'); return await new Promise((resolve, reject) => { const list = [] let index = 0 fs.createReadStream(path).pipe(csv()) .on('data', (row) => { if (callback) { callback(row, index++) } else { list.push(row) } }) .on('end', () => { resolve(list) }) .on('error', () => { reject() }); }) } /** * 读取Excel文件(需要安装依赖:xlsx@0.18.5) * @param {*} filePath * @returns 返回文件内容 */ xlsxReaderAll(filePath) { const XLSX = require('xlsx'); let data = [] try { const buffer = fs.readFileSync(filePath) const workbook = XLSX.read(buffer, { type: 'buffer' }); const sheetName = workbook.SheetNames[0]; this.#hg.log4('Sheet Name:', sheetName); const worksheet = workbook.Sheets[sheetName]; data = XLSX.utils.sheet_to_json(worksheet); this.#hg.log4('Data:', data); } catch (error) { this.#hg.error('xlsxReaderAll - Error parsing Excel file:', error); } return data } /** * 导出数据到 Excel 文件(依赖 exceljs@4.0.1) * @param records 列配置列表,每个对象包含: * @param fields 需要导出的字段名列表(需与 records 中的 key 对应) * - key: 列唯一标识(对应数据字段名) * - header: 列表头显示文本 * - render: (可选) 自定义渲染函数 (value, record) => value * - enums: (可选) 枚举配置 [{ name: [{ language_code, text }], api_alias }] * - type: 列类型(可选 | 'Date' | 'Float' | 'Region') * @param fileName 导出的文件名(可选 | 导出文件.xlsx) * @param sheetName 工作表名称(可选 | Sheet 1) * @returns 导出的文件信息 */ async exportExcelFile(records, fields, fileName = '导出文件.xlsx', sheetName = 'Sheet 1') { const ExcelJS = require('exceljs'); const excelRecords = await this.exportExcelData(records, fields) const workbook = new ExcelJS.Workbook(); const worksheet = workbook.addWorksheet(sheetName); worksheet.columns = fields.map(it => ({ ...((({ enums, type, render, width, ...obj }) => ({ ...obj, width: width || 25 }))(it)) })) excelRecords?.forEach(item => worksheet.addRow(item)); worksheet.getRow(1).font = { bold: true }; worksheet.getRow(1).height = 40; worksheet.eachRow({ includeEmpty: false }, (row, rowNumber) => { if (rowNumber == 1) { row.eachCell(function (Cell, cellNum) { if (cellNum <= worksheet.columns.length) { Cell.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFF5F6F7' }, } } }) } else { row.height = 22 } }) const filePath = `/tmp/${Date.now()}.xlsx` await workbook.xlsx.writeFile(filePath); const file = await application.resources.file.upload(filePath, 60 * 60, fileName) this.#hg.log4('file upload success', file); return file } /** * 导出数据到 Excel 格式 前置处理 * @param records 导出的记录 * @param fields 需要导出的字段名列表(需与 records 中的 key 对应) * - key: 列唯一标识(对应数据字段名) * - header: 列表头显示文本 * - render: (可选) 自定义渲染函数 (value, record) => value * - enums: (可选) 枚举配置 [{ name: [{ language_code, text }], api_alias }] * - type: 列类型(可选 | 'Date' | 'Float' | 'Region') * @returns 导出的 Excel 数据(Buffer) */ async exportExcelData(records, fields) { const toText = (arr) => { return (arr.find(it => it.language_code == '2052') || {}).text || '' } const converToDate = (timestamp, format = 'YYYY-MM-DD HH:mm:ss') => { if (!timestamp || typeof timestamp !== 'number') { return ''; } const date = new Date(timestamp); if (isNaN(date.getTime())) { return ''; } const padZero = (num) => String(num).padStart(2, '0'); const formatMap = { 'YYYY': date.getFullYear(), 'MM': padZero(date.getMonth() + 1), 'DD': padZero(date.getDate()), 'HH': padZero(date.getHours()), 'mm': padZero(date.getMinutes()), 'ss': padZero(date.getSeconds()) }; return format.replace(/YYYY|MM|DD|HH|mm|ss/g, (match) => formatMap[match]); }; const converToFloat = (text) => { try { return parseFloat(text || '0') } catch (error) { return text } } const covetToRegion = data => { if (!data || !data.fullPath) { return '' } return toText(data.fullPath) } for (const record of records) { for (const key of Object.keys(record)) { try { const extfields = fields.find(it => it.key == key) if (!extfields) { continue } if (!record[key]) { record[key] = extfields?.default || '' continue } if (extfields?.render && extfields?.render instanceof Function) { record[key] = await extfields?.render(record[key], record) continue } if (extfields?.enums) { record[key] = toText((extfields.enums?.find(it => it.api_alias == record[key]) || {}).name || []) continue } if (extfields.type) { if (extfields.type == 'Date') { record[key] = converToDate(record[key], extfields.format) } if (extfields.type == 'Float') { record[key] = converToFloat(record[key]) } if (extfields.type == 'Region') { record[key] = covetToRegion(record[key]) } } } catch (error) { this.#hg.warn('exportExcelData - Error processing record:', error, record) } } } this.#hg.log4('exportExcelData success', records); return records } } module.exports = File_