example.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690
  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. let dir = '';
  152. if (path.isAbsolute(args.id)) {
  153. dir = args.id;
  154. } else {
  155. dir = electronApp.getPath(args.id);
  156. }
  157. shell.openPath(dir);
  158. return true;
  159. }
  160. /**
  161. * 加载视图内容
  162. */
  163. loadViewContent (args) {
  164. let content = null;
  165. if (args.type == 'html') {
  166. content = path.join('file://', electronApp.getAppPath(), args.content)
  167. } else {
  168. content = args.content;
  169. }
  170. browserViewObj = new BrowserView();
  171. this.app.electron.mainWindow.setBrowserView(browserViewObj)
  172. browserViewObj.setBounds({
  173. x: 300,
  174. y: 170,
  175. width: 650,
  176. height: 400
  177. });
  178. browserViewObj.webContents.loadURL(content);
  179. return true
  180. }
  181. /**
  182. * 移除视图内容
  183. */
  184. removeViewContent () {
  185. this.app.electron.mainWindow.removeBrowserView(browserViewObj);
  186. return true
  187. }
  188. /**
  189. * 打开新窗口
  190. */
  191. createWindow (args) {
  192. let content = null;
  193. if (args.type == 'html') {
  194. content = path.join('file://', electronApp.getAppPath(), args.content)
  195. } else if (args.type == 'web') {
  196. content = args.content;
  197. } else if (args.type == 'vue') {
  198. let addr = 'http://localhost:8080'
  199. if (this.config.env == 'prod') {
  200. const mainServer = this.app.config.mainServer;
  201. addr = mainServer.protocol + mainServer.host + ':' + mainServer.port;
  202. }
  203. content = addr + args.content;
  204. } else {
  205. // some
  206. }
  207. const addonWindow = this.app.addon.window;
  208. let opt = {
  209. title: args.windowName || 'new window'
  210. }
  211. const name = args.windowName || 'window-1';
  212. const win = addonWindow.create(name, opt);
  213. const winContentsId = win.webContents.id;
  214. // load page
  215. win.loadURL(content);
  216. return winContentsId
  217. }
  218. /**
  219. * 获取窗口contents id
  220. */
  221. getWCid (args) {
  222. const addonWindow = this.app.addon.window;
  223. // 主窗口的name默认是main,其它窗口name开发者自己定义
  224. const name = args;
  225. const id = addonWindow.getWCid(name);
  226. return id;
  227. }
  228. /**
  229. * 加载扩展程序
  230. */
  231. // async loadExtension (args) {
  232. // const crxFile = args[0];
  233. // if (_.isEmpty(crxFile)) {
  234. // return false;
  235. // }
  236. // const extensionId = path.basename(crxFile, '.crx');
  237. // const chromeExtensionDir = chromeExtension.getDirectory();
  238. // const extensionDir = path.join(chromeExtensionDir, extensionId);
  239. // console.log("[api] [example] [loadExtension] extension id:", extensionId);
  240. // unzip(crxFile, extensionDir).then(() => {
  241. // console.log("[api] [example] [loadExtension] unzip success!");
  242. // chromeExtension.load(extensionId);
  243. // });
  244. // return true;
  245. // }
  246. /**
  247. * 创建系统通知
  248. */
  249. sendNotification (arg, event) {
  250. const channel = 'controller.example.sendNotification';
  251. if (!Notification.isSupported()) {
  252. return '当前系统不支持通知';
  253. }
  254. let options = {};
  255. if (!_.isEmpty(arg.title)) {
  256. options.title = arg.title;
  257. }
  258. if (!_.isEmpty(arg.subtitle)) {
  259. options.subtitle = arg.subtitle;
  260. }
  261. if (!_.isEmpty(arg.body)) {
  262. options.body = arg.body;
  263. }
  264. if (!_.isEmpty(arg.silent)) {
  265. options.silent = arg.silent;
  266. }
  267. notificationObj = new Notification(options);
  268. if (arg.clickEvent) {
  269. notificationObj.on('click', (e) => {
  270. let data = {
  271. type: 'click',
  272. msg: '您点击了通知消息'
  273. }
  274. event.reply(`${channel}`, data)
  275. });
  276. }
  277. if (arg.closeEvent) {
  278. notificationObj.on('close', (e) => {
  279. let data = {
  280. type: 'close',
  281. msg: '您关闭了通知消息'
  282. }
  283. event.reply(`${channel}`, data)
  284. });
  285. }
  286. notificationObj.show();
  287. return true
  288. }
  289. /**
  290. * 电源监控
  291. */
  292. initPowerMonitor (arg, event) {
  293. const channel = 'controller.example.initPowerMonitor';
  294. powerMonitor.on('on-ac', (e) => {
  295. let data = {
  296. type: 'on-ac',
  297. msg: '接入了电源'
  298. }
  299. event.reply(`${channel}`, data)
  300. });
  301. powerMonitor.on('on-battery', (e) => {
  302. let data = {
  303. type: 'on-battery',
  304. msg: '使用电池中'
  305. }
  306. event.reply(`${channel}`, data)
  307. });
  308. powerMonitor.on('lock-screen', (e) => {
  309. let data = {
  310. type: 'lock-screen',
  311. msg: '锁屏了'
  312. }
  313. event.reply(`${channel}`, data)
  314. });
  315. powerMonitor.on('unlock-screen', (e) => {
  316. let data = {
  317. type: 'unlock-screen',
  318. msg: '解锁了'
  319. }
  320. event.reply(`${channel}`, data)
  321. });
  322. return true
  323. }
  324. /**
  325. * 获取屏幕信息
  326. */
  327. getScreen (arg) {
  328. let data = [];
  329. let res = {};
  330. if (arg == 0) {
  331. let res = screen.getCursorScreenPoint();
  332. data = [
  333. {
  334. title: '横坐标',
  335. desc: res.x
  336. },
  337. {
  338. title: '纵坐标',
  339. desc: res.y
  340. },
  341. ]
  342. return data;
  343. }
  344. if (arg == 1) {
  345. res = screen.getPrimaryDisplay();
  346. }
  347. if (arg == 2) {
  348. let resArr = screen.getAllDisplays();
  349. // 数组,只取一个吧
  350. res = resArr[0];
  351. }
  352. // console.log('[electron] [ipc] [example] [getScreen] res:', res);
  353. data = [
  354. {
  355. title: '分辨率',
  356. desc: res.bounds.width + ' x ' + res.bounds.height
  357. },
  358. {
  359. title: '单色显示器',
  360. desc: res.monochrome ? '是' : '否'
  361. },
  362. {
  363. title: '色深',
  364. desc: res. colorDepth
  365. },
  366. {
  367. title: '色域',
  368. desc: res.colorSpace
  369. },
  370. {
  371. title: 'scaleFactor',
  372. desc: res.scaleFactor
  373. },
  374. {
  375. title: '加速器',
  376. desc: res.accelerometerSupport
  377. },
  378. {
  379. title: '触控',
  380. desc: res.touchSupport == 'unknown' ? '不支持' : '支持'
  381. },
  382. ]
  383. return data;
  384. }
  385. /**
  386. * 调用其它程序(exe、bash等可执行程序)
  387. */
  388. openSoftware (softName) {
  389. if (!softName) {
  390. return false;
  391. }
  392. let softwarePath = path.join(Utils.getExtraResourcesDir(), softName);
  393. this.app.logger.info('[openSoftware] softwarePath:', softwarePath);
  394. // 检查程序是否存在
  395. if (!fs.existsSync(softwarePath)) {
  396. return false;
  397. }
  398. // 命令行字符串 并 执行
  399. let cmdStr = 'start ' + softwarePath;
  400. exec(cmdStr);
  401. return true;
  402. }
  403. /**
  404. * 获取系统主题
  405. */
  406. getTheme () {
  407. let theme = 'system';
  408. if (nativeTheme.shouldUseHighContrastColors) {
  409. theme = 'light';
  410. } else if (nativeTheme.shouldUseInvertedColorScheme) {
  411. theme = 'dark';
  412. }
  413. return theme;
  414. }
  415. /**
  416. * 设置系统主题
  417. */
  418. setTheme (args) {
  419. // TODO 好像没有什么明显效果
  420. nativeTheme.themeSource = args;
  421. return args;
  422. }
  423. /**
  424. * 检查是否有新版本
  425. */
  426. checkForUpdater () {
  427. const autoUpdaterAddon = this.app.addon.autoUpdater;
  428. autoUpdaterAddon.checkUpdate();
  429. return;
  430. }
  431. /**
  432. * 下载新版本
  433. */
  434. downloadApp () {
  435. const autoUpdaterAddon = this.app.addon.autoUpdater;
  436. autoUpdaterAddon.download();
  437. return;
  438. }
  439. /**
  440. * 检测http服务是否开启
  441. */
  442. async checkHttpServer () {
  443. const httpServerConfig = this.app.config.httpServer;
  444. const url = httpServerConfig.protocol + httpServerConfig.host + ':' + httpServerConfig.port;
  445. const data = {
  446. enable: httpServerConfig.enable,
  447. server: url
  448. }
  449. return data;
  450. }
  451. /**
  452. * 一个http请求访问此方法
  453. */
  454. async doHttpRequest () {
  455. // http方法
  456. const method = this.app.request.method;
  457. // http get 参数
  458. let params = this.app.request.query;
  459. params = (params instanceof Object) ? params : JSON.parse(JSON.stringify(params));
  460. // http post 参数
  461. const body = this.app.request.body;
  462. const httpInfo = {
  463. method,
  464. params,
  465. body
  466. }
  467. console.log('httpInfo:', httpInfo);
  468. if (!body.id) {
  469. return false;
  470. }
  471. const dir = electronApp.getPath(body.id);
  472. shell.openPath(dir);
  473. return true;
  474. }
  475. /**
  476. * 一个socket io请求访问此方法
  477. */
  478. async doSocketRequest (args) {
  479. if (!args.id) {
  480. return false;
  481. }
  482. const dir = electronApp.getPath(args.id);
  483. shell.openPath(dir);
  484. return true;
  485. }
  486. /**
  487. * 异步消息类型
  488. * @param args 前端传的参数
  489. * @param event - IpcMainInvokeEvent 文档:https://www.electronjs.org/zh/docs/latest/api/structures/ipc-main-invoke-event
  490. */
  491. async ipcInvokeMsg (args, event) {
  492. let timeNow = dayjs().format('YYYY-MM-DD HH:mm:ss');
  493. const data = args + ' - ' + timeNow;
  494. return data;
  495. }
  496. /**
  497. * 同步消息类型
  498. * @param args 前端传的参数
  499. * @param event - IpcMainEvent 文档:https://www.electronjs.org/docs/latest/api/structures/ipc-main-event
  500. */
  501. async ipcSendSyncMsg (args) {
  502. let timeNow = dayjs().format('YYYY-MM-DD HH:mm:ss');
  503. const data = args + ' - ' + timeNow;
  504. return data;
  505. }
  506. /**
  507. * 双向异步通信
  508. * @param args 前端传的参数
  509. * @param event - IpcMainEvent 文档:https://www.electronjs.org/docs/latest/api/structures/ipc-main-event
  510. */
  511. ipcSendMsg (args, event) {
  512. // 前端ipc频道 channel
  513. const channel = 'controller.example.ipcSendMsg';
  514. if (args.type == 'start') {
  515. // 每隔1秒,向前端页面发送消息
  516. // 用定时器模拟
  517. myTimer = setInterval(function(e, c, msg) {
  518. let timeNow = Date.now();
  519. let data = msg + ':' + timeNow;
  520. e.reply(`${c}`, data)
  521. }, 1000, event, channel, args.content)
  522. return '开始了'
  523. } else if (args.type == 'end') {
  524. clearInterval(myTimer);
  525. return '停止了'
  526. } else {
  527. return 'ohther'
  528. }
  529. }
  530. /**
  531. * 上传文件
  532. */
  533. async uploadFile() {
  534. let tmpDir = Utils.getLogDir();
  535. const files = this.app.request.files;
  536. let file = files.file;
  537. let tmpFilePath = path.join(tmpDir, file.originalFilename);
  538. try {
  539. let tmpFile = fs.readFileSync(file.filepath);
  540. fs.writeFileSync(tmpFilePath, tmpFile);
  541. } finally {
  542. await fs.unlink(file.filepath, function(){});
  543. }
  544. const fileStream = fs.createReadStream(tmpFilePath);
  545. const uploadRes = await this.service.example.uploadFileToSMMS(fileStream);
  546. return uploadRes;
  547. }
  548. /**
  549. * 启动java项目
  550. */
  551. async startJavaServer () {
  552. let data = {
  553. code: 0,
  554. msg: '',
  555. server: ''
  556. }
  557. const javaCfg = this.app.config.addons.javaServer || {};
  558. if (!javaCfg.enable) {
  559. data.code = -1;
  560. data.msg = 'addon not enabled!';
  561. return data;
  562. }
  563. const javaServerAddon = this.app.addon.javaServer;
  564. await javaServerAddon.createServer();
  565. data.server = 'http://localhost:' + javaCfg.port;
  566. return data;
  567. }
  568. /**
  569. * 关闭java项目
  570. */
  571. async closeJavaServer () {
  572. let data = {
  573. code: 0,
  574. msg: '',
  575. }
  576. const javaCfg = this.app.config.addons.javaServer || {};
  577. if (!javaCfg.enable) {
  578. data.code = -1;
  579. data.msg = 'addon not enabled!';
  580. return data;
  581. }
  582. const javaServerAddon = this.app.addon.javaServer;
  583. await javaServerAddon.kill();
  584. return data;
  585. }
  586. /**
  587. * 测试接口
  588. */
  589. hello (args) {
  590. console.log('hello ', args);
  591. }
  592. }
  593. ExampleController.toString = () => '[class ExampleController]';
  594. module.exports = ExampleController;