gaoshuaixing 2 vuotta sitten
vanhempi
commit
3896275003

+ 0 - 25
electron/controller/effect.js

@@ -11,31 +11,6 @@ class EffectController extends Controller {
     super(ctx);
   }
 
-  /**
-   * 所有方法接收两个参数
-   * @param args 前端传的参数
-   * @param event - ipc通信时才有值。详情见:控制器文档
-   */
-
-  /**
-   * test
-   */
-  async test () {
-    const result = await this.service.example.test('electron');
-
-    // let tmpDir = Ps.getLogDir();
-    // Log.info('tmpDir:', tmpDir);
-
-    let mid = await Utils.machineIdSync(true);
-    Log.info('mid 11111111:', mid);
-
-    Utils.machineId().then((id) => {
-      Log.info('mid 222222222:', id);
-    });
-
-    return result;
-  }
-
 }
 
 EffectController.toString = () => '[class EffectController]';

+ 0 - 760
electron/controller/example.js

@@ -1,760 +0,0 @@
-'use strict';
-
-const _ = require('lodash');
-const path = require('path');
-const fs = require('fs');
-const { exec } = require('child_process');
-const { Controller } = require('ee-core');
-const {
-  app: electronApp,
-  dialog, shell, BrowserView, Notification, 
-  powerMonitor, screen, nativeTheme
-} = require('electron');
-const dayjs = require('dayjs');
-const Ps = require('ee-core/ps');
-const Log = require('ee-core/log');
-const Utils = require('ee-core/utils');
-
-let myTimer = null;
-let browserViewObj = null;
-let notificationObj = null;
-
-/**
- * 示例控制器
- * @class
- */
-class ExampleController extends Controller {
-
-  constructor(ctx) {
-    super(ctx);
-  }
-
-  /**
-   * 所有方法接收两个参数
-   * @param args 前端传的参数
-   * @param event - ipc通信时才有值。详情见:控制器文档
-   */
-
-  /**
-   * test
-   */
-  async test () {
-    const result = await this.service.example.test('electron');
-
-    // let tmpDir = Ps.getLogDir();
-    // Log.info('tmpDir:', tmpDir);
-
-    let mid = await Utils.machineIdSync(true);
-    Log.info('mid 11111111:', mid);
-
-    Utils.machineId().then((id) => {
-      Log.info('mid 222222222:', id);
-    });
-
-    return result;
-  }
-
-  /**
-   * json数据库操作
-   */   
-  async dbOperation(args) {
-    const { service } = this;
-    const paramsObj = args;
-    //Log.info('eeeee paramsObj:', paramsObj);
-    const data = {
-      action: paramsObj.action,
-      result: null,
-      all_list: []
-    };
-    
-    switch (paramsObj.action) {
-      case 'add' :
-        data.result = await service.storage.addTestData(paramsObj.info);;
-        break;
-      case 'del' :
-        data.result = await service.storage.delTestData(paramsObj.delete_name);;
-        break;
-      case 'update' :
-        data.result = await service.storage.updateTestData(paramsObj.update_name, paramsObj.update_age);
-        break;
-      case 'get' :
-        data.result = await service.storage.getTestData(paramsObj.search_age);
-        break;
-    }
-
-    data.all_list = await service.storage.getAllTestData();
-
-    return data;
-  }
-
-  /**
-   * sqlite数据库操作
-   */   
-  async sqlitedbOperation(args) {
-    const { service } = this;
-    const paramsObj = args;
-    //Log.info('eeeee paramsObj:', paramsObj);
-    const data = {
-      action: paramsObj.action,
-      result: null,
-      all_list: []
-    };
-    
-    switch (paramsObj.action) {
-      case 'add' :
-        data.result = await service.storage.addTestDataSqlite(paramsObj.info);;
-        break;
-      case 'del' :
-        data.result = await service.storage.delTestDataSqlite(paramsObj.delete_name);;
-        break;
-      case 'update' :
-        data.result = await service.storage.updateTestDataSqlite(paramsObj.update_name, paramsObj.update_age);
-        break;
-      case 'get' :
-        data.result = await service.storage.getTestDataSqlite(paramsObj.search_age);
-        break;
-      case 'getDataDir' :
-        data.result = await service.storage.getDataDir();
-        break;
-      case 'setDataDir' :
-        data.result = await service.storage.setCustomDataDir(paramsObj.data_dir);
-        break;            
-    }
-
-    data.all_list = await service.storage.getAllTestDataSqlite();
-
-    return data;
-  }
-
-  /**
-   * 消息提示对话框
-   */
-  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;
-  }
-
-  /**
-   * 加载视图内容
-   */
-  loadViewContent (args) {
-    let content = null;
-    if (args.type == 'html') {
-      content = path.join('file://', electronApp.getAppPath(), args.content)
-    } else {
-      content = args.content;
-    }
-
-    // electron实验性功能,慎用
-    browserViewObj = new BrowserView();
-    this.app.electron.mainWindow.setBrowserView(browserViewObj)
-    browserViewObj.setBounds({
-      x: 300,
-      y: 170,
-      width: 650,
-      height: 400
-    });
-    browserViewObj.webContents.loadURL(content);
-    return true
-  }
-
-  /**
-   * 移除视图内容
-   */
-  removeViewContent () {
-    // removeBrowserView移除视图后,进程依然存在,估计是electron bug
-    this.app.electron.mainWindow.removeBrowserView(browserViewObj);
-    return true
-  }  
-
-  /**
-   * 打开新窗口
-   */
-  createWindow (args) {
-    let content = null;
-    if (args.type == 'html') {
-      content = path.join('file://', electronApp.getAppPath(), args.content)
-    } else if (args.type == 'web') {
-      content = args.content;
-    } else if (args.type == 'vue') {
-      let addr = 'http://localhost:8080'
-      if (this.config.env == 'prod') {
-        const mainServer = this.app.config.mainServer;
-        addr = mainServer.protocol + mainServer.host + ':' + mainServer.port;
-      }
-
-      content = addr + args.content;
-    } else {
-      // some
-    }
-
-    const addonWindow = this.app.addon.window;
-    let opt = {
-      title: args.windowName || 'new window'
-    }
-    const name = args.windowName || 'window-1';
-    const win = addonWindow.create(name, opt);
-    const winContentsId = win.webContents.id;
-
-    // load page
-    win.loadURL(content);
-
-    return winContentsId
-  }
-  
-  /**
-   * 获取窗口contents id
-   */
-  getWCid (args) {
-    const addonWindow = this.app.addon.window;
-
-    // 主窗口的name默认是main,其它窗口name开发者自己定义
-    const name = args;
-    const id = addonWindow.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 (arg, event) {
-    const channel = 'controller.example.sendNotification';
-    if (!Notification.isSupported()) {
-      return '当前系统不支持通知';
-    }
-
-    let options = {};
-    if (!_.isEmpty(arg.title)) {
-      options.title = arg.title;
-    }
-    if (!_.isEmpty(arg.subtitle)) {
-      options.subtitle = arg.subtitle;
-    }
-    if (!_.isEmpty(arg.body)) {
-      options.body = arg.body;
-    }
-    if (!_.isEmpty(arg.silent)) {
-      options.silent = arg.silent;
-    }
-
-    notificationObj = new Notification(options);
-
-    if (arg.clickEvent) {
-      notificationObj.on('click', (e) => {
-        let data = {
-          type: 'click',
-          msg: '您点击了通知消息'
-        }
-        event.reply(`${channel}`, data)
-      });
-    }
-
-    if (arg.closeEvent) {
-      notificationObj.on('close', (e) => {
-        let data = {
-          type: 'close',
-          msg: '您关闭了通知消息'
-        }
-        event.reply(`${channel}`, data)
-      });
-    }
-
-    notificationObj.show();
-
-    return true
-  }  
-
-  /**
-   * 电源监控
-   */
-  initPowerMonitor (arg, event) {
-    const channel = 'controller.example.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 (arg) {
-    let data = [];
-    let res = {};
-    if (arg == 0) {
-      let res = screen.getCursorScreenPoint();
-      data = [
-        {
-          title: '横坐标',
-          desc: res.x
-        },
-        {
-          title: '纵坐标',
-          desc: res.y
-        },
-      ]
-      
-      return data;
-    }
-    if (arg == 1) {
-      res = screen.getPrimaryDisplay();
-    }
-    if (arg == 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;
-  }  
-
-  /**
-   * 调用其它程序(exe、bash等可执行程序)
-   */
-  openSoftware (softName) {
-    if (!softName) {
-      return false;
-    }
-
-    let softwarePath = path.join(Ps.getExtraResourcesDir(), softName);
-    Log.info('[openSoftware] softwarePath:', softwarePath);
-
-    // 检查程序是否存在
-    if (!fs.existsSync(softwarePath)) {
-      return false;
-    }
-    // 命令行字符串 并 执行
-    let cmdStr = 'start ' + softwarePath;
-    exec(cmdStr);
-
-    return true;
-  }  
-
-  /**
-   * 获取系统主题
-   */
-  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;
-  }
-
-
-  /**
-   * 检查是否有新版本
-   */
-  checkForUpdater () { 
-    const autoUpdaterAddon = this.app.addon.autoUpdater;
-    autoUpdaterAddon.checkUpdate();  
-
-    return;
-  }
-
-  /**
-   * 下载新版本
-   */
-  downloadApp () {
-    const autoUpdaterAddon = this.app.addon.autoUpdater;
-    autoUpdaterAddon.download();
-    return;
-  }
-
-  /**
-   * 检测http服务是否开启
-   */ 
-  async checkHttpServer () {
-    const httpServerConfig = this.app.config.httpServer;
-    const url = httpServerConfig.protocol + httpServerConfig.host + ':' + httpServerConfig.port;
-
-    const data = {
-      enable: httpServerConfig.enable,
-      server: url
-    }
-    return data;
-  }
-
-  /**
-   * 一个http请求访问此方法
-   */ 
-  async doHttpRequest () {
-    // http方法
-    const method = this.app.request.method;
-    // http get 参数
-    let params = this.app.request.query;
-    params = (params instanceof Object) ? params : JSON.parse(JSON.stringify(params));
-    // http post 参数
-    const body = this.app.request.body;
-
-    const httpInfo = {
-      method,
-      params,
-      body
-    }
-    Log.info('httpInfo:', httpInfo);
-
-    if (!body.id) {
-      return false;
-    }
-    const dir = electronApp.getPath(body.id);
-    shell.openPath(dir);
-    
-    return true;
-  } 
- 
-  /**
-   * 一个socket io请求访问此方法
-   */ 
-  async doSocketRequest (args) {
-    if (!args.id) {
-      return false;
-    }
-    const dir = electronApp.getPath(args.id);
-    shell.openPath(dir);
-    
-    return true;
-  }
-  
-  /**
-   * 异步消息类型
-   * @param args 前端传的参数
-   * @param event - IpcMainInvokeEvent 文档:https://www.electronjs.org/zh/docs/latest/api/structures/ipc-main-invoke-event
-   */ 
-   async ipcInvokeMsg (args, event) {
-    let timeNow = dayjs().format('YYYY-MM-DD HH:mm:ss');
-    const data = args + ' - ' + timeNow;
-    
-    return data;
-  }  
-
-  /**
-   * 同步消息类型
-   * @param args 前端传的参数
-   * @param event - IpcMainEvent 文档:https://www.electronjs.org/docs/latest/api/structures/ipc-main-event
-   */ 
-  async ipcSendSyncMsg (args) {
-    let timeNow = dayjs().format('YYYY-MM-DD HH:mm:ss');
-    const data = args + ' - ' + timeNow;
-    
-    return data;
-  }  
-
-  /**
-   * 双向异步通信
-   * @param args 前端传的参数
-   * @param event - IpcMainEvent 文档:https://www.electronjs.org/docs/latest/api/structures/ipc-main-event
-   */
-  ipcSendMsg (args, event) {
-    // 前端ipc频道 channel
-    const channel = 'controller.example.ipcSendMsg';
-
-    if (args.type == 'start') {
-      // 每隔1秒,向前端页面发送消息
-      // 用定时器模拟
-      myTimer = setInterval(function(e, c, msg) {
-        let timeNow = Date.now();
-        let data = msg + ':' + timeNow;
-        e.reply(`${c}`, data)
-      }, 1000, event, channel, args.content)
-
-      return '开始了'
-    } else if (args.type == 'end') {
-      clearInterval(myTimer);
-      return '停止了'    
-    } else {
-      return 'ohther'
-    }
-  }
-
-  /**
-   * 上传文件
-   */  
-  async uploadFile() {
-    let tmpDir = Ps.getLogDir();
-    const files = this.app.request.files;
-    let file = files.file;
-    
-    let tmpFilePath = path.join(tmpDir, file.originalFilename);
-    try {
-      let tmpFile = fs.readFileSync(file.filepath);
-      fs.writeFileSync(tmpFilePath, tmpFile);
-    } finally {
-      await fs.unlink(file.filepath, function(){});
-    }
-    const fileStream = fs.createReadStream(tmpFilePath);
-    const uploadRes = await this.service.example.uploadFileToSMMS(fileStream);
-
-    return uploadRes;
-  }
-
-  /**
-   * 启动java项目
-   */ 
-  async startJavaServer () {
-    let data = {
-      code: 0,
-      msg: '',
-      server: ''
-    }
-    const javaCfg = this.app.config.addons.javaServer || {};
-    if (!javaCfg.enable) {
-      data.code = -1;
-      data.msg = 'addon not enabled!';
-      return data;
-    }
-
-    const javaServerAddon = this.app.addon.javaServer;
-    await javaServerAddon.createServer();
-
-    data.server = 'http://localhost:' + javaCfg.port;
-
-    return data;
-  }
-
-  /**
-   * 关闭java项目
-   */ 
-  async closeJavaServer () {
-    let data = {
-      code: 0,
-      msg: '',
-    }
-    const javaCfg = this.app.config.addons.javaServer || {};
-    if (!javaCfg.enable) {
-      data.code = -1;
-      data.msg = 'addon not enabled!';
-      return data;
-    }
-
-    const javaServerAddon = this.app.addon.javaServer;
-    await javaServerAddon.kill();
-
-    return data;
-  }
-
-  /**
-   * 任务
-   */ 
-  someJob (args, event) {
-    let jobId = args.id;
-    let action = args.action;
-    
-    let result;
-    switch (action) {
-      case 'create':
-        result = this.service.example.doJob(jobId, action, event);
-        break;       
-      case 'close':
-        this.service.example.doJob(jobId, action, event);
-        break;
-      default:  
-    }
-    
-    let data = {
-      jobId,
-      action,
-      result
-    }
-    return data;
-  }
-
-  /**
-   * 创建任务池
-   */ 
-  async createPool (args, event) {
-    let num = args.number;
-    this.service.example.doCreatePool(num, event);
-
-    // test monitor
-    this.service.example.monitorJob();
-
-    return;
-  }
-
-  /**
-   * 通过进程池执行任务
-   */ 
-  someJobByPool (args, event) {
-    let jobId = args.id;
-    let action = args.action;
-    
-    let result;
-    switch (action) {
-      case 'run':
-        result = this.service.example.doJobByPool(jobId, action, event);
-        break;
-      default:  
-    }
-    
-    let data = {
-      jobId,
-      action,
-      result
-    }
-    return data;
-  }
-
-  /**
-   * 测试接口
-   */ 
-  hello (args) {
-    Log.info('hello ', args);
-  }   
-}
-
-ExampleController.toString = () => '[class ExampleController]';
-module.exports = ExampleController;

+ 365 - 1
electron/controller/framework.js

@@ -1,5 +1,16 @@
 'use strict';
 
+const path = require('path');
+const fs = require('fs');
+const { exec } = require('child_process');
+const { Controller } = require('ee-core');
+const { app: electronApp, shell } = require('electron');
+const dayjs = require('dayjs');
+const Ps = require('ee-core/ps');
+const Log = require('ee-core/log');
+const Utils = require('ee-core/utils');
+
+let myTimer = null;
 
 /**
  * electron-egg framework - 功能demo
@@ -20,7 +31,7 @@ class FrameworkController extends Controller {
   /**
    * test
    */
-  async test () {
+  async test() {
     const result = await this.service.example.test('electron');
 
     // let tmpDir = Ps.getLogDir();
@@ -36,6 +47,359 @@ class FrameworkController extends Controller {
     return result;
   }
 
+  /**
+   * json数据库操作
+   */   
+  async dbOperation(args) {
+    const { service } = this;
+    const paramsObj = args;
+    //Log.info('eeeee paramsObj:', paramsObj);
+    const data = {
+      action: paramsObj.action,
+      result: null,
+      all_list: []
+    };
+    
+    switch (paramsObj.action) {
+      case 'add' :
+        data.result = await service.storage.addTestData(paramsObj.info);;
+        break;
+      case 'del' :
+        data.result = await service.storage.delTestData(paramsObj.delete_name);;
+        break;
+      case 'update' :
+        data.result = await service.storage.updateTestData(paramsObj.update_name, paramsObj.update_age);
+        break;
+      case 'get' :
+        data.result = await service.storage.getTestData(paramsObj.search_age);
+        break;
+    }
+
+    data.all_list = await service.storage.getAllTestData();
+
+    return data;
+  }
+
+  /**
+   * sqlite数据库操作
+   */   
+  async sqlitedbOperation(args) {
+    const { service } = this;
+    const paramsObj = args;
+    //Log.info('eeeee paramsObj:', paramsObj);
+    const data = {
+      action: paramsObj.action,
+      result: null,
+      all_list: []
+    };
+    
+    switch (paramsObj.action) {
+      case 'add' :
+        data.result = await service.storage.addTestDataSqlite(paramsObj.info);;
+        break;
+      case 'del' :
+        data.result = await service.storage.delTestDataSqlite(paramsObj.delete_name);;
+        break;
+      case 'update' :
+        data.result = await service.storage.updateTestDataSqlite(paramsObj.update_name, paramsObj.update_age);
+        break;
+      case 'get' :
+        data.result = await service.storage.getTestDataSqlite(paramsObj.search_age);
+        break;
+      case 'getDataDir' :
+        data.result = await service.storage.getDataDir();
+        break;
+      case 'setDataDir' :
+        data.result = await service.storage.setCustomDataDir(paramsObj.data_dir);
+        break;            
+    }
+
+    data.all_list = await service.storage.getAllTestDataSqlite();
+
+    return data;
+  }  
+
+  /**
+   * 调用其它程序(exe、bash等可执行程序)
+   */
+  openSoftware(softName) {
+    if (!softName) {
+      return false;
+    }
+
+    let softwarePath = path.join(Ps.getExtraResourcesDir(), softName);
+    Log.info('[openSoftware] softwarePath:', softwarePath);
+
+    // 检查程序是否存在
+    if (!fs.existsSync(softwarePath)) {
+      return false;
+    }
+    // 命令行字符串 并 执行
+    let cmdStr = 'start ' + softwarePath;
+    exec(cmdStr);
+
+    return true;
+  }  
+  
+  /**
+   * 检查是否有新版本
+   */
+  checkForUpdater() { 
+    const autoUpdaterAddon = this.app.addon.autoUpdater;
+    autoUpdaterAddon.checkUpdate();  
+
+    return;
+  }
+
+  /**
+   * 下载新版本
+   */
+  downloadApp() {
+    const autoUpdaterAddon = this.app.addon.autoUpdater;
+    autoUpdaterAddon.download();
+    return;
+  }
+
+  /**
+   * 检测http服务是否开启
+   */ 
+  async checkHttpServer() {
+    const httpServerConfig = this.app.config.httpServer;
+    const url = httpServerConfig.protocol + httpServerConfig.host + ':' + httpServerConfig.port;
+
+    const data = {
+      enable: httpServerConfig.enable,
+      server: url
+    }
+    return data;
+  }
+
+  /**
+   * 一个http请求访问此方法
+   */ 
+  async doHttpRequest() {
+    // http方法
+    const method = this.app.request.method;
+    // http get 参数
+    let params = this.app.request.query;
+    params = (params instanceof Object) ? params : JSON.parse(JSON.stringify(params));
+    // http post 参数
+    const body = this.app.request.body;
+
+    const httpInfo = {
+      method,
+      params,
+      body
+    }
+    Log.info('httpInfo:', httpInfo);
+
+    if (!body.id) {
+      return false;
+    }
+    const dir = electronApp.getPath(body.id);
+    shell.openPath(dir);
+    
+    return true;
+  } 
+ 
+  /**
+   * 一个socket io请求访问此方法
+   */ 
+  async doSocketRequest(args) {
+    if (!args.id) {
+      return false;
+    }
+    const dir = electronApp.getPath(args.id);
+    shell.openPath(dir);
+    
+    return true;
+  }
+  
+  /**
+   * 异步消息类型
+   * @param args 前端传的参数
+   * @param event - IpcMainInvokeEvent 文档:https://www.electronjs.org/zh/docs/latest/api/structures/ipc-main-invoke-event
+   */ 
+   async ipcInvokeMsg(args, event) {
+    let timeNow = dayjs().format('YYYY-MM-DD HH:mm:ss');
+    const data = args + ' - ' + timeNow;
+    
+    return data;
+  }  
+
+  /**
+   * 同步消息类型
+   * @param args 前端传的参数
+   * @param event - IpcMainEvent 文档:https://www.electronjs.org/docs/latest/api/structures/ipc-main-event
+   */ 
+  async ipcSendSyncMsg(args) {
+    let timeNow = dayjs().format('YYYY-MM-DD HH:mm:ss');
+    const data = args + ' - ' + timeNow;
+    
+    return data;
+  }  
+
+  /**
+   * 双向异步通信
+   * @param args 前端传的参数
+   * @param event - IpcMainEvent 文档:https://www.electronjs.org/docs/latest/api/structures/ipc-main-event
+   */
+  ipcSendMsg(args, event) {
+    // 前端ipc频道 channel
+    const channel = 'controller.example.ipcSendMsg';
+
+    if (args.type == 'start') {
+      // 每隔1秒,向前端页面发送消息
+      // 用定时器模拟
+      myTimer = setInterval(function(e, c, msg) {
+        let timeNow = Date.now();
+        let data = msg + ':' + timeNow;
+        e.reply(`${c}`, data)
+      }, 1000, event, channel, args.content)
+
+      return '开始了'
+    } else if (args.type == 'end') {
+      clearInterval(myTimer);
+      return '停止了'    
+    } else {
+      return 'ohther'
+    }
+  }
+
+  /**
+   * 上传文件
+   */  
+  async uploadFile() {
+    let tmpDir = Ps.getLogDir();
+    const files = this.app.request.files;
+    let file = files.file;
+    
+    let tmpFilePath = path.join(tmpDir, file.originalFilename);
+    try {
+      let tmpFile = fs.readFileSync(file.filepath);
+      fs.writeFileSync(tmpFilePath, tmpFile);
+    } finally {
+      await fs.unlink(file.filepath, function(){});
+    }
+    const fileStream = fs.createReadStream(tmpFilePath);
+    const uploadRes = await this.service.example.uploadFileToSMMS(fileStream);
+
+    return uploadRes;
+  }
+
+  /**
+   * 启动java项目
+   */ 
+  async startJavaServer() {
+    let data = {
+      code: 0,
+      msg: '',
+      server: ''
+    }
+    const javaCfg = this.app.config.addons.javaServer || {};
+    if (!javaCfg.enable) {
+      data.code = -1;
+      data.msg = 'addon not enabled!';
+      return data;
+    }
+
+    const javaServerAddon = this.app.addon.javaServer;
+    await javaServerAddon.createServer();
+
+    data.server = 'http://localhost:' + javaCfg.port;
+
+    return data;
+  }
+
+  /**
+   * 关闭java项目
+   */ 
+  async closeJavaServer() {
+    let data = {
+      code: 0,
+      msg: '',
+    }
+    const javaCfg = this.app.config.addons.javaServer || {};
+    if (!javaCfg.enable) {
+      data.code = -1;
+      data.msg = 'addon not enabled!';
+      return data;
+    }
+
+    const javaServerAddon = this.app.addon.javaServer;
+    await javaServerAddon.kill();
+
+    return data;
+  }
+
+  /**
+   * 任务
+   */ 
+  someJob(args, event) {
+    let jobId = args.id;
+    let action = args.action;
+    
+    let result;
+    switch (action) {
+      case 'create':
+        result = this.service.example.doJob(jobId, action, event);
+        break;       
+      case 'close':
+        this.service.example.doJob(jobId, action, event);
+        break;
+      default:  
+    }
+    
+    let data = {
+      jobId,
+      action,
+      result
+    }
+    return data;
+  }
+
+  /**
+   * 创建任务池
+   */ 
+  async createPool(args, event) {
+    let num = args.number;
+    this.service.example.doCreatePool(num, event);
+
+    // test monitor
+    this.service.example.monitorJob();
+
+    return;
+  }
+
+  /**
+   * 通过进程池执行任务
+   */ 
+  someJobByPool(args, event) {
+    let jobId = args.id;
+    let action = args.action;
+    
+    let result;
+    switch (action) {
+      case 'run':
+        result = this.service.example.doJobByPool(jobId, action, event);
+        break;
+      default:  
+    }
+    
+    let data = {
+      jobId,
+      action,
+      result
+    }
+    return data;
+  }
+
+  /**
+   * 测试接口
+   */ 
+  hello(args) {
+    Log.info('hello ', args);
+  }   
 }
 
 FrameworkController.toString = () => '[class FrameworkController]';

+ 0 - 26
electron/controller/hardware.js

@@ -1,6 +1,5 @@
 'use strict';
 
-
 /**
  * 硬件设备 - 功能demo
  * @class
@@ -11,31 +10,6 @@ class HardwareController extends Controller {
     super(ctx);
   }
 
-  /**
-   * 所有方法接收两个参数
-   * @param args 前端传的参数
-   * @param event - ipc通信时才有值。详情见:控制器文档
-   */
-
-  /**
-   * test
-   */
-  async test () {
-    const result = await this.service.example.test('electron');
-
-    // let tmpDir = Ps.getLogDir();
-    // Log.info('tmpDir:', tmpDir);
-
-    let mid = await Utils.machineIdSync(true);
-    Log.info('mid 11111111:', mid);
-
-    Utils.machineId().then((id) => {
-      Log.info('mid 222222222:', id);
-    });
-
-    return result;
-  }
-
 }
 
 HardwareController.toString = () => '[class HardwareController]';

+ 348 - 10
electron/controller/os.js

@@ -1,5 +1,17 @@
 'use strict';
 
+const _ = require('lodash');
+const path = require('path');
+const { Controller } = require('ee-core');
+const {
+  app: electronApp,
+  dialog, shell, BrowserView, Notification, 
+  powerMonitor, screen, nativeTheme
+} = require('electron');
+
+let myTimer = null;
+let browserViewObj = null;
+let notificationObj = null;
 
 /**
  * 操作系统 - 功能demo
@@ -18,24 +30,350 @@ class OsController extends Controller {
    */
 
   /**
-   * test
+   * 消息提示对话框
+   */
+  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;
+  }
+
+  /**
+   * 加载视图内容
+   */
+  loadViewContent (args) {
+    let content = null;
+    if (args.type == 'html') {
+      content = path.join('file://', electronApp.getAppPath(), args.content)
+    } else {
+      content = args.content;
+    }
+
+    // electron实验性功能,慎用
+    browserViewObj = new BrowserView();
+    this.app.electron.mainWindow.setBrowserView(browserViewObj)
+    browserViewObj.setBounds({
+      x: 300,
+      y: 170,
+      width: 650,
+      height: 400
+    });
+    browserViewObj.webContents.loadURL(content);
+    return true
+  }
+
+  /**
+   * 移除视图内容
+   */
+  removeViewContent () {
+    // removeBrowserView移除视图后,进程依然存在,估计是electron bug
+    this.app.electron.mainWindow.removeBrowserView(browserViewObj);
+    return true
+  }  
+
+  /**
+   * 打开新窗口
+   */
+  createWindow (args) {
+    let content = null;
+    if (args.type == 'html') {
+      content = path.join('file://', electronApp.getAppPath(), args.content)
+    } else if (args.type == 'web') {
+      content = args.content;
+    } else if (args.type == 'vue') {
+      let addr = 'http://localhost:8080'
+      if (this.config.env == 'prod') {
+        const mainServer = this.app.config.mainServer;
+        addr = mainServer.protocol + mainServer.host + ':' + mainServer.port;
+      }
+
+      content = addr + args.content;
+    } else {
+      // some
+    }
+
+    const addonWindow = this.app.addon.window;
+    let opt = {
+      title: args.windowName || 'new window'
+    }
+    const name = args.windowName || 'window-1';
+    const win = addonWindow.create(name, opt);
+    const winContentsId = win.webContents.id;
+
+    // load page
+    win.loadURL(content);
+
+    return winContentsId
+  }
+  
+  /**
+   * 获取窗口contents id
+   */
+  getWCid (args) {
+    const addonWindow = this.app.addon.window;
+
+    // 主窗口的name默认是main,其它窗口name开发者自己定义
+    const name = args;
+    const id = addonWindow.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 (arg, event) {
+    const channel = 'controller.example.sendNotification';
+    if (!Notification.isSupported()) {
+      return '当前系统不支持通知';
+    }
+
+    let options = {};
+    if (!_.isEmpty(arg.title)) {
+      options.title = arg.title;
+    }
+    if (!_.isEmpty(arg.subtitle)) {
+      options.subtitle = arg.subtitle;
+    }
+    if (!_.isEmpty(arg.body)) {
+      options.body = arg.body;
+    }
+    if (!_.isEmpty(arg.silent)) {
+      options.silent = arg.silent;
+    }
+
+    notificationObj = new Notification(options);
+
+    if (arg.clickEvent) {
+      notificationObj.on('click', (e) => {
+        let data = {
+          type: 'click',
+          msg: '您点击了通知消息'
+        }
+        event.reply(`${channel}`, data)
+      });
+    }
+
+    if (arg.closeEvent) {
+      notificationObj.on('close', (e) => {
+        let data = {
+          type: 'close',
+          msg: '您关闭了通知消息'
+        }
+        event.reply(`${channel}`, data)
+      });
+    }
+
+    notificationObj.show();
+
+    return true
+  }  
+
+  /**
+   * 电源监控
    */
-  async test () {
-    const result = await this.service.example.test('electron');
+  initPowerMonitor (arg, event) {
+    const channel = 'controller.example.initPowerMonitor';
+    powerMonitor.on('on-ac', (e) => {
+      let data = {
+        type: 'on-ac',
+        msg: '接入了电源'
+      }
+      event.reply(`${channel}`, data)
+    });
 
-    // let tmpDir = Ps.getLogDir();
-    // Log.info('tmpDir:', tmpDir);
+    powerMonitor.on('on-battery', (e) => {
+      let data = {
+        type: 'on-battery',
+        msg: '使用电池中'
+      }
+      event.reply(`${channel}`, data)
+    });
 
-    let mid = await Utils.machineIdSync(true);
-    Log.info('mid 11111111:', mid);
+    powerMonitor.on('lock-screen', (e) => {
+      let data = {
+        type: 'lock-screen',
+        msg: '锁屏了'
+      }
+      event.reply(`${channel}`, data)
+    });
 
-    Utils.machineId().then((id) => {
-      Log.info('mid 222222222:', id);
+    powerMonitor.on('unlock-screen', (e) => {
+      let data = {
+        type: 'unlock-screen',
+        msg: '解锁了'
+      }
+      event.reply(`${channel}`, data)
     });
 
-    return result;
+    return true
+  }  
+
+  /**
+   * 获取屏幕信息
+   */
+  getScreen (arg) {
+    let data = [];
+    let res = {};
+    if (arg == 0) {
+      let res = screen.getCursorScreenPoint();
+      data = [
+        {
+          title: '横坐标',
+          desc: res.x
+        },
+        {
+          title: '纵坐标',
+          desc: res.y
+        },
+      ]
+      
+      return data;
+    }
+    if (arg == 1) {
+      res = screen.getPrimaryDisplay();
+    }
+    if (arg == 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]';