Pārlūkot izejas kodu

Merge branch 'ee_dev'

gaoshuaixing 3 gadi atpakaļ
vecāks
revīzija
efe4e020a0

+ 1 - 1
README.md

@@ -16,7 +16,7 @@
 - 🍩 **Why?** desktop software ( office direction , personal tools ), still Yes PC in the next ten years one of the requirements is to improve work efficiency
 - 🍉 **Simple:** just understand JavaScript
 - 🍑 **Vision:** all developers can learn how to develop desktop software
-- 🍰 **Gitee:** https://gitee.com/wallace5303/electron-egg **2000+**
+- 🍰 **Gitee:** https://gitee.com/wallace5303/electron-egg **2200+**
 - 🍨 **Github:** https://github.com/wallace5303/electron-egg **500+**
 - 🏆 most valuable open source project
     ![](https://wallace5303.gitee.io/ee/images/electron-egg/ee-zs.png)    

+ 1 - 1
README.zh-CN.md

@@ -16,7 +16,7 @@
 - 🍩 **为什么使用?** 桌面软件(办公方向、 个人工具),仍然是未来十几年PC端需求之一,提高工作效率
 - 🍉 **简单:** 只需懂 JavaScript
 - 🍑 **愿景:** 所有开发者都能学会桌面软件研发
-- 🍰 **gitee:** https://gitee.com/wallace5303/electron-egg **2000+**
+- 🍰 **gitee:** https://gitee.com/wallace5303/electron-egg **2200+**
 - 🍨 **github:** https://github.com/wallace5303/electron-egg **500+**
 - 🏆 码云最有价值开源项目
     ![](https://wallace5303.gitee.io/ee/images/electron-egg/ee-zs.png)    

+ 23 - 0
electron/addon/test/index.js

@@ -0,0 +1,23 @@
+/**
+ * test插件
+ * @class
+ */
+class TestAddon {
+
+  constructor(app) {
+    this.app = app;
+  }
+
+  /**
+   * 销毁窗口Contents id
+   *
+   * @function 
+   * @since 1.0.0
+   */
+  hello () {
+    return 'hello';
+  }  
+}
+
+TestAddon.toString = () => '[class TestAddon]';
+module.exports = TestAddon;

+ 49 - 15
electron/config/config.default.js

@@ -14,7 +14,9 @@ module.exports = (appInfo) => {
    **/
   const config = {};
 
-  /* 应用模式配置 */
+  /**
+   * 应用模式配置
+   */
   config.developmentMode = {
     default: 'vue',
     mode: {
@@ -33,7 +35,9 @@ module.exports = (appInfo) => {
     }
   };
 
-  /* 开发者工具 */
+  /**
+   * 开发者工具
+   */
   config.openDevTools = false;
 
   /**
@@ -47,35 +51,41 @@ module.exports = (appInfo) => {
    * 主窗口
    */
   config.windowsOption = {
+    title: 'EE框架',
     width: 980,
     height: 650,
     minWidth: 800,
     minHeight: 650,
     webPreferences: {
-      //webSecurity: false,
-      contextIsolation: false, // false->可在渲染进程中使用electronApi,true->需要bridge.js(contextBridge)
+      //webSecurity: false, // 跨域问题 -> 打开注释
+      contextIsolation: false, // false -> 可在渲染进程中使用electron的api,true->需要bridge.js(contextBridge)
       nodeIntegration: true,
       //preload: path.join(appInfo.baseDir, 'preload', 'bridge.js'),
     },
     frame: true,
     show: true,
-    //backgroundColor: '#000000'
-    //titleBarStyle: 'hidden'
+    icon: path.join(appInfo.home, 'public', 'images', 'logo-32.png'),
   };
 
-  /* ee框架日志 */
+  /**
+   * ee框架日志
+   */  
   config.logger = {
     appLogName: `ee-${dayjs().format('YYYY-MM-DD')}.log`, 
     errorLogName: `ee-error-${dayjs().format('YYYY-MM-DD')}.log` 
   }
 
-  /* 远程web地址 (可选) */
+  /**
+   * 远程web地址 (可选)
+   */    
   config.remoteUrl = {
     enable: false, // 是否启用
     url: 'https://discuz.chat/' // Any web url
   };
 
-  /* 内置socket服务 */
+  /**
+   * 内置socket服务
+   */   
   config.socketServer = {
     enable: false, // 是否启用
     port: 7070, // 默认端口(如果端口被使用,则随机获取一个)
@@ -90,7 +100,9 @@ module.exports = (appInfo) => {
     }
   };
 
-  /* 内置http服务 */
+  /**
+   * 内置http服务
+   */     
   config.httpServer = {
     enable: false, // 是否启用
     https: {
@@ -116,7 +128,9 @@ module.exports = (appInfo) => {
     }
   };
 
-  /* 主进程 */
+  /**
+   * 主进程
+   */     
   config.mainServer = {
     host: '127.0.0.1',
     port: 7072, // 默认端口(如果端口被使用,则随机获取一个)
@@ -129,7 +143,9 @@ module.exports = (appInfo) => {
     enable: false
   };
 
-  /* 应用自动升级 (可选) */
+  /**
+   * 应用自动升级 (可选)
+   */   
   config.autoUpdate = {
     windows: false, // windows平台
     macOS: false, // macOs 需要签名验证
@@ -141,17 +157,35 @@ module.exports = (appInfo) => {
     force: false, // 强制更新(运行软件时,检查新版本并后台下载安装)
   };
 
-  /* 被浏览器唤醒 (可选) */
+  /**
+   * 被浏览器唤醒 (可选)
+   */     
   config.awakeProtocol = {
     protocol: 'ee', // 自定义协议名(默认你的应用名称-英文)
     args: []
   };
 
-  /* 托盘 (可选)  */
+  /**
+   * 托盘 (可选)
+   */    
   config.tray = {
     title: 'EE程序', // 托盘显示标题
     icon: '/public/images/tray_logo.png' // 托盘图标
-  }
+  };
+
+  /**
+   * 插件功能
+   * @member window -> 官方内置插件
+   * @member test -> demo插件
+   */
+  config.addons = {
+    window: {
+      enable: true,
+    },
+    test: {
+      enable: true, 
+    }
+  };
 
   return {
     ...config

+ 6 - 4
electron/config/encrypt.js

@@ -1,11 +1,13 @@
 /**
  * 加密配置
+ * @param {String} type - strict (first confusion and then bytecode) || bytecode || confusion
+ * @param {Array} directory - directory to be encrypted
+ * @param {Array} fileExt - file suffix to be encrypted, currently only .js is supported
  */
-module.exports = {
-  type: 'bytecode', // bytecode | confusion
+ module.exports = {
+  type: 'strict',
   directory: [
     'electron'
   ],
   fileExt: ['.js'],
-};
-
+};

+ 57 - 30
electron/controller/example.js

@@ -210,22 +210,49 @@ class ExampleController extends Controller {
     let content = null;
     if (args.type == 'html') {
       content = path.join('file://', electronApp.getAppPath(), args.content)
-    } else {
+    } 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
     }
 
-    let winObj = new BrowserWindow({
-      x: 10,
-      y: 10,
-      width: 980, 
-      height: 650 
-    })
-    winObj.loadURL(content);
+    console.log('url:', content);
+    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;
 
-    return winObj.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) {
@@ -496,27 +523,6 @@ class ExampleController extends Controller {
   }
 
   /**
-   * 上传文件
-   */  
-  async uploadFile() {
-    // const self = this;
-    // const { ctx, service } = this;
-    // let tmpDir = Utils.getLogDir();
-    // const file = ctx.request.files[0];
-
-    // try {
-    //   let tmpFile = fs.readFileSync(file.filepath)
-    //   fs.writeFileSync(path.join(tmpDir, file.filename), tmpFile)
-    // } finally {
-    //   await fs.unlink(file.filepath, function(){});
-    // }
-    // const fileStream = fs.createReadStream(path.join(tmpDir, file.filename))
-    // const uploadRes = await service.example.uploadFileToSMMS(fileStream);
-
-    // return uploadRes;
-  }
-
-  /**
    * 检测http服务是否开启
    */ 
   async checkHttpServer () {
@@ -623,6 +629,27 @@ class ExampleController extends Controller {
   }
 
   /**
+   * 上传文件
+   */  
+  async uploadFile() {
+    let tmpDir = Utils.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;
+  }
+
+  /**
    * 测试接口
    */ 
   hello (args) {

+ 39 - 0
electron/service/example.js

@@ -23,6 +23,45 @@ class ExampleService extends Service {
 
     return obj;
   }
+
+  /**
+   * 上传到smms
+   */
+  async uploadFileToSMMS(tmpFile) {
+    const res = {
+      code: 1000,
+      message: 'unknown error',
+    };
+
+    try {
+      const headersObj = {
+        'Content-Type': 'multipart/form-data',
+        'Authorization': 'aaaaaaaaaaaaa' // 请修改这个token,用你自己的账号token
+      };
+      const url = 'https://sm.ms/api/v2/upload';
+      const response = await this.app.curl(url, {
+        method: 'POST',
+        headers: headersObj,
+        files: {
+          smfile: tmpFile,
+        },
+        dataType: 'json',
+        timeout: 15000,
+      });
+      const result = response.data;
+      if (this.app.config.env === 'local') {
+        this.app.logger.info('[ExampleService] [uploadFileToSMMS]: info result:%j', result);
+      }
+      if (result.code !== 'success') {
+        this.app.logger.error('[ExampleService] [uploadFileToSMMS]: res error result:%j', result);
+      }
+      return result;
+    } catch (e) {
+      this.app.logger.error('[ExampleService] [uploadFileToSMMS]:  ERROR ', e);
+    }
+
+    return res;
+  }    
 }
 
 ExampleService.toString = () => '[class ExampleService]';

+ 2 - 2
frontend/public/index.html

@@ -4,7 +4,7 @@
     <meta charset="utf-8">
     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     <meta name="viewport" content="width=device-width,initial-scale=1.0">
-    <title><%= htmlWebpackPlugin.options.title %></title>
+    <title></title>
     <style>
       /* 滚动条 */
       ::-webkit-scrollbar{width:8px;height:4px}
@@ -17,7 +17,7 @@
   </head>
   <body>
     <noscript>
-      <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
+      <strong>We're sorry but it doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
     </noscript>
     <div id="app"></div>
   </body>

+ 10 - 1
frontend/src/api/main.js

@@ -1,6 +1,9 @@
 import storage from 'store2'
 import request from '@/utils/request'
 
+/**
+ * 路由定义(主进程与渲染进程通信频道定义)
+ */
 const ipcApiRoute = {
   test: 'controller.example.test',
   messageShow: 'controller.example.messageShow',
@@ -28,11 +31,17 @@ const ipcApiRoute = {
   ipcInvokeMsg: 'controller.example.ipcInvokeMsg',
   ipcSendSyncMsg: 'controller.example.ipcSendSyncMsg',
   ipcSendMsg: 'controller.example.ipcSendMsg',
+  getWCid: 'controller.example.getWCid',
   hello: 'controller.example.hello',
 }
 
+/**
+ * 特殊的路由(频道)定义
+ */
 const specialIpcRoute = {
-  appUpdater: 'app.updater' // 此频道在后端也有相同定义
+  appUpdater: 'app.updater', // 此频道在后端也有相同定义
+  window1ToWindow2: 'window1-to-window2', // 窗口之间通信
+  window2ToWindow1: 'window2-to-window1', // 窗口之间通信
 }
 
 /**

+ 18 - 1
frontend/src/config/router.config.js

@@ -4,6 +4,11 @@
  */
 import {AppSider, Menu} from '@/layouts'
 
+const RouteView = {
+  name: 'RouteView',
+  render: h => h('router-view')
+}
+
 export const constantRouterMap = [
   {
     path: '/',
@@ -113,5 +118,17 @@ export const constantRouterMap = [
         ] 
       }
     ]
-  }
+  },
+  {
+    path: '/special',
+    component: RouteView,
+    //redirect: '/special/subwindow',
+    children: [
+      {
+        path: 'subwindow',
+        name: 'SpecialSubwindowIpc',
+        component: () => import('@/views/base/subwindow/Ipc')
+      }
+    ]
+  },
 ]

+ 73 - 9
frontend/src/views/base/file/Index.vue

@@ -1,13 +1,5 @@
 <template>
   <div id="app-base-file">
-    <div class="one-block-2">
-      <a-list v-if="image_info.length !== 0" size="small" bordered :data-source="image_info">
-        <a-list-item slot="renderItem" slot-scope="item" style="text-align:left;">
-          {{ item.id }}.&nbsp;{{ item.imageUrlText }}:&nbsp;
-          <a :href="item.url" target="_blank">{{ item.url }}</a>
-        </a-list-item>
-      </a-list>
-    </div>
     <div class="one-block-1">
       <span>
         1. 系统原生对话框
@@ -38,7 +30,7 @@
     </div>      
     <div class="one-block-1">
       <span>
-        4. 打开文件夹
+        3. 打开文件夹
       </span>
     </div>  
     <div class="one-block-2">
@@ -52,11 +44,35 @@
         </a-list-item>
       </a-list>
     </div>
+    <div class="one-block-1">
+      <span>
+        4. 上传文件到图床
+      </span>
+    </div>  
+    <div class="one-block-2">
+      <a-upload-dragger
+        name="file"
+        :multiple="true"
+        :action="action_url"
+        @change="handleFileChange"
+      >
+        <p class="ant-upload-drag-icon">
+          <a-icon type="inbox" />
+        </p>
+        <p class="ant-upload-text">
+          点击 或 拖拽文件到这里
+        </p>
+        <p class="ant-upload-hint">
+          注意:请使用您自己的图床token
+        </p>
+      </a-upload-dragger>
+    </div>
     <div class="footer">
     </div>
   </div>
 </template>
 <script>
+import storage from 'store2'
 import { ipcApiRoute } from '@/api/main'
 
 const fileList = [
@@ -82,12 +98,33 @@ export default {
   data() {
     return {
       file_list: fileList,
+      action_url: '',
       image_info: [],
       num: 0,
+      servicAddress: '',
 			dir_path: "D:\\www\\ee",
     };
   },
+  mounted () {
+    this.getHost();
+  },
   methods: {
+    getHost () {
+      const self = this;
+      this.$ipcInvoke(ipcApiRoute.checkHttpServer, {}).then(r => {
+        if (r.enable) {
+          self.servicAddress = r.server;
+          storage.set('httpServiceConfig', r);
+
+          // url转换
+          const host = r.server || 'http://127.0.0.1:7071';
+          let uri = ipcApiRoute.uploadFile;
+          let url = uri.split('.').join('/');
+          this.action_url = host + '/' + url;
+        }
+        console.log('action_url:', this.action_url);
+      })
+    },
     openDirectry (id) {
       this.$ipcInvoke(ipcApiRoute.openDirectory, {id: id}).then(res => {
         //console.log('res:', res)
@@ -114,6 +151,33 @@ export default {
         self.$message.info(r);
       })
     },
+    handleFileChange(info) {
+      console.log('handleFileChange-----');
+      if (this.action_url == '') {
+        this.$message.error('http服务未开启');
+        return;
+      }
+      const status = info.file.status;
+      if (status !== 'uploading') {
+        console.log(info.file);
+      }
+      if (status === 'done') {
+        const uploadRes = info.file.response;
+        console.log('uploadRes:', uploadRes)
+        if (uploadRes.code !== 'success') {
+          this.$message.error(`file upload failed ${uploadRes.code} .`);
+          return false;
+        }
+        this.num++;
+        const picInfo = uploadRes.data;
+        picInfo.id = this.num;
+        picInfo.imageUrlText = 'image url';
+        this.image_info.push(picInfo);
+        this.$message.success(`${info.file.name} file uploaded successfully.`);
+      } else if (status === 'error') {
+        this.$message.error(`${info.file.name} file upload failed.`);
+      }
+    },
   }
 };
 </script>

+ 0 - 1
frontend/src/views/base/notification/Index.vue

@@ -28,7 +28,6 @@ export default {
           subtitle: '副标题', // macOS系统专有属性
           body: '这是通知内容-默认',
           silent: true,
-          icon: '/asset/images/tray_logo.png',
         },
         {
           type: 'main',

+ 39 - 2
frontend/src/views/base/socket/Ipc.vue

@@ -39,18 +39,39 @@
         <a-button @click="sendMsgStop">结束</a-button>
         结果:{{ messageString }}
       </a-space>
+    </div>
+    <div class="one-block-1">
+      <span>
+        4. 多窗口通信:子窗口与主进程通信,子窗口互相通信
+      </span>
     </div>  
+    <div class="one-block-2">
+      <a-space>
+        <a-button @click="createWindow(0)">打开新窗口2</a-button>
+        <a-button @click="sendTosubWindow()">向新窗口2发消息</a-button>
+      </a-space>
+    </div>      
   </div>
 </template>
 <script>
-import { ipcApiRoute } from '@/api/main'
+import { ipcApiRoute, specialIpcRoute } from '@/api/main'
 export default {
   data() {
     return {
       messageString: '',
       message1: '',
       message2: '',
-      message3: ''
+      message3: '',
+      windowName: 'window-1',
+      newWcId: 0,
+      views: [
+        {
+          type: 'vue',
+          content: '/special/subwindow',
+          windowName: 'window-1',
+          windowTitle: 'new window'
+        },    
+      ],
     }
   },
   mounted () {
@@ -68,6 +89,12 @@ export default {
         // 调用后端的另一个接口
         event.sender.send(ipcApiRoute.hello, 'electron-egg');
       })
+
+      // 监听 窗口2 发来的消息
+      this.$ipc.removeAllListeners(specialIpcRoute.window2ToWindow1);
+      this.$ipc.on(specialIpcRoute.window2ToWindow1, (event, arg) => {
+        this.$message.info(arg);
+      })
     },
     sendMsgStart() {
       const params = {
@@ -99,6 +126,16 @@ export default {
       const msg = this.$ipcSendSync(ipcApiRoute.ipcSendSyncMsg, '同步');
       this.message3 = msg;
     },
+    createWindow (index) {
+      this.$ipcInvoke(ipcApiRoute.createWindow, this.views[index]).then(id => {
+        console.log('[createWindow] id:', id);
+      })
+    },
+    async sendTosubWindow () {
+      // 新窗口id
+      this.newWcId = await this.$ipcInvoke(ipcApiRoute.getWCid, this.windowName);
+      this.$ipc.sendTo(this.newWcId, specialIpcRoute.window1ToWindow2, '窗口1通过 sendTo 给窗口2发送消息');
+    },
   }
 }
 </script>

+ 142 - 0
frontend/src/views/base/subwindow/Ipc.vue

@@ -0,0 +1,142 @@
+<template>
+  <div id="app-base-socket-ipc">
+    <div class="one-block-1">
+      <span>
+        1. 发送异步消息
+      </span>
+    </div>  
+    <div class="one-block-2">
+      <a-space>
+        <a-button @click="handleInvoke">发送 - 回调</a-button>
+        结果:{{ message1 }}
+      </a-space>
+      <p></p>
+      <a-space>
+        <a-button @click="handleInvoke2">发送 - async/await</a-button>
+        结果:{{ message2 }}
+      </a-space>            
+    </div>   
+    <div class="one-block-1">
+      <span>
+        <!-- 尽量不要使用,任何错误都容易引起卡死 -->
+        2. 同步消息(不推荐,阻塞执行)
+      </span>
+    </div>  
+    <div class="one-block-2">
+      <a-space>
+        <a-button @click="handleSendSync">同步消息</a-button>
+        结果:{{ message3 }}
+      </a-space>   
+    </div>        
+    <div class="one-block-1">
+      <span>
+        3. 长消息: 服务端持续向前端页面发消息
+      </span>
+    </div>  
+    <div class="one-block-2">
+      <a-space>
+        <a-button @click="sendMsgStart">开始</a-button>
+        <a-button @click="sendMsgStop">结束</a-button>
+        结果:{{ messageString }}
+      </a-space>
+    </div>
+    <div class="one-block-1">
+      <span>
+        4. 多窗口通信:窗口之间互相通信
+      </span>
+    </div>  
+    <div class="one-block-2">
+      <a-space>
+        <a-button @click="sendTosubWindow()">向主窗口发消息</a-button>
+      </a-space>
+    </div>       
+  </div>
+</template>
+<script>
+import { ipcApiRoute, specialIpcRoute } from '@/api/main'
+export default {
+  data() {
+    return {
+      messageString: '',
+      message1: '',
+      message2: '',
+      message3: '',
+      mainWCid: 0,
+    }
+  },
+  mounted () {
+    this.init();
+  },
+  methods: {
+    init () {
+      const self = this;
+      // 避免重复监听,或者将 on 功能写到一个统一的地方,只加载一次
+      this.$ipc.removeAllListeners(ipcApiRoute.ipcSendMsg);
+      this.$ipc.on(ipcApiRoute.ipcSendMsg, (event, result) => {
+        console.log('[ipcRenderer] [socketMsgStart] result:', result);
+
+        self.messageString = result;
+        // 调用后端的另一个接口
+        event.sender.send(ipcApiRoute.hello, 'electron-egg');
+      })
+
+      // 监听主窗口发来的消息
+      this.$ipc.removeAllListeners(specialIpcRoute.window1ToWindow2);
+      this.$ipc.on(specialIpcRoute.window1ToWindow2, (event, arg) => {
+          this.$message.info(arg);
+      })
+    },
+    sendMsgStart() {
+      const params = {
+        type: 'start',
+        content: '开始'
+      }
+      this.$ipc.send(ipcApiRoute.ipcSendMsg, params)
+    },
+    sendMsgStop() {
+      const params = {
+        type: 'end',
+        content: ''
+      }
+      this.$ipc.send(ipcApiRoute.ipcSendMsg, params)
+    },
+    handleInvoke () {
+      const self = this;
+      this.$ipcInvoke(ipcApiRoute.ipcInvokeMsg, '异步-回调').then(r => {
+        console.log('r:', r);
+        self.message1 = r;
+      });
+    },
+    async handleInvoke2 () {
+      const msg = await this.$ipcInvoke(ipcApiRoute.ipcInvokeMsg, '异步');
+      console.log('msg:', msg);
+      this.message2 = msg;
+    },
+    handleSendSync () {
+      const msg = this.$ipcSendSync(ipcApiRoute.ipcSendSyncMsg, '同步');
+      this.message3 = msg;
+    },
+    sendTosubWindow () {
+      // 获取主窗口id
+      this.$ipcInvoke(ipcApiRoute.getWCid, 'main').then(id => {
+        this.mainWCid = id;
+        this.$ipc.sendTo(this.mainWCid, specialIpcRoute.window2ToWindow1, '窗口2 通过 sendTo 给主窗口发送消息');
+      });
+    },
+  }
+}
+</script>
+<style lang="less" scoped>
+#app-base-socket-ipc {
+  padding: 0px 10px;
+  text-align: left;
+  width: 100%;
+  .one-block-1 {
+    font-size: 16px;
+    padding-top: 10px;
+  }
+  .one-block-2 {
+    padding-top: 10px;
+  }
+}
+</style>

+ 15 - 1
frontend/src/views/base/window/Index.vue

@@ -20,6 +20,16 @@
         <a-button @click="createWindow(1)">打开html页面</a-button>
       </a-space>
     </div>
+    <div class="one-block-1">
+      <span>
+        3. 新窗口中加载当前项目页面
+      </span>
+    </div>  
+    <div class="one-block-2">
+      <a-space>
+        <a-button @click="createWindow(2)">打开vue页面</a-button>
+      </a-space>
+    </div>    
   </div>
 </template>
 <script>
@@ -36,7 +46,11 @@ export default {
         {
           type: 'html',
           content: '/public/html/view_example.html'
-        },        
+        },
+        {
+          type: 'vue',
+          content: '/special/subwindow'
+        },    
       ],
     };
   },

+ 80 - 0
frontend/src/views/special/subwindow/HttpServer.vue

@@ -0,0 +1,80 @@
+<template>
+  <div id="app-base-httpserver">
+    <div class="one-block-1">
+      <span>
+        1. 内置http server服务
+      </span>
+    </div>
+    <div class="one-block-2">
+      <a-space>
+        <p>* 状态:{{ currentStatus }}</p>
+      </a-space>
+      <p>* 地址:{{ servicAddress }}</p>
+    </div>
+    <div class="one-block-1">
+      <span>
+        2. 发送请求
+      </span>
+    </div>    
+    <div class="one-block-2">
+      <a-space>
+        <a-button @click="sendRequest('pictures')"> 打开【我的图片】 </a-button>
+      </a-space>
+    </div>
+  </div>
+</template>
+<script>
+import storage from 'store2'
+import { ipcApiRoute, requestHttp } from '@/api/main'
+
+export default {
+  data() {
+    return {
+      currentStatus: '关闭',
+      servicAddress: '无'
+    };
+  },
+  mounted () {
+    this.init();
+  },
+  methods: {
+    init () {
+      const self = this;
+      this.$ipcInvoke(ipcApiRoute.checkHttpServer, {}).then(r => {
+        if (r.enable) {
+          self.currentStatus = '开启';
+          self.servicAddress = r.server;
+          storage.set('httpServiceConfig', r);
+        }
+      })
+    },
+    sendRequest (id) {
+      if (this.currentStatus == '关闭') {
+        this.$message.error('http服务未开启');
+        return;
+      }
+
+      const params = {
+        id: id
+      }
+      requestHttp(ipcApiRoute.doHttpRequest, params).then(res => {
+        //console.log('res:', res)
+      }) 
+    },  
+  }
+};
+</script>
+<style lang="less" scoped>
+#app-base-httpserver {
+  padding: 0px 10px;
+  text-align: left;
+  width: 100%;
+  .one-block-1 {
+    font-size: 16px;
+    padding-top: 10px;
+  }
+  .one-block-2 {
+    padding-top: 10px;
+  }
+}
+</style>

+ 118 - 0
frontend/src/views/special/subwindow/Ipc.vue

@@ -0,0 +1,118 @@
+<template>
+  <div id="app-base-socket-ipc">
+    <div class="one-block-1">
+      <span>
+        1. 发送异步消息
+      </span>
+    </div>  
+    <div class="one-block-2">
+      <a-space>
+        <a-button @click="handleInvoke">发送 - 回调</a-button>
+        结果:{{ message1 }}
+      </a-space>
+      <p></p>
+      <a-space>
+        <a-button @click="handleInvoke2">发送 - async/await</a-button>
+        结果:{{ message2 }}
+      </a-space>            
+    </div>   
+    <div class="one-block-1">
+      <span>
+        <!-- 尽量不要使用,任何错误都容易引起卡死 -->
+        2. 同步消息(不推荐,阻塞执行)
+      </span>
+    </div>  
+    <div class="one-block-2">
+      <a-space>
+        <a-button @click="handleSendSync">同步消息</a-button>
+        结果:{{ message3 }}
+      </a-space>   
+    </div>        
+    <div class="one-block-1">
+      <span>
+        3. 长消息: 服务端持续向前端页面发消息
+      </span>
+    </div>  
+    <div class="one-block-2">
+      <a-space>
+        <a-button @click="sendMsgStart">开始</a-button>
+        <a-button @click="sendMsgStop">结束</a-button>
+        结果:{{ messageString }}
+      </a-space>
+    </div>  
+  </div>
+</template>
+<script>
+import { ipcApiRoute } from '@/api/main'
+export default {
+  data() {
+    return {
+      messageString: '',
+      message1: '',
+      message2: '',
+      message3: ''
+    }
+  },
+  mounted () {
+    this.init();
+  },
+  methods: {
+    init () {
+      const self = this;
+      // 避免重复监听,或者将 on 功能写到一个统一的地方,只加载一次
+      this.$ipc.removeAllListeners(ipcApiRoute.ipcSendMsg);
+      this.$ipc.on(ipcApiRoute.ipcSendMsg, (event, result) => {
+        console.log('[ipcRenderer] [socketMsgStart] result:', result);
+
+        self.messageString = result;
+        // 调用后端的另一个接口
+        event.sender.send(ipcApiRoute.hello, 'electron-egg');
+      })
+    },
+    sendMsgStart() {
+      const params = {
+        type: 'start',
+        content: '开始'
+      }
+      this.$ipc.send(ipcApiRoute.ipcSendMsg, params)
+    },
+    sendMsgStop() {
+      const params = {
+        type: 'end',
+        content: ''
+      }
+      this.$ipc.send(ipcApiRoute.ipcSendMsg, params)
+    },
+    handleInvoke () {
+      const self = this;
+      this.$ipcInvoke(ipcApiRoute.ipcInvokeMsg, '异步-回调').then(r => {
+        console.log('r:', r);
+        self.message1 = r;
+      });
+    },
+    async handleInvoke2 () {
+      const msg = await this.$ipcInvoke(ipcApiRoute.ipcInvokeMsg, '异步');
+      console.log('msg:', msg);
+      this.message2 = msg;
+    },
+    handleSendSync () {
+      const msg = this.$ipcSendSync(ipcApiRoute.ipcSendSyncMsg, '同步');
+      this.message3 = msg;
+    },
+  }
+}
+</script>
+<style lang="less" scoped>
+#app-base-socket-ipc {
+  padding: 0px 10px;
+  text-align: left;
+  width: 100%;
+  .one-block-1 {
+    font-size: 16px;
+    padding-top: 10px;
+  }
+  .one-block-2 {
+    padding-top: 10px;
+  }
+}
+</style>

+ 77 - 0
frontend/src/views/special/subwindow/SocketServer.vue

@@ -0,0 +1,77 @@
+<template>
+  <div id="app-base-httpserver">
+    <div class="one-block-1">
+      <span>
+        1. 内置socket-io server服务
+      </span>
+    </div>
+    <div class="one-block-2">
+      <a-space>
+        <p>* 状态:{{ currentStatus }}</p>
+      </a-space>
+      <p>* 地址:{{ servicAddress }}</p>
+    </div>
+    <div class="one-block-1">
+      <span>
+        2. 发送请求
+      </span>
+    </div>    
+    <div class="one-block-2">
+      <a-space>
+        <a-button @click="sendRequest('downloads')"> 打开【我的下载】 </a-button>
+      </a-space>
+    </div>
+  </div>
+</template>
+<script>
+import { io } from 'socket.io-client'
+import { ipcApiRoute, requestHttp } from '@/api/main'
+
+export default {
+  data() {
+    return {
+      currentStatus: '关闭',
+      servicAddress: 'ws://127.0.0.1:7070'
+    };
+  },
+  mounted () {
+    this.init();
+  },
+  methods: {
+    init () {
+      const self = this;
+      this.socket = io(this.servicAddress);
+      this.socket.on('connect', () => {
+        console.log('connect!!!!!!!!');
+        self.currentStatus = '开启';
+      });
+    },
+    sendRequest (id) {
+      if (this.currentStatus == '关闭') {
+        this.$message.error('socketio服务未开启');
+        return;
+      }
+
+      const method = ipcApiRoute.doSocketRequest; 
+      this.socket.emit('c1', { cmd: method, params: {id: id} }, (response) => {
+        // response为返回值
+        console.log('response:', response)
+      });
+    },  
+  }
+};
+</script>
+<style lang="less" scoped>
+#app-base-httpserver {
+  padding: 0px 10px;
+  text-align: left;
+  width: 100%;
+  .one-block-1 {
+    font-size: 16px;
+    padding-top: 10px;
+  }
+  .one-block-2 {
+    padding-top: 10px;
+  }
+}
+</style>

+ 1 - 1
frontend/vue.config.js

@@ -12,7 +12,7 @@ module.exports = {
       config
         .plugin('html')
         .tap(args => {
-          args[0].title= 'EE框架' // 设置title
+          //args[0].title= '' // 设置title
           return args
         })
     },

BIN
public/images/logo-32.png