Browse Source

electron客户端

yingp 7 năm trước cách đây
mục cha
commit
cdec518abd

+ 4 - 4
frontend/saas-web/app/view/home/charts/KeyData.scss

@@ -55,16 +55,16 @@
                     }
 
                     &-storageTotal {
-                        background-image: url(/resources/images/home/storageTotal.png);
+                        background-image: url(get-resource-path('images/home/storageTotal.png'));
                     }
                     &-receiveTotal {
-                        background-image: url(/resources/images/home/receiveTotal.png);
+                        background-image: url(get-resource-path('images/home/receiveTotal.png'));
                     }
                     &-payTotal {
-                        background-image: url(/resources/images/home/payTotal.png);
+                        background-image: url(get-resource-path('images/home/payTotal.png'));
                     }
                     &-balanceTotal {
-                        background-image: url(/resources/images/home/balanceTotal.png);
+                        background-image: url(get-resource-path('images/home/balanceTotal.png'));
                     }
                 }
 

+ 26 - 8
frontend/saas-web/app/view/viewport/ViewportController.js

@@ -18,8 +18,18 @@ Ext.define('saas.view.viewport.ViewportController', {
     },
 
     init: function() {
-        this.originalRoute = saas.getApplication().getDefaultToken();
-        this.restoreSession();
+        var me = this;
+        me.originalRoute = saas.getApplication().getDefaultToken();
+        // electron app
+        if (typeof require === 'function') {
+            me.ipc = require('electron').ipcRenderer;
+            me.ipc.on('session', function(e, session){
+                saas.util.State.set('session', Ext.decode(session));
+                me.restoreSession();
+            });
+        } else {
+            me.restoreSession();
+        }
     },
 
     mainviewboxready: function() {
@@ -72,7 +82,7 @@ Ext.define('saas.view.viewport.ViewportController', {
     handleUnmatchedRoute: function(route) {
         var me = this;
 
-        if (!me.session || !me.session.isValid()) {
+        if ((!me.session || !me.session.isValid()) && !me.ipc) {
             // There is no authenticated user, let's redirect to the login page but keep track
             // of the original route to restore the requested route after user authentication.
             me.originalRoute = route;
@@ -238,14 +248,22 @@ Ext.define('saas.view.viewport.ViewportController', {
      * @param {} session 
      */
     syncSessionToPortal: function(session) {
-        const frame = window.frames[window.frames.length - 1];
-        frame.postMessage(session ? JSON.stringify(session) : '', '*');
+        var sessionStr = session ? JSON.stringify(session) : '';
+        if (this.ipc) {
+            this.ipc.send('session.change', sessionStr);
+        } else {
+            const frame = window.frames[window.frames.length - 1];
+            frame.postMessage(sessionStr, '*');
+        }
     },
     /**
      * 跳转门户
      */
     redirectPortal: function() {
-        window.location.href = Ext.manifest.server.accountCenter;
+        if (this.ipc) {
+            // window.close();
+        } else {
+            window.location.href = Ext.manifest.server.accountCenter;
+        }
     }
-});
-
+});

BIN
frontend/saas-web/electron/build/icon.icns


BIN
frontend/saas-web/electron/build/icon.ico


BIN
frontend/saas-web/electron/build/icons/48x48.png


+ 2 - 0
frontend/saas-web/electron/dev-app-update.yml

@@ -0,0 +1,2 @@
+provider: generic
+url: http://127.0.0.1/saas/

BIN
frontend/saas-web/electron/images/icon.ico


+ 79 - 2
frontend/saas-web/electron/login.html

@@ -2,13 +2,75 @@
 <html lang="zh_CN">
     <head>
         <title>账户登录 - U企云服</title>
+        <link rel="icon" href="./images/icon.ico" type="image/x-icon">
         <style>
             body {
                 margin: 0;
+                overflow: hidden;
             }
             iframe {
                 border: 0;
             }
+            .loading-wrap {
+                position: absolute;
+                background-color: #fff;
+                width: 100%;
+                height: 100%;
+                text-align: center;
+                z-index: 1;
+            }
+            .loading{
+                display: inline-block;
+                width: 150px;
+                height: 15px;
+                margin: 0 auto;
+                margin-top: 150px;
+            }
+            .loading span{
+                display: inline-block;
+                width: 15px;
+                height: 100%;
+                margin-right: 5px;
+                border-radius: 50%;
+                background: #34baf6;
+                -webkit-animation: load 1.04s ease infinite;
+            }
+            .loading span:last-child{
+                margin-right: 0px; 
+            }
+            @-webkit-keyframes load{
+                0%{
+                    opacity: 1;
+                    -webkit-transform: scale(1.3);
+                }
+                100%{
+                    opacity: 0.2;
+                    -webkit-transform: scale(.3);
+                }
+            }
+            .loading span:nth-child(1){
+                -webkit-animation-delay:0.13s;
+            }
+            .loading span:nth-child(2){
+                -webkit-animation-delay:0.26s;
+            }
+            .loading span:nth-child(3){
+                -webkit-animation-delay:0.39s;
+            }
+            .loading span:nth-child(4){
+                -webkit-animation-delay:0.52s;
+            }
+            .loading span:nth-child(5){
+                -webkit-animation-delay:0.65s;
+            }
+            .message {
+                position: absolute;
+                bottom: 150px;
+                left: 0;
+                width: 100%;
+                text-align: center;
+                color: #9c9c9c;
+            }
         </style>
         <script src="./lib/sockjs.min.js"></script>
         <script src="./lib/stomp.min.js"></script>
@@ -40,6 +102,18 @@
         </script>
     </head>
     <body>
+        <div class="loading-wrap">
+            <div class="loading">
+                <span></span>
+                <span></span>
+                <span></span>
+                <span></span>
+                <span></span>
+            </div>
+            <div class="message">
+                正在读取网络文件,请稍等
+            </div>
+        </div>
         <script>
             const ipc = require('electron').ipcRenderer;
             var clientId = Math.random().toString(36).substr(2);
@@ -49,12 +123,15 @@
                 session.account = account;
                 ipc.send('session.change', JSON.stringify(session));
             });
-            var frame = document.createElement("iframe");
+            var loading = document.querySelector('.loading-wrap'), frame = document.createElement("iframe");
             frame.setAttribute("src", "https://sso.ubtob.com/sassLogin?appId=sp&baseUrl=" + 
                 encodeURIComponent('https://saas-api.usoftchina.com/api/auth/sso/callback/' + clientId));
             frame.setAttribute("width", "430");
-            frame.setAttribute("height", "504");
+            frame.setAttribute("height", "539");
             document.body.appendChild(frame);
+            frame.onload = function() {
+                loading.style.display = 'none';
+            };
         </script>       
     </body>
 </html>

+ 0 - 32
frontend/saas-web/electron/main.dev.js

@@ -1,32 +0,0 @@
-const { app, BrowserWindow } = require('electron');
-let mainWindow;
-
-function createWindow () {
-    mainWindow = new BrowserWindow({ width: 1280, height: 720, show: false });
-    mainWindow.once('ready-to-show', function(){
-        mainWindow.maximize();
-        mainWindow.show();
-    });
-    mainWindow.loadURL('http://127.0.0.1:1841/');
-
-    mainWindow.webContents.openDevTools();
-
-    mainWindow.on('closed', function () {
-        mainWindow = null;
-    });
-}
-
-app.on('ready', createWindow);
-
-// Quit when all windows are closed, except for Mac users
-app.on('window-all-closed', function () {
-    if (process.platform !== 'darwin') {
-        app.quit()
-    }
-});
-
-app.on('activate', function () {
-    if (mainWindow === null) {
-        createWindow();
-    }
-});

+ 111 - 36
frontend/saas-web/electron/main.js

@@ -1,8 +1,14 @@
-const { app, BrowserWindow, ipcMain } = require('electron');
+const electron = require('electron');
+const app = electron.app;
+const BrowserWindow = electron.BrowserWindow;
+const ipcMain = electron.ipcMain;
+const globalShortcut = electron.globalShortcut;
+const { autoUpdater } = require('electron-updater');
 const path = require('path');
 const url = require('url');
-const isLocal = process.argv[process.argv.length - 1] === 'local';
-const extDir = isLocal ? '../build/production/saas' : 'dist';
+const profile = process.argv[process.argv.length - 1];
+const extDir = profile == 'local' ? '../build/production/saas' : 'dist';
+let updateWindow;
 let loginWindow;
 let mainWindow;
 
@@ -10,66 +16,135 @@ let mainWindow;
 ipcMain.on('session.change', (event, arg) => {
     if (arg) {
         loginWindow && loginWindow.close();
-        createMainWindow(arg);
+        if (!mainWindow) {
+			createMainWindow();
+		}
+		if (!mainWindow.isVisible()) {
+			loadMainContents(arg);
+		}
     } else {
-        mainWindow && mainWindow.close();
-        createLoginWindow();
+        if (mainWindow) {
+            mainWindow.hide();
+            mainWindow.webContents.reload();
+        }
+        !loginWindow && createLoginWindow(true);
     }
 });
-
-function createLoginWindow() {
-    loginWindow = new BrowserWindow({ width: 453, height: 513, fullscreenable: false, maximizable: false, resizable: false });
+function sendUpdateMessage(channel, message) {
+    if (updateWindow.webContents.isLoading()) {
+        updateWindow.webContents.on("did-finish-load", function() {
+            updateWindow.webContents.send(channel, message);
+        });
+    } else {
+        updateWindow.webContents.send(channel, message);
+    }
+}
+autoUpdater.on('error', function (error) {
+    loginWindow.show();
+	// 预加载主页
+    createMainWindow(false);
+    updateWindow && updateWindow.close();
+});
+autoUpdater.on('update-available', function (info) {
+    updateWindow && updateWindow.show();
+    sendUpdateMessage('message', info);
+});
+autoUpdater.on('update-not-available', function (info) {
+    loginWindow.show();
+	// 预加载主页
+    createMainWindow(false);
+    updateWindow && updateWindow.close();
+});
+// 下载进度
+autoUpdater.on('download-progress', function (progressObj) {
+    sendUpdateMessage('downloadProgress', progressObj);
+});
+autoUpdater.on('update-downloaded', function () {
+    // 下载完自动安装
+    autoUpdater.quitAndInstall();
+});
+// 自动更新窗口
+function createUpdateWindow() {
+    updateWindow = new BrowserWindow({ width: 453, height: 538, frame: false, show: false });
+    updateWindow.loadURL(url.format({
+        pathname: path.join(__dirname, 'update.html'),
+        protocol: 'file:',
+        slashes: true
+    }));
+    updateWindow.on('closed', function () {
+        updateWindow = null;
+    });
+    autoUpdater.checkForUpdates();
+    // updateWindow.webContents.on("did-finish-load", function() {
+    //     autoUpdater.checkForUpdates();
+    // });
+}
+// 登录窗口
+function createLoginWindow(show) {
+    loginWindow = new BrowserWindow({ width: 453, height: 538, show: !!show, title: '账户登录 - U企云服', fullscreenable: false, maximizable: false, resizable: false });
     loginWindow.loadURL(url.format({
         pathname: path.join(__dirname, 'login.html'),
         protocol: 'file:',
         slashes: true
     }));
 
-    if (isLocal) {
-        loginWindow.webContents.openDevTools();
-    }
-
     loginWindow.on('closed', function () {
         loginWindow = null;
+		if (mainWindow && !mainWindow.isVisible()) {
+            mainWindow.close();
+        }
     });
 }
-
-function createMainWindow (session) {
-    mainWindow = new BrowserWindow({ width: 1280, height: 720, show: false });
-    mainWindow.once('ready-to-show', function(){
-        mainWindow.maximize();
-        mainWindow.show();
-    });
-    mainWindow.loadURL(url.format({
-        pathname: path.join(__dirname, extDir + '/index.html'),
-        protocol: 'file:',
-        slashes: true
-    }));
-
-    if (isLocal) {
-        mainWindow.webContents.openDevTools();
+// 主窗口
+function createMainWindow (show) {
+    const electronScreen = electron.screen;
+    const size = electronScreen.getPrimaryDisplay().workAreaSize;
+    mainWindow = new BrowserWindow({ width: size.width, height: size.height, show: !!show });
+	if (profile == 'dev') {
+        mainWindow.loadURL('http://127.0.0.1:1841/');
+    } else {
+        mainWindow.loadURL(url.format({
+            pathname: path.join(__dirname, extDir + '/index.html'),
+            protocol: 'file:',
+            slashes: true
+        }));
     }
-
-    mainWindow.webContents.on("did-finish-load", function() {
-        mainWindow.webContents.executeJavaScript('\
-            localStorage.setItem("app-state-session", decodeURIComponent("' + encodeURIComponent(session) + '"))');
-    });
+    
     mainWindow.on('closed', function () {
         mainWindow = null;
     });
 }
+function loadMainContents(session) {
+    mainWindow.webContents.send("session", session);
+    mainWindow.maximize();
+    mainWindow.show();
+}
 
-app.on('ready', createLoginWindow);
+function onReady() {
+    globalShortcut.register('ctrl+shift+d', function() {
+        const win = BrowserWindow.getFocusedWindow();
+        win && win.webContents.openDevTools();
+    });
+    createUpdateWindow();
+    // 预加载登录页
+    createLoginWindow(false);
+}
+
+app.on('ready', onReady);
+
+app.on('will-quit', function() {
+    globalShortcut.unregisterAll();
+});
 
 // Quit when all windows are closed, except for Mac users
 app.on('window-all-closed', function () {
     if (process.platform !== 'darwin') {
-        app.quit()
+        app.quit();
     }
 });
 
 app.on('activate', function () {
     if (mainWindow === null) {
-        createMainWindow();
+        onReady();
     }
 });

+ 57 - 10
frontend/saas-web/electron/package.json

@@ -1,21 +1,68 @@
 {
-  "name": "saas-client",
-  "version": "1.0.0",
+  "name": "UsoftchinaSaasClient",
+  "version": "0.0.1",
   "description": "saas在线进销存系统",
   "main": "./main.js",
   "scripts": {
-    "dev-start": "electron ./main.dev.js",
-    "prod-start": "electron . local",
+    "dev-start": "electron . dev",
+    "local-start": "electron . local",
     "build": "cd ../ && sencha app build --build prod --destination electron/dist/ --production",
-    "pack-win": "electron-packager . saas --overwrite --asar --platform=win32 --arch=x64 --out=out --ignore=\"(src|docs|out|.gitignore|LICENSE.md|README.md|npm-debug.log|node_modules|.idea|main.dev.js|package-lock.json|yarn.lock)\"",
-    "pack": "npm run build && npm run pack-win"
+    "pack": "npm run build && electron-builder --dir",
+    "dist": "npm run build && electron-builder"
   },
-  "author": "yingp@usoftchina.com",
+  "author": "深圳市优软科技有限公司",
   "license": "ISC",
   "dependencies": {
-    "electron": "^1.8.1"
+    "electron-updater": "^4.0.6"
   },
   "devDependencies": {
-    "electron-packager": "^9.0.1"
+    "electron": "^3.0.11",
+    "electron-builder": "^20.38.3"
+  },
+  "build": {
+    "productName": "U企云服",
+    "appId": "saas.usoftchina.com",
+    "directories": {
+      "output": "out"
+    },
+    "publish": [
+      {
+        "provider": "generic",
+        "url": "https://saas-assets.usoftchina.com"
+      }
+    ],
+    "files": [
+      "dist/**/*",
+      "lib/**/*",
+      "images/**/*",
+      "main.js",
+      "*.html"
+    ],
+    "mac": {
+      "artifactName": "${name}_setup_${version}.${ext}"
+    },
+    "win": {
+      "target": "nsis-web",
+      "artifactName": "${name}_setup_${version}.${ext}"
+    },
+    "linux": {
+      "artifactName": "${name}_setup_${version}.${ext}"
+    }
+  },
+  "nsis": {
+    "oneClick": true,
+    "perMachine": true,
+    "allowElevation": true,
+    "allowToChangeInstallationDirectory": true,
+    "createDesktopShortcut": true,
+    "runAfterFinish": true
+  },
+  "nsisWeb": {
+    "oneClick": true,
+    "perMachine": true,
+    "allowElevation": true,
+    "allowToChangeInstallationDirectory": true,
+    "createDesktopShortcut": true,
+    "runAfterFinish": true
   }
-}
+}

+ 85 - 0
frontend/saas-web/electron/update.html

@@ -0,0 +1,85 @@
+<!DOCTYPE html>
+<html lang="zh_CN">
+    <head>
+        <title>软件更新 - U企云服</title>
+        <style>
+            body {
+                margin: 0;
+                font-family: 'Microsoft YaHei';
+                font-size: 16px;
+                overflow: hidden;
+            }
+            .block {
+                position: relative;
+                transition: .2s;
+                padding: 24px;
+            }
+            .progress {
+                position: relative;
+                line-height: 1;
+            }
+            .progress-circle {
+                height: 126px; 
+                width: 126px;
+                margin: 103px auto;
+            }
+            .progress-text {
+                position: absolute;
+                top: 50%;
+                left: 0;
+                width: 100%;
+                text-align: center;
+                color: #606266;
+                display: inline-block;
+                vertical-align: middle;
+                line-height: 1;
+                transform: translateY(-50%);
+            }
+            .message {
+                position: absolute;
+                bottom: 20px;
+                left: 0;
+                width: 100%;
+                text-align: center;
+                color: #9c9c9c;
+            }
+        </style>
+    </head>
+    <body>
+        <div class="block">
+            <div class="progress">
+                <div class="progress-circle">
+                    <svg viewBox="0 0 100 100">
+                        <path d="M 50 50 m 0 -47 a 47 47 0 1 1 0 94 a 47 47 0 1 1 0 -94" stroke="#e5e9f2" stroke-width="4.8" fill="none" class="progress-circle-track"></path>
+                        <path d="M 50 50 m 0 -47 a 47 47 0 1 1 0 94 a 47 47 0 1 1 0 -94" stroke-linecap="round" stroke="#20a0ff" stroke-width="4.8" fill="none" class="progress-circle-path" 
+                            style="stroke-dasharray: 299.08px, 299.08px; stroke-dashoffset: 299.08px; transition: stroke-dashoffset 0.6s ease 0s, stroke 0.6s ease 0s;"></path>
+                    </svg>
+                </div>
+                <div class="progress-text">0%</div>
+            </div>
+            <div class="message">
+                <span class="version"></span><span class="action">正在更新</span>,请稍等
+            </div>
+        </div>
+
+        <script>
+            const ipcRenderer = require('electron').ipcRenderer;
+            ipcRenderer.on("message", (event, text) => {
+                document.querySelector('.version').innerHTML = '版本' + text.version;
+            });
+            ipcRenderer.on("downloadProgress", (event, progressObj)=> {
+                const percent = Math.round(progressObj.percent || 0);
+                const pathEl = document.querySelector('.progress-circle-path');
+                pathEl.style.strokeDashoffset = 299.08*(1 - percent/100) + 'px';
+                if (percent >= 100) {
+                    pathEl.style.stroke = '#13ce66';
+                    document.querySelector('.action').innerHTML = '下载完毕,准备安装';
+                } else if (percent >= 50) {
+                    pathEl.style.stroke = '#8e71c7';
+                }
+                const textEl = document.querySelector('.progress-text');
+                textEl.innerHTML = percent >= 100 ? '√' : (percent + '%');
+            });
+        </script>       
+    </body>
+</html>

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 515 - 199
frontend/saas-web/electron/yarn.lock


+ 5 - 1
frontend/saas-web/overrides/data/Connection.js

@@ -18,7 +18,11 @@ Ext.define('saas.override.data.Connection', {
     privates: {
         parseBasePath: function(basePath) {
             if (Ext.isObject(basePath)) {
-                return basePath[window.location.protocol.split(":")[0]];
+                var protocol = window.location.protocol.split(":")[0];
+                if (protocol === 'file') {
+                    protocol = 'https';
+                }
+                return basePath[protocol];
             }
             return basePath;
         },

Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác