'use strict'; const _ = require('lodash'); const path = require('path'); const { Controller } = require('ee-core'); const { app: electronApp, dialog, shell, Notification, powerMonitor, screen, nativeTheme } = require('electron'); const Conf = require('ee-core/config'); const Ps = require('ee-core/ps'); const Services = require('ee-core/services'); const Addon = require('ee-core/addon'); const { getNetworkIFaceOne, getMac, getAllMac, getAllPhysicsMac } = require('@lzwme/get-physical-address'); const os = require('os'); const shutdown = require('electron-shutdown-command'); // 终端命令 const { exec, execSync, execFile } = require("child_process"); // 声音控制库 https://github.com/LinusU/node-loudness const loudness = require("loudness"); // 文件处理 const fs = require('fs'); /** * 操作系统 - 功能demo * @class */ class OsController extends Controller { constructor(ctx) { super(ctx); } /** * 所有方法接收两个参数 * @param args 前端传的参数 * @param event - ipc通信时才有值。详情见:控制器文档 */ // 获取所有的网卡-无参数 async getAllMac(args) { // 文档说明 https://github.com/lzwme/get-physical-address/blob/main/.github/README_zh-CN.md const list = getAllPhysicsMac(); return list; } // 查找到指定进程并关闭? 注意 进程要全, 不然容易误杀 deviceKillName(name) { // 最新 taskkill /F /IM program.exe 这个命令一句话能直接杀掉进程 const self = this; let rebootShell = "tasklist|findstr " + name; let command = exec(rebootShell, function (err, stdout, stderr) { if (err || stderr) { console.log("tasklist failed" + err + stderr); } else { const lines = stdout.split('\n') console.log(lines); for (let index = 0; index < lines.length; index++) { const element = lines[index]; const strs = element.split(' ') const firstNumber = strs.find(item => !isNaN(Number(item)) && item != '') console.log('jincheng id :' + firstNumber); self.deviceKillPid(firstNumber) } } }); command.stdin.end(); command.on("close", function (code) { console.log("tasklist", code); }); } // 杀掉pid 进程 deviceKillPid(pid) { let rebootShell = "tskill " + pid; let command = exec(rebootShell, function (err, stdout, stderr) { if (err || stderr) { console.log("tskill failed" + err + stderr); } }) command.stdin.end(); command.on("close", function (code) { console.log("tskill", code); }); } // 启动指定目录的程序 可能有权限问题, 方案1 打包后管理员权限执行, 2 按照egg 的方案把需要执行的程序拷贝到安装包 deviceStarExe(path) { let rebootShell = 'start ' + path; exec(rebootShell); } /** * 设备关机 */ deviceShutdown() { // 关机 // let shutdownShell = "shutdown -s -t 00"; console.log('deviceShutdown=============') shutdown.shutdown(); return true; } deviceRestart(args) { // 重启 let rebootShell = "shutdown -r -t 0"; let command = exec(rebootShell, function (err, stdout, stderr) { if (err || stderr) { console.log("shutdown failed" + err + stderr); } }); command.stdin.end(); command.on("close", function (code) { console.log("shutdown", code); }); } // 同步执行 声音设置 支持0-100 async deviceLoudness(args) { const value = args.value; //操作系统平台 const pf = os.platform(); console.log("OS: " + pf) // 特殊处理以下 if (pf == "linux") { let shellStr = "amixer -D pulse set Master " + value + "% unmute" if (value == 0) { shellStr = "amixer -D pulse set Master mute" } // else{ // shellStr = "amixer -c 0 set Master,0 100%,80% unmute" // } let command = exec(shellStr, function (err, stdout, stderr) { if (err || stderr) { console.log("amixer failed" + err + stderr); } }); command.stdin.end(); command.on("close", function (code) { console.log("amixer", code); }); return; } else { /// 兼容模式, try catch 如果第一种方式报错, 在采用第二种 try { //0 为静音 if (value == 0) { await loudness.setMuted(true) return await loudness.getMuted() } // 设置声音改为不静音 且设置声音 await loudness.setMuted(false) await loudness.setVolume(value) const newValue = await loudness.getVolume(); return newValue; } catch { const maxVolume = 65535; let volumeValue = Math.round((value / 100) * maxVolume); // 确保音量值在有效范围内 volumeValue = Math.max(0, Math.min(maxVolume, volumeValue)); // 将音量值转换为字符串 const valueStr = volumeValue.toString(); let excPath = path.join(Ps.getExtraResourcesDir(), 'nircmd.exe'); execFile(excPath, ['setsysvolume', valueStr], (error, stdout, stderr) => { if (error) { console.error(' Nircmd error: ', error); return; } console.log('Nircmd ok '); }); return value; } } } // 获取电脑信息 async getOSMessage(args) { var OSDic = {}; var dealTime = (seconds) => { var seconds = seconds | 0; var day = (seconds / (3600 * 24)) | 0; var hours = ((seconds - day * 3600) / 3600) | 0; var minutes = ((seconds - day * 3600 * 24 - hours * 3600) / 60) | 0; var second = seconds % 60; (day < 10) && (day = '0' + day); (hours < 10) && (hours = '0' + hours); (minutes < 10) && (minutes = '0' + minutes); (second < 10) && (second = '0' + second); return [day, hours, minutes, second].join(':'); }; var dealMem = (mem) => { var G = 0, M = 0, KB = 0; (mem > (1 << 30)) && (G = (mem / (1 << 30)).toFixed(2)); (mem > (1 << 20)) && (mem < (1 << 30)) && (M = (mem / (1 << 20)).toFixed(2)); (mem > (1 << 10)) && (mem > (1 << 20)) && (KB = (mem / (1 << 10)).toFixed(2)); return G > 0 ? G + 'G' : M > 0 ? M + 'M' : KB > 0 ? KB + 'KB' : mem + 'B'; }; //cpu架构 const arch = os.arch(); // console.log("cpu架构:" + arch); OSDic["arch"] = arch; //操作系统内核 const kernel = os.type(); // console.log("操作系统内核:" + kernel); OSDic["kernel"] = kernel; //操作系统平台 const pf = os.platform(); // console.log("平台:" + pf); OSDic["pf"] = pf; //系统开机时间 const uptime = os.uptime(); // console.log("开机时间:" + dealTime(uptime)); OSDic["uptime"] = uptime; //主机名 const hn = os.hostname(); // console.log("主机名:" + hn); OSDic["hostname"] = hn; // //主目录 // const hdir = os.homedir(); // console.log("主目录:" + hdir); // OSDic["homedir"] = hdir; //内存 const totalMem = os.totalmem(); const freeMem = os.freemem(); // console.log("内存大小:" + dealMem(totalMem) + ' 空闲内存:' + dealMem(freeMem)); OSDic["totalmem"] = totalMem; OSDic["freeMem"] = freeMem; //cpu const cpus = os.cpus(); OSDic["cpuModel"] = cpus[0]["model"]; // OSDic["cpus"] = cpus; // console.log('*****cpu信息*******'); // cpus.forEach((cpu, idx, arr) => { // var times = cpu.times; // console.log(`cpu${idx}:`); // console.log(`型号:${cpu.model}`); // console.log(`频率:${cpu.speed}MHz`); // console.log(`使用率:${((1 - times.idle / (times.idle + times.user + times.nice + times.sys + times.irq)) * 100).toFixed(2)}%`); // }); try { const volumeValue = await loudness.getVolume() OSDic["volume"] = volumeValue; console.log('volumeValue' + volumeValue); } catch (error) { console.log(error) } return OSDic; } // const volume = await loudness.getVolume() // OSDic["volume"] = volume; // return OSDic; // } /** * 获取当前目录的配置 * @param {*} name 配置文件名 * @returns */ getCurrentDirectoryConfig(name) { let configPath = ''; configPath = path.join(Ps.getExtraResourcesDir(), name); console.log(configPath) // let configJSON = null; let dataString = null; try { // 同步读取配置文件 dataString = fs.readFileSync(configPath, 'utf8'); // 解析 JSON 格式的配置数据 // configJSON = JSON.parse(data); // console.log('读取到的配置:', configJSON); // 在这里可以根据需要使用配置数据进行操作 } catch (err) { console.error('无法读取配置文件:', err); } return dataString; } /** * 消息提示对话框 */ messageShow() { dialog.showMessageBoxSync({ type: 'info', // "none", "info", "error", "question" 或者 "warning" title: '自定义标题-message', message: '自定义消息内容', detail: '其它的额外信息' }) return '打开了消息框'; } /** * 消息提示与确认对话框 */ messageShowConfirm() { const res = dialog.showMessageBoxSync({ type: 'info', title: '自定义标题-message', message: '自定义消息内容', detail: '其它的额外信息', cancelId: 1, // 用于取消对话框的按钮的索引 defaultId: 0, // 设置默认选中的按钮 buttons: ['确认', '取消'], // 按钮及索引 }) let data = (res === 0) ? '点击确认按钮' : '点击取消按钮'; return data; } /** * 选择目录 */ selectFolder() { const filePaths = dialog.showOpenDialogSync({ properties: ['openDirectory', 'createDirectory'] }); if (_.isEmpty(filePaths)) { return null } return filePaths[0]; } /** * 打开目录 */ openDirectory(args) { if (!args.id) { return false; } let dir = ''; if (path.isAbsolute(args.id)) { dir = args.id; } else { dir = electronApp.getPath(args.id); } shell.openPath(dir); return true; } /** * 选择图片 */ selectPic() { const filePaths = dialog.showOpenDialogSync({ title: 'select pic', properties: ['openFile'], filters: [ { name: 'Images', extensions: ['jpg', 'png', 'gif'] }, ] }); if (_.isEmpty(filePaths)) { return null } return filePaths[0]; } /** * 加载视图内容 */ loadViewContent(args) { const { type, content } = args; let contentUrl = content; if (type == 'html') { contentUrl = path.join('file://', electronApp.getAppPath(), content); } Services.get('os').createBrowserView(contentUrl); return true } /** * 移除视图内容 */ removeViewContent() { Services.get('os').removeBrowserView(); return true } /** * 打开新窗口 */ createWindow(args) { const { type, content, windowName, windowTitle } = args; let contentUrl = null; if (type == 'html') { contentUrl = path.join('file://', electronApp.getAppPath(), content) } else if (type == 'web') { contentUrl = content; } else if (type == 'vue') { let addr = 'http://localhost:17680' if (Ps.isProd()) { const mainServer = Conf.getValue('mainServer'); if (Conf.isFileProtocol(mainServer)) { addr = mainServer.protocol + path.join(Ps.getHomeDir(), mainServer.indexPath); } else { addr = mainServer.protocol + mainServer.host + ':' + mainServer.port; } } contentUrl = addr + content; } else { // some } console.log('contentUrl: ', contentUrl); let opt = { title: windowTitle } const win = Addon.get('window').create(windowName, opt); const winContentsId = win.webContents.id; // load page win.loadURL(contentUrl); return winContentsId; } /** * 获取窗口contents id */ getWCid(args) { // 主窗口的name默认是main,其它窗口name开发者自己定义 const name = args; const id = Addon.get('window').getWCid(name); return id; } /** * 加载扩展程序 */ // async loadExtension (args) { // const crxFile = args[0]; // if (_.isEmpty(crxFile)) { // return false; // } // const extensionId = path.basename(crxFile, '.crx'); // const chromeExtensionDir = chromeExtension.getDirectory(); // const extensionDir = path.join(chromeExtensionDir, extensionId); // Log.info("[api] [example] [loadExtension] extension id:", extensionId); // unzip(crxFile, extensionDir).then(() => { // Log.info("[api] [example] [loadExtension] unzip success!"); // chromeExtension.load(extensionId); // }); // return true; // } /** * 创建系统通知 */ sendNotification(args, event) { const { title, subtitle, body, silent } = args; if (!Notification.isSupported()) { return '当前系统不支持通知'; } let options = {}; if (!_.isEmpty(title)) { options.title = title; } if (!_.isEmpty(subtitle)) { options.subtitle = subtitle; } if (!_.isEmpty(body)) { options.body = body; } if (!_.isEmpty(silent)) { options.silent = silent; } Services.get('os').createNotification(options, event); return true } /** * 电源监控 */ initPowerMonitor(args, event) { const channel = 'controller.os.initPowerMonitor'; powerMonitor.on('on-ac', (e) => { let data = { type: 'on-ac', msg: '接入了电源' } event.reply(`${channel}`, data) }); powerMonitor.on('on-battery', (e) => { let data = { type: 'on-battery', msg: '使用电池中' } event.reply(`${channel}`, data) }); powerMonitor.on('lock-screen', (e) => { let data = { type: 'lock-screen', msg: '锁屏了' } event.reply(`${channel}`, data) }); powerMonitor.on('unlock-screen', (e) => { let data = { type: 'unlock-screen', msg: '解锁了' } event.reply(`${channel}`, data) }); return true } /** * 获取屏幕信息 */ getScreen(args) { let data = []; let res = {}; if (args == 0) { let res = screen.getCursorScreenPoint(); data = [ { title: '横坐标', desc: res.x }, { title: '纵坐标', desc: res.y }, ] return data; } if (args == 1) { res = screen.getPrimaryDisplay(); } if (args == 2) { let resArr = screen.getAllDisplays(); // 数组,只取一个吧 res = resArr[0]; } // Log.info('[electron] [ipc] [example] [getScreen] res:', res); data = [ { title: '分辨率', desc: res.bounds.width + ' x ' + res.bounds.height }, { title: '单色显示器', desc: res.monochrome ? '是' : '否' }, { title: '色深', desc: res.colorDepth }, { title: '色域', desc: res.colorSpace }, { title: 'scaleFactor', desc: res.scaleFactor }, { title: '加速器', desc: res.accelerometerSupport }, { title: '触控', desc: res.touchSupport == 'unknown' ? '不支持' : '支持' }, ] return data; } /** * 获取系统主题 */ getTheme() { let theme = 'system'; if (nativeTheme.shouldUseHighContrastColors) { theme = 'light'; } else if (nativeTheme.shouldUseInvertedColorScheme) { theme = 'dark'; } return theme; } /** * 设置系统主题 */ setTheme(args) { // TODO 好像没有什么明显效果 nativeTheme.themeSource = args; return args; } } OsController.toString = () => '[class OsController]'; module.exports = OsController;