example.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684
  1. 'use strict';
  2. const _ = require('lodash');
  3. const path = require('path');
  4. const fs = require('fs');
  5. const { exec } = require('child_process');
  6. const { Controller, Utils } = require('ee-core');
  7. const electronApp = require('electron').app;
  8. const {dialog, shell, BrowserView,
  9. Notification, powerMonitor, screen, nativeTheme} = require('electron');
  10. const dayjs = require('dayjs');
  11. let myTimer = null;
  12. let browserViewObj = null;
  13. let notificationObj = null;
  14. /**
  15. * 示例控制器
  16. * @class
  17. */
  18. class ExampleController extends Controller {
  19. constructor(ctx) {
  20. super(ctx);
  21. }
  22. /**
  23. * 所有方法接收两个参数
  24. * @param args 前端传的参数
  25. * @param event - ipc通信时才有值。invoke()方法时,event == IpcMainInvokeEvent; send()/sendSync()方法时,event == IpcMainEvent
  26. */
  27. /**
  28. * test
  29. */
  30. async test () {
  31. const result = await this.service.example.test('electron');
  32. let tmpDir = Utils.getLogDir();
  33. console.log('tmpDir:', tmpDir);
  34. // console.log('this.app.request:', this.app.request.query);
  35. // const exampleAddon = this.app.addon.example;
  36. // const str = exampleAddon.hello();
  37. // console.log('str:', str);
  38. return result;
  39. }
  40. /**
  41. * json数据库操作
  42. */
  43. async dbOperation(args) {
  44. const { service } = this;
  45. const paramsObj = args;
  46. //console.log('eeeee paramsObj:', paramsObj);
  47. const data = {
  48. action: paramsObj.action,
  49. result: null,
  50. all_list: []
  51. };
  52. switch (paramsObj.action) {
  53. case 'add' :
  54. data.result = await service.storage.addTestData(paramsObj.info);;
  55. break;
  56. case 'del' :
  57. data.result = await service.storage.delTestData(paramsObj.delete_name);;
  58. break;
  59. case 'update' :
  60. data.result = await service.storage.updateTestData(paramsObj.update_name, paramsObj.update_age);
  61. break;
  62. case 'get' :
  63. data.result = await service.storage.getTestData(paramsObj.search_age);
  64. break;
  65. }
  66. data.all_list = await service.storage.getAllTestData();
  67. return data;
  68. }
  69. /**
  70. * sqlite数据库操作
  71. */
  72. async sqlitedbOperation(args) {
  73. const { service } = this;
  74. const paramsObj = args;
  75. //console.log('eeeee paramsObj:', paramsObj);
  76. const data = {
  77. action: paramsObj.action,
  78. result: null,
  79. all_list: []
  80. };
  81. switch (paramsObj.action) {
  82. case 'add' :
  83. data.result = await service.storage.addTestDataSqlite(paramsObj.info);;
  84. break;
  85. case 'del' :
  86. data.result = await service.storage.delTestDataSqlite(paramsObj.delete_name);;
  87. break;
  88. case 'update' :
  89. data.result = await service.storage.updateTestDataSqlite(paramsObj.update_name, paramsObj.update_age);
  90. break;
  91. case 'get' :
  92. data.result = await service.storage.getTestDataSqlite(paramsObj.search_age);
  93. break;
  94. case 'getDataDir' :
  95. data.result = await service.storage.getDataDir();
  96. break;
  97. case 'setDataDir' :
  98. data.result = await service.storage.setCustomDataDir(paramsObj.data_dir);
  99. break;
  100. }
  101. data.all_list = await service.storage.getAllTestDataSqlite();
  102. return data;
  103. }
  104. /**
  105. * 消息提示对话框
  106. */
  107. messageShow () {
  108. dialog.showMessageBoxSync({
  109. type: 'info', // "none", "info", "error", "question" 或者 "warning"
  110. title: '自定义标题-message',
  111. message: '自定义消息内容',
  112. detail: '其它的额外信息'
  113. })
  114. return '打开了消息框';
  115. }
  116. /**
  117. * 消息提示与确认对话框
  118. */
  119. messageShowConfirm () {
  120. const res = dialog.showMessageBoxSync({
  121. type: 'info',
  122. title: '自定义标题-message',
  123. message: '自定义消息内容',
  124. detail: '其它的额外信息',
  125. cancelId: 1, // 用于取消对话框的按钮的索引
  126. defaultId: 0, // 设置默认选中的按钮
  127. buttons: ['确认', '取消'], // 按钮及索引
  128. })
  129. let data = (res === 0) ? '点击确认按钮' : '点击取消按钮';
  130. return data;
  131. }
  132. /**
  133. * 选择目录
  134. */
  135. selectFolder () {
  136. const filePaths = dialog.showOpenDialogSync({
  137. properties: ['openDirectory', 'createDirectory']
  138. });
  139. if (_.isEmpty(filePaths)) {
  140. return null
  141. }
  142. return filePaths[0];
  143. }
  144. /**
  145. * 打开目录
  146. */
  147. openDirectory (args) {
  148. if (!args.id) {
  149. return false;
  150. }
  151. const dir = electronApp.getPath(args.id);
  152. shell.openPath(dir);
  153. return true;
  154. }
  155. /**
  156. * 加载视图内容
  157. */
  158. loadViewContent (args) {
  159. let content = null;
  160. if (args.type == 'html') {
  161. content = path.join('file://', electronApp.getAppPath(), args.content)
  162. } else {
  163. content = args.content;
  164. }
  165. browserViewObj = new BrowserView();
  166. this.app.electron.mainWindow.setBrowserView(browserViewObj)
  167. browserViewObj.setBounds({
  168. x: 300,
  169. y: 170,
  170. width: 650,
  171. height: 400
  172. });
  173. browserViewObj.webContents.loadURL(content);
  174. return true
  175. }
  176. /**
  177. * 移除视图内容
  178. */
  179. removeViewContent () {
  180. this.app.electron.mainWindow.removeBrowserView(browserViewObj);
  181. return true
  182. }
  183. /**
  184. * 打开新窗口
  185. */
  186. createWindow (args) {
  187. let content = null;
  188. if (args.type == 'html') {
  189. content = path.join('file://', electronApp.getAppPath(), args.content)
  190. } else if (args.type == 'web') {
  191. content = args.content;
  192. } else if (args.type == 'vue') {
  193. let addr = 'http://localhost:8080'
  194. if (this.config.env == 'prod') {
  195. const mainServer = this.app.config.mainServer;
  196. addr = mainServer.protocol + mainServer.host + ':' + mainServer.port;
  197. }
  198. content = addr + args.content;
  199. } else {
  200. // some
  201. }
  202. const addonWindow = this.app.addon.window;
  203. let opt = {
  204. title: args.windowName || 'new window'
  205. }
  206. const name = args.windowName || 'window-1';
  207. const win = addonWindow.create(name, opt);
  208. const winContentsId = win.webContents.id;
  209. // load page
  210. win.loadURL(content);
  211. return winContentsId
  212. }
  213. /**
  214. * 获取窗口contents id
  215. */
  216. getWCid (args) {
  217. const addonWindow = this.app.addon.window;
  218. // 主窗口的name默认是main,其它窗口name开发者自己定义
  219. const name = args;
  220. const id = addonWindow.getWCid(name);
  221. return id;
  222. }
  223. /**
  224. * 加载扩展程序
  225. */
  226. // async loadExtension (args) {
  227. // const crxFile = args[0];
  228. // if (_.isEmpty(crxFile)) {
  229. // return false;
  230. // }
  231. // const extensionId = path.basename(crxFile, '.crx');
  232. // const chromeExtensionDir = chromeExtension.getDirectory();
  233. // const extensionDir = path.join(chromeExtensionDir, extensionId);
  234. // console.log("[api] [example] [loadExtension] extension id:", extensionId);
  235. // unzip(crxFile, extensionDir).then(() => {
  236. // console.log("[api] [example] [loadExtension] unzip success!");
  237. // chromeExtension.load(extensionId);
  238. // });
  239. // return true;
  240. // }
  241. /**
  242. * 创建系统通知
  243. */
  244. sendNotification (arg, event) {
  245. const channel = 'controller.example.sendNotification';
  246. if (!Notification.isSupported()) {
  247. return '当前系统不支持通知';
  248. }
  249. let options = {};
  250. if (!_.isEmpty(arg.title)) {
  251. options.title = arg.title;
  252. }
  253. if (!_.isEmpty(arg.subtitle)) {
  254. options.subtitle = arg.subtitle;
  255. }
  256. if (!_.isEmpty(arg.body)) {
  257. options.body = arg.body;
  258. }
  259. if (!_.isEmpty(arg.silent)) {
  260. options.silent = arg.silent;
  261. }
  262. notificationObj = new Notification(options);
  263. if (arg.clickEvent) {
  264. notificationObj.on('click', (e) => {
  265. let data = {
  266. type: 'click',
  267. msg: '您点击了通知消息'
  268. }
  269. event.reply(`${channel}`, data)
  270. });
  271. }
  272. if (arg.closeEvent) {
  273. notificationObj.on('close', (e) => {
  274. let data = {
  275. type: 'close',
  276. msg: '您关闭了通知消息'
  277. }
  278. event.reply(`${channel}`, data)
  279. });
  280. }
  281. notificationObj.show();
  282. return true
  283. }
  284. /**
  285. * 电源监控
  286. */
  287. initPowerMonitor (arg, event) {
  288. const channel = 'controller.example.initPowerMonitor';
  289. powerMonitor.on('on-ac', (e) => {
  290. let data = {
  291. type: 'on-ac',
  292. msg: '接入了电源'
  293. }
  294. event.reply(`${channel}`, data)
  295. });
  296. powerMonitor.on('on-battery', (e) => {
  297. let data = {
  298. type: 'on-battery',
  299. msg: '使用电池中'
  300. }
  301. event.reply(`${channel}`, data)
  302. });
  303. powerMonitor.on('lock-screen', (e) => {
  304. let data = {
  305. type: 'lock-screen',
  306. msg: '锁屏了'
  307. }
  308. event.reply(`${channel}`, data)
  309. });
  310. powerMonitor.on('unlock-screen', (e) => {
  311. let data = {
  312. type: 'unlock-screen',
  313. msg: '解锁了'
  314. }
  315. event.reply(`${channel}`, data)
  316. });
  317. return true
  318. }
  319. /**
  320. * 获取屏幕信息
  321. */
  322. getScreen (arg) {
  323. let data = [];
  324. let res = {};
  325. if (arg == 0) {
  326. let res = screen.getCursorScreenPoint();
  327. data = [
  328. {
  329. title: '横坐标',
  330. desc: res.x
  331. },
  332. {
  333. title: '纵坐标',
  334. desc: res.y
  335. },
  336. ]
  337. return data;
  338. }
  339. if (arg == 1) {
  340. res = screen.getPrimaryDisplay();
  341. }
  342. if (arg == 2) {
  343. let resArr = screen.getAllDisplays();
  344. // 数组,只取一个吧
  345. res = resArr[0];
  346. }
  347. // console.log('[electron] [ipc] [example] [getScreen] res:', res);
  348. data = [
  349. {
  350. title: '分辨率',
  351. desc: res.bounds.width + ' x ' + res.bounds.height
  352. },
  353. {
  354. title: '单色显示器',
  355. desc: res.monochrome ? '是' : '否'
  356. },
  357. {
  358. title: '色深',
  359. desc: res. colorDepth
  360. },
  361. {
  362. title: '色域',
  363. desc: res.colorSpace
  364. },
  365. {
  366. title: 'scaleFactor',
  367. desc: res.scaleFactor
  368. },
  369. {
  370. title: '加速器',
  371. desc: res.accelerometerSupport
  372. },
  373. {
  374. title: '触控',
  375. desc: res.touchSupport == 'unknown' ? '不支持' : '支持'
  376. },
  377. ]
  378. return data;
  379. }
  380. /**
  381. * 调用其它程序(exe、bash等可执行程序)
  382. */
  383. openSoftware (softName) {
  384. if (!softName) {
  385. return false;
  386. }
  387. let softwarePath = path.join(Utils.getExtraResourcesDir(), softName);
  388. this.app.logger.info('[openSoftware] softwarePath:', softwarePath);
  389. // 检查程序是否存在
  390. if (!fs.existsSync(softwarePath)) {
  391. return false;
  392. }
  393. // 命令行字符串 并 执行
  394. let cmdStr = 'start ' + softwarePath;
  395. exec(cmdStr);
  396. return true;
  397. }
  398. /**
  399. * 获取系统主题
  400. */
  401. getTheme () {
  402. let theme = 'system';
  403. if (nativeTheme.shouldUseHighContrastColors) {
  404. theme = 'light';
  405. } else if (nativeTheme.shouldUseInvertedColorScheme) {
  406. theme = 'dark';
  407. }
  408. return theme;
  409. }
  410. /**
  411. * 设置系统主题
  412. */
  413. setTheme (args) {
  414. // TODO 好像没有什么明显效果
  415. nativeTheme.themeSource = args;
  416. return args;
  417. }
  418. /**
  419. * 检查是否有新版本
  420. */
  421. checkForUpdater () {
  422. const autoUpdaterAddon = this.app.addon.autoUpdater;
  423. autoUpdaterAddon.checkUpdate();
  424. return;
  425. }
  426. /**
  427. * 下载新版本
  428. */
  429. downloadApp () {
  430. const autoUpdaterAddon = this.app.addon.autoUpdater;
  431. autoUpdaterAddon.download();
  432. return;
  433. }
  434. /**
  435. * 检测http服务是否开启
  436. */
  437. async checkHttpServer () {
  438. const httpServerConfig = this.app.config.httpServer;
  439. const url = httpServerConfig.protocol + httpServerConfig.host + ':' + httpServerConfig.port;
  440. const data = {
  441. enable: httpServerConfig.enable,
  442. server: url
  443. }
  444. return data;
  445. }
  446. /**
  447. * 一个http请求访问此方法
  448. */
  449. async doHttpRequest () {
  450. // http方法
  451. const method = this.app.request.method;
  452. // http get 参数
  453. let params = this.app.request.query;
  454. params = (params instanceof Object) ? params : JSON.parse(JSON.stringify(params));
  455. // http post 参数
  456. const body = this.app.request.body;
  457. const httpInfo = {
  458. method,
  459. params,
  460. body
  461. }
  462. console.log('httpInfo:', httpInfo);
  463. if (!body.id) {
  464. return false;
  465. }
  466. const dir = electronApp.getPath(body.id);
  467. shell.openPath(dir);
  468. return true;
  469. }
  470. /**
  471. * 一个socket io请求访问此方法
  472. */
  473. async doSocketRequest (args) {
  474. if (!args.id) {
  475. return false;
  476. }
  477. const dir = electronApp.getPath(args.id);
  478. shell.openPath(dir);
  479. return true;
  480. }
  481. /**
  482. * 异步消息类型
  483. * @param args 前端传的参数
  484. * @param event - IpcMainInvokeEvent 文档:https://www.electronjs.org/zh/docs/latest/api/structures/ipc-main-invoke-event
  485. */
  486. async ipcInvokeMsg (args, event) {
  487. let timeNow = dayjs().format('YYYY-MM-DD HH:mm:ss');
  488. const data = args + ' - ' + timeNow;
  489. return data;
  490. }
  491. /**
  492. * 同步消息类型
  493. * @param args 前端传的参数
  494. * @param event - IpcMainEvent 文档:https://www.electronjs.org/docs/latest/api/structures/ipc-main-event
  495. */
  496. async ipcSendSyncMsg (args) {
  497. let timeNow = dayjs().format('YYYY-MM-DD HH:mm:ss');
  498. const data = args + ' - ' + timeNow;
  499. return data;
  500. }
  501. /**
  502. * 双向异步通信
  503. * @param args 前端传的参数
  504. * @param event - IpcMainEvent 文档:https://www.electronjs.org/docs/latest/api/structures/ipc-main-event
  505. */
  506. ipcSendMsg (args, event) {
  507. // 前端ipc频道 channel
  508. const channel = 'controller.example.ipcSendMsg';
  509. if (args.type == 'start') {
  510. // 每隔1秒,向前端页面发送消息
  511. // 用定时器模拟
  512. myTimer = setInterval(function(e, c, msg) {
  513. let timeNow = Date.now();
  514. let data = msg + ':' + timeNow;
  515. e.reply(`${c}`, data)
  516. }, 1000, event, channel, args.content)
  517. return '开始了'
  518. } else if (args.type == 'end') {
  519. clearInterval(myTimer);
  520. return '停止了'
  521. } else {
  522. return 'ohther'
  523. }
  524. }
  525. /**
  526. * 上传文件
  527. */
  528. async uploadFile() {
  529. let tmpDir = Utils.getLogDir();
  530. const files = this.app.request.files;
  531. let file = files.file;
  532. let tmpFilePath = path.join(tmpDir, file.originalFilename);
  533. try {
  534. let tmpFile = fs.readFileSync(file.filepath);
  535. fs.writeFileSync(tmpFilePath, tmpFile);
  536. } finally {
  537. await fs.unlink(file.filepath, function(){});
  538. }
  539. const fileStream = fs.createReadStream(tmpFilePath);
  540. const uploadRes = await this.service.example.uploadFileToSMMS(fileStream);
  541. return uploadRes;
  542. }
  543. /**
  544. * 启动java项目
  545. */
  546. async startJavaServer () {
  547. let data = {
  548. code: 0,
  549. msg: '',
  550. server: ''
  551. }
  552. const javaCfg = this.app.config.addons.javaServer || {};
  553. if (!javaCfg.enable) {
  554. data.code = -1;
  555. data.msg = 'addon not enabled!';
  556. return data;
  557. }
  558. const javaServerAddon = this.app.addon.javaServer;
  559. await javaServerAddon.createServer();
  560. data.server = 'http://localhost:' + javaCfg.port;
  561. return data;
  562. }
  563. /**
  564. * 关闭java项目
  565. */
  566. async closeJavaServer () {
  567. let data = {
  568. code: 0,
  569. msg: '',
  570. }
  571. const javaCfg = this.app.config.addons.javaServer || {};
  572. if (!javaCfg.enable) {
  573. data.code = -1;
  574. data.msg = 'addon not enabled!';
  575. return data;
  576. }
  577. const javaServerAddon = this.app.addon.javaServer;
  578. await javaServerAddon.kill();
  579. return data;
  580. }
  581. /**
  582. * 测试接口
  583. */
  584. hello (args) {
  585. console.log('hello ', args);
  586. }
  587. }
  588. ExampleController.toString = () => '[class ExampleController]';
  589. module.exports = ExampleController;