import fs from 'fs';// npm i fs-extra import path from 'path'; import axios from 'axios';// 确保 axios 已安装 import FormData from 'form-data';// 确保 form-data 已安装 const { BrowserWindow, dialog } = require('electron'); const Store = require("electron-store"); const store = new Store(); const os = require('os'); function getIPAddress() { const networkInterfaces = os.networkInterfaces(); for (const name of Object.keys(networkInterfaces)) { for (const net of networkInterfaces[name]) { // IPv4且未被内部使用 if (net.family === 'IPv4' && !net.internal) { return net.address; } } } return null; // 如果没有找到合适的IP地址 } const userDataPath = process.cwd(); const configPath = path.join(userDataPath, 'config.json'); let latestMTime = 0 let checkTimeout = null function showMessage(message, title = '提示') { dialog.showMessageBox({ type: 'info', // 可以是 'none', 'info', 'error', 'question' 或 'warning' title: title, message: message, buttons: [] // 自定义按钮文本 }).then(result => { console.log(result.response); // '0' 表示第一个按钮,以此类推 }).catch(err => { console.log(err); }); } // 读取配置文件 function loadConfig() { try { const data = fs.readFileSync(configPath, 'utf8'); return JSON.parse(data); } catch (error) { console.error('Error loading config:', error); return {}; // 或者返回一个默认配置对象 } } // 日志文件路径 const cwd = process.cwd(); //获取项目的根目录 const logFilePath = path.join(cwd, 'api.log'); // 函数:写入日志 function logApiCall(data) { const logEntry = `[${new Date().toLocaleString()}] ${data}\n`; fs.appendFile(logFilePath, logEntry, (err) => { if (err) { console.error('写入日志时出错:', err); } }); } export const uploadLatestFile = async (id) => { // const cwd = process.cwd(); //获取项目的根目录 // 获取文件夹下所有文件 let dataJson = loadConfig() let directoryPath = path.join(`${dataJson.device.filePathDisc}:`, dataJson.device.file_path); let fileExt = null let oldPath = null let newPath = null // const directoryPath = path.join(`C:`, '检测记录'); const files = fs.readdirSync(directoryPath); // 3. 获取文件元数据并记录修改时间 const filesWithStats = files .map(fileName => { const filePath = path.join(directoryPath, fileName); return { name: fileName, stats: fs.statSync(filePath) }; }) .filter(item => item.stats.isFile() || item.stats.isDirectory()); // 可选:过滤有效项 if (filesWithStats.length === 0) { logApiCall("上传目录为空,无文件可上传"); store.set('key', 'error'); return; } const latestFile = filesWithStats.reduce((prev, current) => { // 使用 mtimeMs(毫秒时间戳)确保精度 return current.stats.mtimeMs > prev.stats.mtimeMs ? current : prev; }); // 获取最新文件 // const latestFile = files.sort((a, b) => b.mtime - a.mtime)[0]; const stats = fs.statSync(path.join(directoryPath, latestFile.name)); if (stats.isFile()) {//文件处理 fileExt = path.extname(latestFile.name); // 正确获取扩展名(包含点) oldPath = latestFile.name; // newPath = `${latestFile.name}`;//不修改文件名 newPath = `${id}${fileExt}`;//修改文件名 } else if (stats.isDirectory()) {//文件夹处理 directoryPath = path.join(`${dataJson.device.filePathDisc}:`, `${dataJson.device.file_path}/${latestFile.name}`); const filess = fs.readdirSync(directoryPath); const filesWithStatss = filess.map(fileName => { const filePath = path.join(directoryPath, fileName); return { name: fileName, stats: fs.statSync(filePath) // 获取文件状态 }; }); const latestFiles = filesWithStatss.reduce((prev, current) => { // 使用 mtimeMs(毫秒时间戳)确保精度 return current.stats.mtimeMs > prev.stats.mtimeMs ? current : prev; }); let fileExts = path.extname(latestFiles.name); // 正确获取扩展名(包含点) oldPath = latestFiles.name; // newPath = `${latestFiles.name}`; 不修改文件名 newPath = `${id}${fileExts}`; //修改文件名 } logApiCall(`重命名之前的文件: ${path.join(directoryPath, oldPath)},${path.join(directoryPath, newPath)}`); fs.renameSync(path.join(directoryPath, oldPath), path.join(directoryPath, newPath)) // logApiCall(`获取文件信息: ${JSON.stringify(fs.createReadStream(path.join(directoryPath, newPath)))}`); try { // // 采用form-data 的方式上传 const formData = new FormData(); formData.append( 'file', fs.readFileSync(path.join(directoryPath, newPath)), ); formData.append('deviceId', dataJson.device.code); formData.append('orderNumber', id); formData.append('deviceModel', dataJson.device.codeType); logApiCall(`上传路径: ${path.join(directoryPath, newPath)}`); logApiCall(`上传接口: ${dataJson.device.address}/upper/parsing`); logApiCall(`上传参数: ${JSON.stringify(formData)}`); // 上传文件 const result = await axios.post( 'http://49.232.74.228:80/blade-resource/oss/endpoint/put-file-attach', formData, { headers: { ...formData.getHeaders(), }, }, ) logApiCall(`上传返回: ${JSON.stringify(result)}`); if (result.data.msg == '操作成功') { store.set('key', 'success'); store.set('resultDate', JSON.stringify(result.data)); } else { logApiCall(`上传失败1: ${JSON.stringify(result)}`); store.set('key', 'error'); } } catch (error) { store.set('key', 'error'); const errorMsg = error.response ? JSON.stringify(error.response.data) : error.message || 'Unknown error'; logApiCall(`请求失败2: ${errorMsg}`); } }; // 记录已上传的文件,避免重复上传(模块级变量,所有调用共享) let uploadedFiles = new Set(); // 防止多次调用导致多个循环 let isWatching = false; // 监控文件夹上传 export const watchUploadLatestFile = async (id) => { // 如果已经在监控,直接返回 if (isWatching) { logApiCall("监控已在运行,跳过重复调用"); return; } isWatching = true; store.set("key", "error"); let dataJson = loadConfig(); let directoryPath = path.join( `${dataJson.device.filePathDisc}:`, dataJson.device.file_path, ); // 获取文件夹中最新文件的函数 const getLatestFile = () => { try { const files = fs.readdirSync(directoryPath); if (files.length === 0) { return null; // 文件夹为空 } // 获取所有文件的状态并找到最新的 const filesWithStats = files .map((fileName) => { const filePath = path.join(directoryPath, fileName); try { const stats = fs.statSync(filePath); return { name: fileName, path: filePath, mtimeMs: stats.mtimeMs, size: stats.size, }; } catch (error) { console.error(`无法获取文件状态: ${fileName}`, error); return null; } }) .filter(Boolean); // 过滤掉无法获取状态的文件 if (filesWithStats.length === 0) { return null; // 没有有效文件 } // 找到修改时间最新的文件 const latestFile = filesWithStats.reduce((prev, current) => { return current.mtimeMs > prev.mtimeMs ? current : prev; }); return latestFile; } catch (error) { console.error("读取文件夹失败:", error); return null; } }; // 获取初始文件列表 let previousFiles = new Set(fs.readdirSync(directoryPath)); // 延迟函数 const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); // 使用 while 循环替代 setInterval while (true) { try { const currentFiles = new Set(fs.readdirSync(directoryPath)); const currentLatestFile = getLatestFile(); logApiCall(`循环读取新文件: ${Array.from(currentFiles)}`); logApiCall(`之前状态文件: ${Array.from(previousFiles)}`); // 检查是否有新增文件 const newFiles = Array.from(currentFiles).filter( (file) => !previousFiles.has(file), ); logApiCall(`新增文件: ${newFiles}`); if (newFiles.length > 0 && currentLatestFile) { logApiCall(`发现新增文件: ${newFiles.join(", ")}`); // 只上传最新文件,且确保该文件未被上传过 if (!uploadedFiles.has(currentLatestFile.name)) { logApiCall( `标记已上传的文件列表: ${JSON.stringify(Array.from(uploadedFiles))}`, ); // 标记为已上传 uploadedFiles.add(currentLatestFile.name); logApiCall( `添加后的文件列表: ${JSON.stringify(Array.from(uploadedFiles))}`, ); // 上传最新的文件 await watchUpload(currentLatestFile, id); } else { logApiCall(`文件 ${currentLatestFile.name} 已经上传过,跳过`); } } else if (!currentLatestFile) { logApiCall("文件夹中没有文件"); } else { logApiCall("没有新增文件"); } // 更新文件列表 previousFiles = currentFiles; } catch (error) { logApiCall(`检查文件夹时出错: ${error.message}`); } // 等待指定时间后再进行下一次检查 await sleep(dataJson.device.reconnect_time * 2000); } }; // 上传最新文件的函数 async function watchUpload(latestFile, id) { const filePath = latestFile.path; let dataJson = loadConfig(); try { logApiCall(`开始上传最新文件: ${filePath}`); // 采用form-data的方式上传 const formData = new FormData(); formData.append("file", fs.createReadStream(filePath)); formData.append("deviceId", dataJson.device.code); formData.append("orderNumber", id); formData.append("deviceModel", dataJson.device.codeType); // logApiCall(`上传formData: ${JSON.stringify(formData)}`); logApiCall(`上传路径: ${filePath}`); logApiCall(`上传接口: ${dataJson.device.address}/upper/send`); // 上传文件 const result = await axios.post( dataJson.device.address + "/upper/send", formData, { headers: { ...formData.getHeaders(), }, }, ); logApiCall(`上传返回: ${JSON.stringify(result.data)}`); if (result.data.msg == "操作成功") { // showMessage(`文件 ${latestFile.name} 上传成功`); store.set("key", "success"); } else { store.set("key", "success"); // showMessage(`文件 ${latestFile.name} 上传失败: ${result.data.msg}`); } } catch (error) { store.set("key", "success"); // showMessage(`文件 ${latestFile.name} 上传失败: ${JSON.stringify(error)}`); logApiCall(`请求失败: ${JSON.stringify(error)}`); } } // 停止监听的函数 export const stopFileWatching = () => { if (checkTimeout) { clearInterval(checkTimeout); console.log('文件夹监听已停止'); } } // 监控文件上传并获取解析之后的数据 export const watchUploadLatestAnalysisFile = async (id) => { store.set('key', ''); let newPath = null let fileExt = null let dataJson = loadConfig() let directoryPath = path.join(`${dataJson.device.filePathDisc}:`, dataJson.device.file_path); const files = fs.readdirSync(directoryPath) // 遍历所有文件获取最新修改时间 const filesWithStats = files.map(fileName => { const filePath = path.join(directoryPath, fileName); return { name: fileName, stats: fs.statSync(filePath) // 获取文件状态 }; }); const latestFile = filesWithStats.reduce((prev, current) => { // 使用 mtimeMs(毫秒时间戳)确保精度 return current.stats.mtimeMs > prev.stats.mtimeMs ? current : prev; }); // 获取最新文件 const stats = fs.statSync(path.join(directoryPath, latestFile.name)); let newLatestMTime = stats.mtimeMs latestMTime = stats.mtimeMs //获取最新的以此上传文件的时间 fileExt = path.extname(latestFile.name); // 正确获取扩展名(包含点) newPath = `${latestFile.name}`; checkTimeout = setInterval(async () => { logApiCall(`上传文件解析修改日期开始:${newLatestMTime} 上传文件解析最新修改:${latestMTime}`); if (newLatestMTime == latestMTime) { // 遍历所有文件获取最新修改时间 let newStats = fs.statSync(path.join(directoryPath, latestFile.name)); newLatestMTime = newStats.mtimeMs logApiCall(`上传文件解析未被修改过: ${path.join(directoryPath, newPath)}`); console.log('上传文件解析未被修改过', directoryPath) } else { clearTimeout(checkTimeout) logApiCall(`上传文件解析被修改过: ${path.join(directoryPath, newPath)}`); console.log('上传文件解析被修改过', directoryPath) // 采用form-data 的方式上传 const formData = new FormData(); formData.append( 'file', fs.createReadStream(path.join(directoryPath, newPath)), ); formData.append('deviceId', dataJson.device.code); formData.append('orderNumber', id); formData.append('deviceModel', dataJson.device.codeType); logApiCall(`上传文件解析路径: ${path.join(directoryPath, newPath)}`); logApiCall(`上传文件解析内容: ${JSON.stringify(formData)}`); logApiCall(`上传文件解析接口: ${dataJson.device.address}/upper/parsing`); // 上传文件 try { const result = await axios.post( dataJson.device.address + '/upper/parsing', formData, { headers: { ...formData.getHeaders(), }, }, ) logApiCall(`上传返回: ${JSON.stringify(result.data)}`); if (result.data.msg == '操作成功') { // showMessage('上传成功'); store.set('key', 'success'); store.set('resultDate', JSON.stringify(result.data)); // resolve(`文件上传成功`); } else { // reject(new Error(`上传失败${result.data.msg}`)); // store.set('key', 'error'); store.set('key', 'error'); // showMessage(`上传失败${result.data.msg}`); } } catch (error) { // store.set('key', 'error'); store.set('key', 'error'); // showMessage(`上传失败${JSON.stringify(error)}`); logApiCall(`请求失败: ${JSON.stringify(error)}`); } } }, dataJson.device.reconnect_time * 1000) // }) }