apass-opensdk-hugong
Version:
飞书Apass低代码平台-飞书开放平台-相关的接口整合和常用的方法整合
239 lines (237 loc) • 8.75 kB
JavaScript
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_