gsx 3 lat temu
rodzic
commit
c6633ac16c

+ 1 - 0
.gitignore

@@ -4,3 +4,4 @@ logs/
 run/
 .idea/
 package-lock.json
+data/

+ 14 - 0
app/controller/v1/example.js

@@ -21,6 +21,20 @@ class ExampleController extends BaseController {
     this.sendSuccess(data);
   }
 
+  /**
+   * test2
+   */
+  test2() {
+    const { ctx, service } = this;
+    const body = ctx.request.body;
+    console.log('test2 params:', body);
+    const data = {
+      age: 32
+    };
+
+    this.sendSuccess(data);
+  }
+
   async openLocalDir() {
     const self = this;
     const { ctx, service } = this;

+ 3 - 20
app/controller/v1/home.js

@@ -4,6 +4,9 @@ const BaseController = require('../base');
 
 class HomeController extends BaseController {
 
+  /**
+   * 单页应用入口(vue、react等)
+   */
   async index() {
     const { ctx } = this;
 
@@ -13,26 +16,6 @@ class HomeController extends BaseController {
 
     await ctx.render('index.ejs', data);
   }
-  
-  async hello() {
-    const { ctx } = this;
-
-    const data = {
-      title: 'hello'
-    };
-
-    this.sendSuccess(data);
-  }
-
-  async helloPage() {
-    const { ctx } = this;
-
-    const data = {
-      title: 'hello'
-    };
-
-    await ctx.render('hello.ejs', data);
-  }
 }
 
 module.exports = HomeController;

+ 1 - 14
app/extend/context.js

@@ -4,16 +4,6 @@
  */
 'use strict';
 module.exports = {
-  isMobile() {
-    const deviceAgent = this.get('user-agent').toLowerCase();
-    const agentID = deviceAgent.match(/(iphone|ipod|ipad|android)/);
-    if (agentID) {
-      // 手机访问
-      return true;
-    }
-    // 电脑访问
-    return false;
-  },
   success(msg, data, total) {
     this.body = {
       success: true,
@@ -28,8 +18,5 @@ module.exports = {
       msg,
       result: data,
     };
-  },
-  async infoPage(msg) {
-    await this.render('500', { msg });
-  },
+  }
 };

+ 2 - 0
app/router/example.js

@@ -35,6 +35,8 @@ module.exports = app => {
   router.post('/api/v1/example/selectFileDir', controller.v1.example.selectFileDir);
   // test some electron api
   router.post('/api/v1/example/testElectronApi', controller.v1.example.testElectronApi);
+  // test2
+  router.post('/api/v1/example/test2', controller.v1.example.test2);
   // message show
   router.post('/api/v1/example/messageShow', controller.v1.example.messageShow);
   // message show confirm

+ 22 - 0
app/schedule/example.js

@@ -0,0 +1,22 @@
+'use strict';
+
+const Subscription = require('egg').Subscription;
+
+/**
+ * test
+ */
+
+class Test extends Subscription {
+  static get schedule() {
+    return {
+      interval: '360m',
+      type: 'worker',
+      immediate: false,
+      disable: true,
+    };
+  }
+
+  async subscribe() {}
+}
+
+module.exports = Test;

+ 11 - 8
app/service/example.js

@@ -1,8 +1,17 @@
 'use strict';
 
-const BaseService = require('./base');
+const Service = require('egg').Service;
+const EeSocket = require('ee-core').Socket.EeSocket;
+const socketClient = EeSocket.getClient();
+
+class ExampleService extends Service {
+
+  async testElectronApi(id = 0) {
+    const res = await socketClient.call('controller.example.test', {name:"gsx"}, {age:12});
+
+    return null;
+  }
 
-class ExampleService extends BaseService {
   async openLocalDir(dir) {
     const self = this;
 
@@ -93,12 +102,6 @@ class ExampleService extends BaseService {
     return result.data;
   }
 
-  async testElectronApi(id = 0) {
-    await this.ipcCall('example.testElectronApi');
-
-    return null;
-  }
-
   async messageShow() {
     await this.ipcCall('example.messageShow');
 

+ 29 - 68
app/service/storage.js

@@ -1,73 +1,34 @@
 'use strict';
 
-const BaseService = require('./base');
-const path = require('path');
+const Storage = require('ee-core').Storage;
+const Service = require('egg').Service;
 const _ = require('lodash');
-const lowdb = require('lowdb');
-const FileSync = require('lowdb/adapters/FileSync');
-const storageKey = require('../const/storageKey');
-const fs = require('fs');
-const os = require('os');
-const utils = require('../utils/utils');
-const pkg = require('../../package.json');
-const storageDb = 'db.json';
 
-class StorageService extends BaseService {
-  /*
-   * instance
-   */
-  instance(file = null) {
-    if (!file) {
-      const storageDir = this.getStorageDir();
-      if (!fs.existsSync(storageDir)) {
-        utils.mkdir(storageDir);
-        utils.chmodPath(storageDir, '777');
-      }
-      file = path.normalize(storageDir + storageDb);
-    }
-    const isExist = fs.existsSync(file);
-    if (!isExist) {
-        return null;
-    }
-  
-    const adapter = new FileSync(file);
-    const db = lowdb(adapter);
-  
-    return db;
-  }
-
-  /*
-   * getElectronIPCPort
-   */
-  getElectronIPCPort() {
-    const key = storageKey.ELECTRON_IPC + '.port';
-    const port = this.instance()
-    .get(key)
-    .value();
-  
-    return port;
-  }
-
-  /*
-   * getStorageDir
-   */
-  getStorageDir() {
-    const userHomeDir = os.userInfo().homedir;
-    const storageDir = path.normalize(userHomeDir + '/' + pkg.name + '/');
-
-    return storageDir;
+class StorageService extends Service {
+
+  constructor () {
+    super();
+    this.systemDB = Storage.JsonDB.connection('system');
+    this.demoDB = Storage.JsonDB.connection('demo');  
+    this.systemDBKey = {
+      cache: 'cache'
+    };
+    this.demoDBKey = {
+      preferences: 'preferences',
+      test_data: 'test_data'
+    };
   }
 
   /*
    * 增 Test data
    */
   async addTestData(user) {
-    const key = storageKey.TEST_DATA;
-    if (!this.instance().has(key).value()) {
-      this.instance().set(key, []).write();
+    const key = this.demoDBKey.test_data;
+    if (!this.demoDB.has(key).value()) {
+      this.demoDB.set(key, []).write();
     }
     
-    const data = this.instance()
+    const data = this.demoDB
     .get(key)
     .push(user)
     .write();
@@ -79,8 +40,8 @@ class StorageService extends BaseService {
    * 删 Test data
    */
   async delTestData(name = '') {
-    const key = storageKey.TEST_DATA;
-    const data = this.instance()
+    const key = this.demoDBKey.test_data;
+    const data = this.demoDB
     .get(key)
     .remove({name: name})
     .write();
@@ -92,8 +53,8 @@ class StorageService extends BaseService {
    * 改 Test data
    */
   async updateTestData(name= '', age = 0) {
-    const key = storageKey.TEST_DATA;
-    const data = this.instance()
+    const key = this.demoDBKey.test_data;
+    const data = this.demoDB
     .get(key)
     .find({name: name}) // 修改找到的第一个数据,貌似无法批量修改 todo
     .assign({age: age})
@@ -106,8 +67,8 @@ class StorageService extends BaseService {
    * 查 Test data
    */
   async getTestData(age = 0) {
-    const key = storageKey.TEST_DATA;
-    let data = this.instance()
+    const key = this.demoDBKey.test_data;
+    let data = this.demoDB
     .get(key)
     //.find({age: age}) 查找单个
     .filter(function(o) {
@@ -130,11 +91,11 @@ class StorageService extends BaseService {
    * all Test data
    */
     async getAllTestData() {
-      const key = storageKey.TEST_DATA;
-      if (!this.instance().has(key).value()) {
-        this.instance().set(key, []).write();
+      const key = this.demoDBKey.test_data;
+      if (!this.demoDB.has(key).value()) {
+        this.demoDB.set(key, []).write();
       }
-      let data = this.instance()
+      let data = this.demoDB
       .get(key)
       .value();
   

+ 0 - 221
app/utils/index.js

@@ -1,228 +1,7 @@
 'use strict';
 
-// MD5加密工具
-const crypto = require('crypto');
-// 使用crypto进行MD5加密
-const md5 = crypto.createHash('md5');
-
-/* 通用函数集合 */
-// UTC时间格式化成本地时间
-exports.formatUTC = UTCDateString => {
-  if (!UTCDateString) {
-    return '-';
-  }
-  // 格式化显示
-  function formatFunc(str) {
-    return str > 9 ? str : '0' + str;
-  }
-  // 这步是关键
-  const date2 = new Date(UTCDateString);
-  const year = date2.getFullYear();
-  const mon = formatFunc(date2.getMonth() + 1);
-  const day = formatFunc(date2.getDate());
-  const hour = date2.getHours();
-  const min = date2.getMinutes();
-  const second = date2.getSeconds();
-
-  const dateStr =
-    year + '-' + mon + '-' + day + ' ' + hour + ':' + min + ':' + second;
-  return dateStr;
-};
-// 生成8位数的uid
-exports.createNewUid = () => {
-  /* 生成8位随机整数,不能有4位连续数字,不能有4位重复数字 */
-  // 4位重复数字
-  // let reg1 = /\d{4}/;
-  const reg1 = /([\d])\1{3}/;
-  // 4位连续数字
-  const reg2 = /(0(?=1)|1(?=2)|2(?=3)|3(?=4)|4(?=5)|5(?=6)|6(?=7)|7(?=8)|8(?=9)|9(?=0)){3}|(?:0(?=9)|9(?=8)|8(?=7)|7(?=6)|6(?=5)|5(?=4)|4(?=3)|3(?=2)|2(?=1)|1(?=0)){3}/;
-  // const numStr1 = '10122229';
-  // const numStr2 = '78902100';
-  // console.log(`reg1 is ${reg1.test(numStr1)}`);
-  // console.log(`reg2 is ${reg2.test(numStr2)}`);
-
-  // 生成uid(随机20次应该能有1次满足条件)
-  let uid = null;
-  for (let i = 0; i < 20; i++) {
-    // 生成随机整数(范围11111111到19878711)
-    uid = String(parseInt(Math.random() * 8767600) + 11111111);
-    // console.log(`uid is ${uid}`)
-    // const uid = "89016530";
-    // console.log(`reg1 is ${reg1.test(uid)}`);
-    // console.log(`reg2 is ${reg2.test(uid)}`);
-    if (!reg1.test(uid) && !reg2.test(uid)) {
-      // console.log(`uid is 1111`)
-      return uid;
-    }
-  }
-};
-
-// 生成密码加密的盐slat(8位字符串)
-exports.saltPwd = () => {
-  let str = '';
-  const arr = [
-    '0',
-    '1',
-    '2',
-    '3',
-    '4',
-    '5',
-    '6',
-    '7',
-    '8',
-    '9',
-    'a',
-    'b',
-    'c',
-    'd',
-    'e',
-    'f',
-    'g',
-    'h',
-    'i',
-    'j',
-    'k',
-    'l',
-    'm',
-    'n',
-    'o',
-    'p',
-    'q',
-    'r',
-    's',
-    't',
-    'u',
-    'v',
-    'w',
-    'x',
-    'y',
-    'z',
-  ];
-
-  let pos = null;
-  for (let i = 0; i < 8; i++) {
-    pos = Math.round(Math.random() * (arr.length - 1));
-    str += arr[pos];
-  }
-  return str;
-};
-// 生成随机字符串(数字(0-9),字母(a-z,A-Z))
-exports.randomWord = (randomFlag, min, max) => {
-  let str = '';
-  let range = min;
-  const arr = [
-    '0',
-    '1',
-    '2',
-    '3',
-    '4',
-    '5',
-    '6',
-    '7',
-    '8',
-    '9',
-    'a',
-    'b',
-    'c',
-    'd',
-    'e',
-    'f',
-    'g',
-    'h',
-    'i',
-    'j',
-    'k',
-    'l',
-    'm',
-    'n',
-    'o',
-    'p',
-    'q',
-    'r',
-    's',
-    't',
-    'u',
-    'v',
-    'w',
-    'x',
-    'y',
-    'z',
-    'A',
-    'B',
-    'C',
-    'D',
-    'E',
-    'F',
-    'G',
-    'H',
-    'I',
-    'J',
-    'K',
-    'L',
-    'M',
-    'N',
-    'O',
-    'P',
-    'Q',
-    'R',
-    'S',
-    'T',
-    'U',
-    'V',
-    'W',
-    'X',
-    'Y',
-    'Z',
-  ];
-
-  // 随机产生
-  if (randomFlag) {
-    range = Math.round(Math.random() * (max - min)) + min;
-  }
-  let pos = null;
-  for (let i = 0; i < range; i++) {
-    pos = Math.round(Math.random() * (arr.length - 1));
-    str += arr[pos];
-  }
-  return str;
-  // 使用方法
-  // 生成3-32位随机串:randomWord(true, 3, 32)
-  // 生成43位随机串:randomWord(false, 43)
-};
 // 生成两数之间随机数
 exports.randomNums = (min, max) => {
   return Math.round(Math.random() * (max - min) + min);
 };
-// 客户端密码加密
-exports.saltPwdMd5 = (password, saltPwd) => {
-  const md5 = crypto.createHash('md5');
-  // 加了盐的客户端密码
-  const saltPassword = password + ':' + saltPwd;
-  // 加盐的密码再用MD5加密
-  const saltPasswordMd5 = md5.update(saltPassword).digest('hex');
-  return saltPasswordMd5;
-};
-exports.createToken = data => {
-  // console.log(`data is ${JSON.stringify(data)}`);
-  const { uid, app } = data;
-  // 当前时间戳
-  const created = Math.floor(Date.now() / 1000);
-
-  const token = app.jwt.sign({ uid, created }, app.config.jwt.secret, {
-    expiresIn: '30d',
-  });
-
-  return token;
-};
-exports.createAdminToken = data => {
-  // console.log(`data is ${JSON.stringify(data)}`);
-  const { id, role, app } = data;
-  // 当前时间戳
-  const created = Math.floor(Date.now() / 1000);
 
-  const token = app.jwt.sign({ id, role, created }, app.config.jwt.secret, {
-    expiresIn: '30d',
-  });
-
-  return token;
-};

+ 7 - 22
config/config.default.js

@@ -1,8 +1,8 @@
-/* eslint valid-jsdoc: "off" */
-
 'use strict';
+
 const path = require('path');
-const electronEggConfig = require('../electron/config').get('webEgg');
+const Utils = require('ee-core').Utils;
+const eggConfig = Utils.getEggConfig();
 
 /**
  * @param {Egg.EggAppInfo} appInfo app info
@@ -21,23 +21,15 @@ module.exports = appInfo => {
   config.middleware = [];
 
   // add your user config here
-  const userConfig = {
-    // myAppName: 'egg',
-  };
+  const userConfig = {};
 
   config.cluster = {
     listen: {
-      port: electronEggConfig.port || 7068,
-      hostname: electronEggConfig.hostname || '0.0.0.0',
-      // path: '/var/run/egg.sock',
+      port: eggConfig.port || 7068,
+      hostname: eggConfig.hostname || '127.0.0.1',
     },
   };
 
-  // jwt插件配置(盐)
-  config.jwt = {
-    secret: 'jcgame88',
-  };
-
   /* 跨域插件配置-start */
   config.security = {
     xframe: {
@@ -50,7 +42,7 @@ module.exports = appInfo => {
       // 'http://127.0.0.1:8080'
     ],
     methodnoallow: { enable: false },
-    // 安全配置(很重要)
+    // 安全配置
     csrf: {
       enable: false,
       ignoreJSON: true, // 默认为 false,当设置为 true 时,将会放过所有 content-type 为 `application/json` 的请求
@@ -59,17 +51,10 @@ module.exports = appInfo => {
   // 允许的跨域请求类型(GET,POST)
   config.cors = {
     origin: '*',
-    // allowMethods: 'GET,POST',
     allowMethods: 'GET,POST,HEAD,PUT,OPTIONS,DELETE,PATCH',
   };
   /* 跨域插件配置-end */
 
-  // 校验插件配置(支持 parameter的所有配置项)
-  config.validate = {
-    // convert: false,
-    // validateRoot: false,
-  };
-
   // 获取真实ip
   config.maxProxyCount = 2;
   

+ 7 - 10
config/config.local.js

@@ -1,13 +1,10 @@
 'use strict';
-// 本地环境-配置文件
-const storageDir = require('../electron/lib/storage').getStorageDir();
-
-/*
- * 远程调用
- */
-exports.outApi = {
-  login: 'http://local.com/api/login',
-};
+
+const Utils = require('ee-core').Utils;
+const logDir = Utils.getLogDir();
+
 exports.logger = {
-  dir: storageDir + 'logs/local',
+  dir: logDir,
 };
+
+

+ 7 - 10
config/config.prod.js

@@ -1,14 +1,11 @@
 'use strict';
-// 本地环境-配置文件
-const storageDir = require('../electron/lib/storage').getStorageDir();
-
-/*
- * 远程调用
- */
-exports.outApi = {
-  login: 'http://api.local.com/api/login',
-};
+
+const Utils = require('ee-core').Utils;
+const logDir = Utils.getLogDir();
+
 exports.logger = {
-  dir: storageDir + 'logs/prod',
+  dir: logDir,
 };
 
+
+

+ 0 - 6
config/plugin.js

@@ -4,12 +4,6 @@
  *Egg插件
  */
 
-// jwt登录状态验证插件
-exports.jwt = {
-  enable: true,
-  package: 'egg-jwt',
-};
-
 // 跨域插件
 exports.cors = {
   enable: true,

+ 102 - 0
electron/config/config.default.js

@@ -0,0 +1,102 @@
+'use strict';
+
+const dayjs = require('dayjs');
+
+/**
+ * 默认配置
+ */
+module.exports = (appInfo) => {
+  /**
+   * built-in config
+   * @type {Ee.EeAppConfig}
+   **/
+  const config = {};
+
+  /* 开发模式配置 */
+  config.developmentMode = {
+    default: 'vue',
+    mode: {
+      vue: {
+        hostname: 'localhost',
+        port: 8080
+      },
+      react: {
+        hostname: 'localhost',
+        port: 3000
+      },
+      ejs: {
+        hostname: 'localhost',
+        port: 7068 // The same as the egg port
+      }
+    }
+  };
+
+  /* 开发者工具 */
+  config.openDevTools = false;
+
+  /* 应用程序顶部菜单 */
+  config.openAppMenu = false;
+
+  /* 主窗口 */
+  config.windowsOption = {
+    width: 980,
+    height: 650,
+    minWidth: 800,
+    minHeight: 650,
+    webPreferences: {
+      //webSecurity: false,
+      contextIsolation: false, // 设置此项为false后,才可在渲染进程中使用electron api
+      nodeIntegration: true,
+    },
+    frame: true,
+    //titleBarStyle: 'hidden'
+  };
+
+  /* ee框架日志 */
+  config.logger = {
+    appLogName: `ee-${dayjs().format('YYYY-MM-DD')}.log`, 
+    errorLogName: `ee-error-${dayjs().format('YYYY-MM-DD')}.log` 
+  }
+
+  /* 远程web地址 (可选) */
+  config.remoteUrl = {
+    enable: false, // 是否启用
+    url: 'https://discuz.chat/' // Any web url
+  };
+
+  /* egg服务 (可选) */
+  config.egg = {
+    title: 'electron-egg', // 进程的title属性标识(默认你的应用名称-英文)
+    port: 7068,
+    hostname: '127.0.0.1',
+    workers: 1 // 工作进程数据
+  };
+
+  /* 应用自动升级 (可选) */
+  config.autoUpdate = {
+    windows: false, // windows平台
+    macOS: false, // macOs 需要签名验证
+    linux: false, // linux平台
+    options: {
+      provider: 'generic', // or github, s3, bintray
+      url: 'http://kodo.qiniu.com/' // resource dir, end with '/'
+    },
+    force: false, // 强制更新(运行软件时,检查新版本并后台下载安装)
+  };
+
+  /* 被浏览器唤醒 (可选) */
+  config.awakeProtocol = {
+    protocol: 'electron-egg', // 自定义协议名(默认你的应用名称-英文)
+    args: []
+  };
+
+  /* 托盘 (可选)  */
+  config.tray = {
+    title: 'EE程序', // 托盘显示标题
+    icon: '/public/images/tray_logo.png' // 托盘图标
+  }
+
+  return {
+    ...config
+  };
+}

+ 8 - 0
electron/config/config.local.js

@@ -0,0 +1,8 @@
+'use strict';
+
+/*
+ * test
+ */
+exports.testConfig = {
+  login: 'http://local.com/api/login',
+};

+ 8 - 0
electron/config/config.prod.js

@@ -0,0 +1,8 @@
+'use strict';
+
+/*
+ * test
+ */
+exports.testConfig = {
+  login: 'http://prod.com/api/login',
+};

+ 38 - 0
electron/controller/example.js

@@ -0,0 +1,38 @@
+'use strict';
+
+const Controller = require('ee-core').Controller;
+const { app } = require('electron');
+
+class ExampleController extends Controller {
+
+  /**
+   * test
+   */
+  async test (args) {
+    let obj = {
+      status:'ok'
+    }
+
+    // 调用egg的某个api
+    // const result = await this.app.curlEgg('post', '/api/v1/example/test2', {name: 'gsx2'});
+    // console.log('fffffffffff: ', result);
+    //this.app.logger.info('ssssssssssssssssssss');
+
+    return obj;
+  }
+
+  /**
+   * hello
+   */
+  hello (args, event) {
+    let newMsg = args + " +1";
+    let reply = '';
+    reply = '收到:' + args + ',返回:' + newMsg;
+
+    // let channel = "example.socketMessageStop";
+    // event.reply(`${channel}`, '另外的数据');
+    return reply;
+  }
+}
+
+module.exports = ExampleController;

+ 148 - 0
electron/library/autoUpdater.js

@@ -0,0 +1,148 @@
+'use strict';
+
+const {app} = require('electron');
+const updater = require("electron-updater");
+const autoUpdater = updater.autoUpdater;
+const path = require('path');
+
+/**
+ * 自动升级模块
+ */
+module.exports = {
+
+  /**
+   * 安装
+   */
+  install (eeApp) {
+    console.log('[preload] load AutoUpdater module');
+
+    const status = {
+      error: -1,
+      available: 1,
+      noAvailable: 2,
+      downloading: 3,
+      downloaded: 4,
+    }
+
+    const updateConfig = eeApp.config.autoUpdate;
+    const mainWindow = eeApp.electron.mainWindow;
+    const version = app.getVersion();
+    console.log('[preload:autoUpdater] current version: ', version);
+  
+    // 设置下载服务器地址
+    let server = updateConfig.options.url;
+    let lastChar = server.substring(server.length - 1);
+    server = lastChar === '/' ? server : server + "/";
+    console.log('[preload:autoUpdater] server: ', server);
+    updateConfig.options.url = server;
+  
+    // 是否后台自动下载
+    autoUpdater.autoDownload = updateConfig.force ? true : false;
+    if (process.env.EE_SERVER_ENV == 'local') {
+      autoUpdater.updateConfigPath = path.join(__dirname, '../../out/dev-app-update.yml')
+    }
+  
+    try {
+      autoUpdater.setFeedURL(updateConfig.options);
+    } catch (error) {
+      eeApp.logger.error('[preload:autoUpdater] setFeedURL error : ', error);
+    }
+  
+    autoUpdater.on('checking-for-update', () => {
+      //sendStatusToWindow('正在检查更新...');
+    })
+    autoUpdater.on('update-available', (info) => {
+      info.status = status.available;
+      info.desc = '有可用更新';
+      sendStatusToWindow(mainWindow, info);
+    })
+    autoUpdater.on('update-not-available', (info) => {
+      info.status = status.noAvailable;
+      info.desc = '没有可用更新';
+      sendStatusToWindow(mainWindow, info);
+    })
+    autoUpdater.on('error', (err) => {
+      let info = {
+        status: status.error,
+        desc: err
+      }
+      sendStatusToWindow(mainWindow, info);
+    })
+    autoUpdater.on('download-progress', (progressObj) => {
+      let percentNumber = parseInt(progressObj.percent);
+      let totalSize = bytesChange(progressObj.total);
+      let transferredSize = bytesChange(progressObj.transferred);
+      let text = '已下载 ' + percentNumber + '%';
+      text = text + ' (' + transferredSize + "/" + totalSize + ')';
+  
+      let info = {
+        status: status.downloading,
+        desc: text,
+        percentNumber: percentNumber,
+        totalSize: totalSize,
+        transferredSize: transferredSize
+      }
+      sendStatusToWindow(mainWindow, info);
+    })
+    autoUpdater.on('update-downloaded', (info) => {
+      info.status = status.downloaded;
+      info.desc = '下载完成';
+      sendStatusToWindow(mainWindow, info);
+      // quit and update
+      eeApp.appQuit();
+      autoUpdater.quitAndInstall();
+    });
+    
+
+  },
+
+  /**
+   * 检查更新
+   */
+  checkUpdate () {
+    autoUpdater.checkForUpdates();
+  },
+  
+  /**
+   * 下载更新
+   */
+  download () {
+    autoUpdater.downloadUpdate();
+  },
+
+
+}
+
+/**
+ * 向前端发消息
+ */
+function sendStatusToWindow(mainWindow, content = {}) {
+  const textJson = JSON.stringify(content);
+  eLogger.info(textJson);
+  const channel = 'app.updater';
+  mainWindow.webContents.send(channel, textJson);
+}
+ 
+function bytesChange (limit) {
+  let size = "";
+  if(limit < 0.1 * 1024){                            
+    size = limit.toFixed(2) + "B";
+  }else if(limit < 0.1 * 1024 * 1024){            
+    size = (limit/1024).toFixed(2) + "KB";
+  }else if(limit < 0.1 * 1024 * 1024 * 1024){        
+    size = (limit/(1024 * 1024)).toFixed(2) + "MB";
+  }else{                                            
+    size = (limit/(1024 * 1024 * 1024)).toFixed(2) + "GB";
+  }
+
+  let sizeStr = size + "";                        
+  let index = sizeStr.indexOf(".");                    
+  let dou = sizeStr.substring(index + 1 , index + 3);            
+  if(dou == "00"){
+      return sizeStr.substring(0, index) + sizeStr.substring(index + 3, index + 5);
+  }
+
+  return size;
+}
+
+  

+ 56 - 0
electron/library/awaken.js

@@ -0,0 +1,56 @@
+'use strict';
+
+const { app } = require('electron');
+
+/**
+ * 应用唤醒模块
+ */
+module.exports = {
+
+  /**
+   * 安装
+   */     
+  install (eeApp) {
+    console.log('[preload] load awaken module');
+    const protocolInfo = eeApp.config.awakeProtocol;
+    const PROTOCOL = protocolInfo.protocol;
+  
+    app.setAsDefaultProtocolClient(PROTOCOL);
+  
+    handleArgv(process.argv);
+  
+    app.on('second-instance', (event, argv) => {
+      if (process.platform === 'win32') {
+        handleArgv(argv)
+      }
+    })
+  
+    // 仅用于macOS
+    app.on('open-url', (event, urlStr) => {
+      handleUrl(urlStr)
+    })
+  
+    // 参数处理
+    function handleArgv(argv) {
+      const offset = app.isPackaged ? 1 : 2;
+      const url = argv.find((arg, i) => i >= offset && arg.startsWith(PROTOCOL));
+      handleUrl(url)
+    }
+
+    // url解析
+    function handleUrl(awakeUrlStr) {
+      if (!awakeUrlStr || awakeUrlStr.length === 0) {
+        return
+      }
+      const {hostname, pathname, search} = new URL(awakeUrlStr);
+      let awakeUrlInfo = {
+        urlStr: awakeUrlStr,
+        urlHost: hostname,
+        urlPath: pathname,
+        urlParams: search && search.slice(1)
+      }
+      console.log('[awaken] [handleUrl] awakeUrlInfo:', awakeUrlInfo);
+    }
+  }
+}
+

+ 88 - 0
electron/library/chromeExtension.js

@@ -0,0 +1,88 @@
+'use strict';
+
+const { app, session } = require('electron');
+const _ = require('lodash');
+const fs = require('fs');
+const path = require('path');
+
+/**
+ * chrome扩展模块
+ */
+module.exports = {
+
+  /**
+   * 安装
+   */   
+  install (eeApp) {
+    console.log('[preload] load chrome extension module');
+    const extensionIds = this.getAllIds();
+    
+    for (let i = 0; i < extensionIds.length; i++) {
+      await this.load(extensionIds[i]);
+    }
+  },
+
+  /**
+   * 获取扩展id列表(crx解压后的目录名,即是该扩展的id)
+   */
+  getAllIds () {
+    const extendsionDir = this.getDirectory();
+    const ids = getDirs(extendsionDir);
+
+    return ids;
+  },
+
+  /**
+   * 扩展所在目录
+   */
+  getDirectory () {
+    let extensionDirPath = '';
+    let variablePath = 'build'; // 打包前路径
+    if (app.isPackaged) {
+      variablePath = '..'; // 打包后路径
+    }
+    extensionDirPath = path.join(app.getAppPath(), variablePath, "extraResources", "chromeExtension");
+  
+    return extensionDirPath;
+  },
+
+  /**
+   * 加载扩展
+   */
+  load (extensionId = '') {
+    if (_.isEmpty(extensionId)) {
+      return false
+    }
+    
+    try {
+      const extensionPath = path.join(this.getDirectory(), extensionId);
+      console.log('[chromeExtension] [load] extensionPath:', extensionPath);
+      await session.defaultSession.loadExtension(extensionPath, { allowFileAccess: true });
+    } catch (e) {
+     console.log('[chromeExtension] [load] load extension error extensionId:%s, errorInfo:%s', extensionId, e.toString());
+      return false
+    }
+  
+    return true
+  }
+}
+
+/**
+ * 获取目录下所有文件夹
+ */
+function getDirs(dir) {
+  if (!dir) {
+    return [];
+  }
+
+  const components = [];
+  const files = fs.readdirSync(dir);
+  files.forEach(function(item, index) {
+    const stat = fs.lstatSync(dir + '/' + item);
+    if (stat.isDirectory() === true) {
+      components.push(item);
+    }
+  });
+
+  return components;
+};

+ 26 - 0
electron/library/security.js

@@ -0,0 +1,26 @@
+'use strict';
+
+/**
+ * 安全模块
+ */
+
+module.exports = {
+  
+  /**
+   * 安装
+   */  
+  install (eeApp) {
+    console.log('[preload] load security module');
+    const runWithDebug = process.argv.find(function(e){
+      let isHasDebug = e.includes("--inspect") || e.includes("--inspect-brk") || e.includes("--remote-debugging-port");
+      return isHasDebug;
+    })
+  
+    // 不允许远程调试
+    if (runWithDebug) {
+      console.log('[error] Remote debugging is not allowed,  runWithDebug:', runWithDebug);
+      eeApp.appQuit();
+    }
+  }
+
+}

+ 69 - 0
electron/library/tray.js

@@ -0,0 +1,69 @@
+'use strict';
+
+const {Tray, Menu} = require('electron');
+const path = require('path');
+
+/**
+ * 托盘模块
+ */
+
+module.exports = {
+
+  /**
+   * 安装
+   */
+  install (eeApp) {
+    console.log('[preload] load tray module');
+    const trayConfig = eeApp.config.tray;
+    const mainWindow = eeApp.electron.mainWindow;
+
+    // 托盘图标
+    let iconPath = path.join(eeApp.config.homeDir, trayConfig.icon);
+  
+    // 托盘菜单功能列表
+    let trayMenuTemplate = [
+      {
+        label: '显示',
+        click: function () {
+          mainWindow.show();
+        }
+      },
+      {
+        label: '退出',
+        click: function () {
+          eeApp.appQuit();
+        }
+      }
+    ]
+  
+    // 点击关闭,最小化到托盘
+    mainWindow.on('close', (event) => {
+      mainWindow.hide();
+      mainWindow.setSkipTaskbar(true);
+      event.preventDefault();
+    });
+    mainWindow.show();
+
+    // 测试发现:创建的Tray对象实例变量和app.whenReady()在同一模块中定义才行
+    // 赋值给eeApp.electron.tray,已在框架ee-core包中定义
+    // 如果赋值给其它变量,可能出现异常,估计是electron的bug
+    
+    eeApp.electron.tray = new Tray(iconPath);
+    let appTray = eeApp.electron.tray;
+
+    appTray.setToolTip(trayConfig.title); // 托盘标题
+    const contextMenu = Menu.buildFromTemplate(trayMenuTemplate);
+    appTray.setContextMenu(contextMenu);
+  
+    // 监听 显示/隐藏
+    appTray.on('click', function(){
+      if (mainWindow.isVisible()) {
+        mainWindow.hide();
+        mainWindow.setSkipTaskbar(false);
+      } else {
+        mainWindow.show();
+        mainWindow.setSkipTaskbar(true);
+      }
+    });
+  }
+}

+ 45 - 0
electron/preload/index.js

@@ -0,0 +1,45 @@
+'use strict';
+
+/*************************************************
+ ** preload为预加载模块,该文件将会在程序启动时加载 **
+ *************************************************/
+
+const is = require('electron-is');
+const tray = require('../library/tray');
+const security = require('../library/security');
+const awaken = require('../library/awaken');
+const chromeExtension = require('../library/chromeExtension');
+
+/**
+ * 预加载模块入口
+ */
+module.exports = async (app) => {
+
+  //已实现的功能模块,可选择性使用和修改
+
+  tray.install(app);
+
+  security.install(app);
+
+  awaken.install(app);
+
+  chromeExtension.install(app);
+
+  loadUpdate(app);
+}
+
+/**
+ * 加载自动升级模块
+ */
+function loadUpdate (app) {
+  const config = app.config.autoUpdate;
+  if ( (is.windows() && config.windows) || (is.macOS() && config.macOS) || (is.linux() && config.linux) ) {
+    const autoUpdater = require('../library/autoUpdater');
+    autoUpdater.install();
+
+    // 是否检查更新
+    if (config.force) {
+      autoUpdater.checkUpdate();
+    }
+  }
+}

+ 1 - 1
frontend/src/views/demo/socket/Index.vue

@@ -70,7 +70,7 @@ export default {
     },
     helloHandle(value) {
       const self = this;
-      this.$ipcCallMain('example.hello', value).then(r => {
+      this.$ipcCallMain('controller.example.hello', value).then(r => {
         self.$message.info(r);
       })
     },

+ 38 - 2
main.js

@@ -1,6 +1,42 @@
-const EeApp = require('ee-core').EeAppliaction;
+const Appliaction = require('ee-core').Appliaction;
+const { app } = require('electron');
 
-new EeApp();
+class Main extends Appliaction {
+
+  constructor() {
+    super();
+  }
+
+  /**
+   * core app have been loaded
+   */
+  async ready () {
+    // do some things
+  }
+
+  /**
+   * main window have been loaded
+   */
+  async windowReady () {
+    // do some things
+
+    // const app = this;
+    // // preload预加载模块
+    // const preload = require('./electron/preload');
+    // preload(app);
+
+  }
+
+  /**
+   * before app close
+   */  
+  async beforeClose () {
+    // do some things
+
+  }
+}
+
+new Main();
 
 
  

+ 10 - 6
package.json

@@ -4,8 +4,9 @@
   "description": "A fast, desktop software development framework",
   "main": "main.js",
   "scripts": {
-    "start": "electron .",
+    "start": "electron . ",
     "dev": "electron . --env=local",
+    "test": "set DEBUG=* && electron . --env=local",
     "build-w": "electron-builder -w --ia32",
     "build-w-64": "electron-builder -w --x64",
     "build-m": "electron-builder -m",
@@ -29,7 +30,9 @@
     "files": [
       "**/*",
       "!frontend/",
-      "!run/"
+      "!run/",
+      "!logs/",
+      "!data/"
     ],
     "extraResources": {
       "from": "./build/extraResources/",
@@ -96,10 +99,11 @@
     "eslint-plugin-prettier": "^3.0.1"
   },
   "dependencies": {
+    "dayjs": "^1.10.7",
     "egg": "^2.33.1",
-    "egg-scripts": "^2.13.0",
-    "egg-view-ejs": "^2.0.0",
-    "electron-updater": "^4.3.5",
-    "lodash": "^4.17.21"
+    "egg-cluster": "^1.27.1",
+    "egg-cors": "^2.2.3",
+    "egg-scripts": "^2.15.2",
+    "egg-view-ejs": "^2.0.1"
   }
 }

+ 1 - 1
asset/loading.html → public/html/loading.html

@@ -16,7 +16,7 @@
  </head> 
  <body> 
   <div id="picture1">
-   <img src="./images/loding.gif" />
+   <img src="../images/loding.gif" />
   </div>  
  </body>
 </html>

+ 0 - 0
asset/view_example.html → public/html/view_example.html


+ 0 - 0
asset/images/loding.gif → public/images/loding.gif


+ 0 - 0
asset/images/tray_logo.png → public/images/tray_logo.png