| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181 |
- import { getMainWindow } from "ee-core/electron";
- import { app, dialog, shell } from "electron";
- import { logger } from "ee-core/log";
- import path from "path";
- import fs from "fs";
- import http from "http";
- import https from "https";
- import FormData from "form-data";
- class Os {
- async minimizeWindow() {
- getMainWindow().minimize();
- }
- async maximizeWindow() {
- getMainWindow().maximize();
- }
- async unmaximizeWindow() {
- getMainWindow().unmaximize();
- }
- async closeWindow() {
- getMainWindow().close();
- }
- async isMaximized() {
- return getMainWindow().isMaximized();
- }
- async toggleDevTools() {
- getMainWindow().webContents.toggleDevTools();
- }
- async openUserDataFolder() {
- const userDataPath = app.getPath('userData');
- await shell.openPath(userDataPath);
- }
- async openInstallFolder() {
- const exePath = app.getPath('exe');
- const installDir = path.dirname(exePath);
- await shell.openPath(installDir);
- }
- async selectDirectory() {
- const win = getMainWindow();
- const result = await dialog.showOpenDialog(win, {
- title: '选择目录',
- properties: ['openDirectory', 'createDirectory'],
- });
- if (result.canceled || !result.filePaths || result.filePaths.length === 0) {
- return '';
- }
- return result.filePaths[0];
- }
- async getAppInfo() {
- return {
- version: app.getVersion(),
- name: app.getName(),
- electronVersion: process.versions.electron,
- chromeVersion: process.versions.chrome,
- nodeVersion: process.versions.node,
- platform: process.platform,
- arch: process.arch,
- userDataPath: app.getPath('userData'),
- exePath: app.getPath('exe'),
- };
- }
- async openExternal(url) {
- if (!url || typeof url !== 'string') return false;
- try {
- await shell.openExternal(url);
- return true;
- } catch (e) {
- logger.error('[os] openExternal failed:', e);
- return false;
- }
- }
- /**
- * 通过 Node.js 主进程流式上传清鉴数据源文件
- * - 校验选中目录最后一级必须为 QingJian
- * - 在 QingJian 目录下拼接 workspace 作为扫描根
- * - 扫描 workspace 下一层文件夹,再读取每个文件夹下的文件(不递归更深层)
- * - 用 fs.createReadStream 流式读取,避免大文件占内存
- * - 用 form-data 构建 multipart,http/https 模块发送
- * @param params.dirPath 目录完整磁盘路径(最后一级必须为 QingJian)
- * @param params.uploadUrl 后端接口完整 URL
- * @param params.token 鉴权 token(可选)
- */
- async uploadQingJianFiles(params) {
- logger.info('[os] uploadQingJianFiles params:', params);
- const { dirPath, uploadUrl, token } = params || {};
- if (!dirPath || !uploadUrl) {
- logger.error('[os] uploadQingJianFiles params missing:', params);
- throw new Error('请选择 QingJian 目录');
- }
- // 1. 校验选中目录最后一级必须为 QingJian
- const dirName = path.basename(dirPath);
- if (dirName !== 'QingJian') {
- throw new Error('请选择 QingJian 目录');
- }
- // 2. 在选中目录下拼接 workspace,作为扫描根目录
- const workspacePath = path.join(dirPath, 'workspace');
- const platPath = path.join(dirPath, 'db',"plat");
- // 3. 扫描 workspace 下一层文件夹,再读取每个文件夹下的文件(不递归更深层)
- // id = 文件直接所在的父级目录名(即子文件夹名)
- const subEntries = await fs.promises.readdir(workspacePath, { withFileTypes: true });
- const subDirs = subEntries.filter(e => e.isDirectory());
- if (subDirs.length === 0) {
- throw new Error('workspace 目录下没有子文件夹');
- }
- const files = [];
- for (const sub of subDirs) {
- const subDirPath = path.join(workspacePath, sub.name);
- const subFiles = await fs.promises.readdir(subDirPath, { withFileTypes: true });
- for (const f of subFiles) {
- if (f.isFile()) {
- files.push({ id: sub.name, name: f.name, filePath: path.join(subDirPath, f.name) });
- }
- }
- }
- files.push({ id: 'plat', name: 'plat', filePath: platPath });
- if (files.length === 0) {
- throw new Error('workspace 的子文件夹下没有可上传的文件');
- }
- // 4. 构建 multipart FormData
- const form = new FormData();
- form.append('path', dirPath);
- for (let i = 0; i < files.length; i++) {
- const { id, name: fileName, filePath } = files[i];
- const stream = fs.createReadStream(filePath);
- form.append(`items[${i}].file`, stream, { filename: fileName });
- form.append(`items[${i}].name`, fileName);
- form.append(`items[${i}].id`, id);
- }
- // 3. 发送 HTTP 请求(流式 pipe,不占内存)
- return await new Promise((resolve, reject) => {
- const urlObj = new URL(uploadUrl);
- const lib = urlObj.protocol === 'https:' ? https : http;
- const headers = form.getHeaders();
- if (token) {
- headers['Authorization'] = token;
- }
- const req = lib.request(uploadUrl, {
- method: 'POST',
- headers,
- }, (res) => {
- let data = '';
- res.setEncoding('utf8');
- res.on('data', (chunk) => { data += chunk; });
- res.on('end', () => {
- const status = res.statusCode || 0;
- if (status >= 200 && status < 300) {
- try {
- resolve(JSON.parse(data));
- } catch {
- resolve(data);
- }
- } else {
- reject(new Error(`HTTP ${status}: ${data}`));
- }
- });
- });
- req.on('error', (e) => {
- logger.error('[os] uploadQingJianFiles request error:', e);
- reject(e.message);
- });
- form.pipe(req);
- });
- }
- }
- Os.toString = () => 'Os';
- export const os = new Os();
|