const dayjs = require('dayjs'); exports.generateRandomString = (length) => { const characters = "0123456789abcdefghijklmnopqrstuvwxyz"; let result = ""; const charactersLength = characters.length; for (let i = 0; i < length; i++) { const randomIndex = Math.floor(Math.random() * charactersLength); result += characters[randomIndex]; } return `${result}${Date.now()}`; }; /** * 生成唯一字符串 * @param {*} prefix 唯一字符串前缀 * @param {*} len 补充字符串长度 * @description 总长度 = prefix.length + 固定15 (当前时间的长度 YYMMDDHHmmssSSS格式) + 补充字符串的长度 */ exports.generateUniqueStr = (prefix = '', len = 6) => { const dateStamp = dayjs().format('YYMMDDHHmmssSSS'); const groups = Math.ceil(len / 4); // 4个字符串一组 const suffix = new Array(groups).fill(1).map((_, idx) => { const exponent = Math.min(4, len - idx * 4); const str = Math.floor(Math.random() * (10 ** exponent)).toString().padStart(exponent, '0'); return str; }).join(''); return `${prefix}${dateStamp}${suffix}`; } exports.getAttachments = (fileList, sopTaskId, executeUserId) => { if (!Array.isArray(fileList)) return []; return fileList.map((item) => { let { type, mediaId, file, URL } = item; let { subtitle, name, url, type: fileType } = file; let attachment = {}; if (type === "image") { attachment = { msgtype: type, title: name, image: { media_id: mediaId, }, }; } else if (type === "video") { attachment = { msgtype: type, title: name, video: { media_id: mediaId, }, }; } else if (type === "link") { attachment = { msgtype: type, title: name, linkType: fileType || "", link: { title: name, picurl: URL, desc: subtitle, url: fileType === "questionnaire" ? `${url}&id=${sopTaskId}&source=sop&userId=${executeUserId}` : url, }, }; } return attachment; }); }; /** * 批量执行任务,控制最大并发数 * @param {Array} items - 待处理的任务参数列表 * @param {Function} taskFn - 单个任务的处理函数,需返回 Promise * @param {number} maxConcurrency - 最大并发数 * @returns {Promise} - 返回所有任务的结果 */ exports.executeWithConcurrency = async (items, taskFn, maxConcurrency) => { let index = 0; const results = []; while (index < items.length) { // 获取当前批次 const batch = items.slice(index, index + maxConcurrency); // 映射当前批次的任务并执行 const promises = batch.map((item) => taskFn(item)); // 等待当前批次的任务完成 const batchResults = await Promise.all(promises); // 收集结果 results.push(...batchResults); // 更新索引 index += maxConcurrency; } return results; };