您现在的位置是:首页 >学无止境 >vue Electron ArcGis 桌面应用 Sqllite3 node-grp:老旧项目的起死回生网站首页学无止境

vue Electron ArcGis 桌面应用 Sqllite3 node-grp:老旧项目的起死回生

屋昂仼 2024-09-21 00:01:02
简介vue Electron ArcGis 桌面应用 Sqllite3 node-grp:老旧项目的起死回生

最近接收了一个三四年前做的项目。主要技术栈就是vue2+electron+sqllite3+node-gyp。看到这个技术栈,基本可以知道感知这个项目的关键词:vue、Gis地图、本地数据库、桌面客户端。顿时深感亚历山大。

不多说,开干。

第一步,查看项目

 我一般喜欢直接看一个项目用了哪些东西。然后再慢慢去看具体细节。以上就是这个项目的用到的依赖。首先我们需要下载下来,安装依赖看看。

第二步,升级项目

之前项目用的node 10。而且脚手架和很多依赖版本太低。所以需要对项目做个整容手术。

我的node环境是14。版本不算高。因为公司大多项目很老,贸然升级,下力不讨好。

直接install。

果然不出所料,直接报错。

报错卡在了sqllite3、node-gyp的安装上,大概意思就是没有VC++环境。

行吧,既然这样我在电脑上开始安装VC。

地址:Visual Studio 2022 IDE - 适用于软件开发人员的编程工具

需注意:下载的时候,需要勾选C++客户端开发这个包,否则就白瞎了。

安装成功后,当然还是不行。还要安装python(python安装很简单,自行搜索)。

再次install,终于报错了!!!

electron相关的包完全拉不下来(外网禁止访问)。真是心累。

这里配置electron优点繁琐。有需要可以参考我的另外一篇文章。

vuecli4 electron13.3.0 创建客户端应用以及安装、打包时候遇到的问题_win.loadurl('app://./index.html')_屋昂仼的博客-CSDN博客

索性,我把之前的electron的项目拿过来。两者node_moudules已合并,就齐活了。

npm run electron:dev。

终于又报错了!!

因为之前的项目用的electron的配置文件版本低,有些不适合。所以我再src下直接新建一个background.js, 重新将配置写了一份,并且添加了退出、进入全屏,配置IP端口、打开开发者工具等跨界键和出发事件,整体代码如下:

// background.js
// electron 配置文件

import {
    app,
    BrowserWindow,
    Menu,
    MenuItem,
    ipcMain,
    globalShortcut
} from 'electron'
import {
    appMenuTemplate
} from './electron_app/appmenu.js'
import {
    createProtocol
} from 'vue-cli-plugin-electron-builder/lib'

/**
 * Set `__static` path to static files in production
 * https://simulatedgreg.gitbooks.io/electron-vue/content/en/using-static-assets.html
 */
if (process.env.NODE_ENV !== 'development') {
    global.__static = require('path').join(__dirname, '/static').replace(/\/g, '\\')
}
let path = require('path');

let mainWindow
// http://localhost:9080
// const winURL = process.env.NODE_ENV === 'development' ?
//     `http://localhost:9080` :
//     `file://${__dirname}/index.html`

async function createWindow() {
    /**
     * Initial window options
     */
    mainWindow = new BrowserWindow({
        width: 800,
        height: 600,
        webPreferences: {

            // Use pluginOptions.nodeIntegration, leave this alone
            // See nklayman.github.io/vue-cli-plugin-electron-builder/guide/security.html#node-integration for more info
            // process.env.ELECTRON_NODE_INTEGRATION
            nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION,
            contextIsolation: !process.env.ELECTRON_NODE_INTEGRATION,
            preload: path.join(__dirname, './preload.js')
        },
    })
    // BrowserWindow.addDevToolsExtension('F:/SC/vue/vue-devtools-5.0.0-beta.3/shells/chrome')
    //mainWindow.loadURL(winURL)
    mainWindow.on('closed', () => {
        mainWindow = null
    })
    // 渲染以及控制 web 页面
    // 屏蔽拖入文件浏览器自动打开事件
    mainWindow.webContents.on('will-navigate', function (event) {
        event.preventDefault()
    })
    /**
     * 菜单
     */
    console.info(appMenuTemplate)
    // 增加主菜单(在开发测试时会有一个默认菜单,但打包后这个菜单是没有的,需要自己增加)
    const menu = Menu.buildFromTemplate(appMenuTemplate)
    // 从模板创建主菜单
    // 在File菜单下添加名为New的子菜单
    menu.items[0].submenu.append(new MenuItem({ // menu.items获取是的主菜单一级菜单的菜单数组,menu.items[0]在这里就是第1个File菜单对象,在其子菜单submenu中添加新的子菜单
        label: 'Open Data',
        click() {
            mainWindow.webContents.send('action', 'openkml') // 点击后向主页渲染进程发送“新建文件”的命令
        },
        accelerator: 'CmdOrCtrl+N' // 快捷键:Ctrl+N
    }))
    menu.items[0].submenu.append(new MenuItem({
        role: 'quit'
    }))
    Menu.setApplicationMenu(menu) // 注意:这个代码要放到菜单添加完成之后,否则会造成新增菜单的快捷键无效
    if (process.env.WEBPACK_DEV_SERVER_URL) {
        // Load the url of the dev server if in development mode
        await mainWindow.loadURL(process.env.WEBPACK_DEV_SERVER_URL)
        if (!process.env.IS_TEST) mainWindow.webContents.openDevTools()
    } else {
        createProtocol('app')
        // Load the index.html when not in development
        // win.loadURL('app://./index.html');
        mainWindow.loadURL(path.join(__dirname, './index.html'));
        //mainWindow.webContents.openDevTools()

    }

    //进入软件即开启全屏
    mainWindow.setFullScreen(true);

    // 最大化
    mainWindow.maximize();


    //配置ESC键退出全屏
    globalShortcut.register('ESC', () => {
        mainWindow.setFullScreen(false);
    })

    // ctrl_alt_S 打开地图服务设置
    globalShortcut.register('Alt+CommandOrControl+S', () => {
        mainWindow.webContents.send("asynchronous-message", "123");
    })

    // ctrl_alt_f 打开全屏设置
    globalShortcut.register('Alt+CommandOrControl+F', () => {
        mainWindow.setFullScreen(true);
    })

    // 主进程缩小窗口
    ipcMain.on('window-min', function () { // 收到渲染进程的窗口最小化操作的通知,并调用窗口最小化函数,执行该操作
        mainWindow.minimize();
    })

    // 手动打开开发者工具
    ipcMain.on('open-dev', function () { // 收到渲染进程的窗口最小化操作的通知,并调用窗口最小化函数,执行该操作
        mainWindow.webContents.openDevTools({
            mode: 'bottom'
        })
    })

    // 清楚缓存刷新
    ipcMain.on('force-refresh', function () { // 收到渲染进程的窗口最小化操作的通知,并调用窗口最小化函数,执行该操作
        mainWindow.webContents.reloadIgnoringCache()
    })

}

app.on('ready', createWindow)
app.on('window-all-closed', () => {
    if (process.platform !== 'darwin') {
        app.quit()
    }
})

app.on('activate', () => {
    if (mainWindow === null) {
        createWindow()
    }
})

// 监听与渲染进程的通信(暂时无用)
ipcMain.on('reqaction', (event, arg) => {
    switch (arg) {
        case 'exit':
            // 做点其它操作:比如记录窗口大小、位置等,下次启动时自动使用这些设置;不过因为这里(主进程)无法访问localStorage,这些数据需要使用其它的方式来保存和加载,这里就不作演示了。这里推荐一个相关的工具类库,可以使用它在主进程中保存加载配置数据:https://github.com/sindresorhus/electron-store
            // ...
            app.quit() // 退出程序
            break
    }
})



/**
 * Auto Updater
 *
 * Uncomment the following code below and install `electron-updater` to
 * support auto updating. Code Signing with a valid certificate is required.
 * https://simulatedgreg.gitbooks.io/electron-vue/content/en/using-electron-builder.html#auto-updating
 */

/*
import { autoUpdater } from 'electron-updater'

autoUpdater.on('update-downloaded', () => {
  autoUpdater.quitAndInstall()
})

app.on('ready', () => {
  if (process.env.NODE_ENV === 'production') autoUpdater.checkForUpdates()
})
 */

如上,齐活。

这还不够,需要在vue.config.js中配置相关的打包机制。代码如下:

// vue.config.js
// 配置electron打包
// 注意 我只写electron打包的部分  其他的和vue开发相同,不在赘述


// ....

// 添加electron - app -icon
    pluginOptions: {
        electronBuilder: {
            builderOptions: {
                productName: 'aaaa', //项目名,也是生成的安装文件名
                //copyright: "Copyright © 2023",//版权信息
                win: {
                    icon: './public/aaa.ico',
                    target: [{
                        target: "nsis", //利用nsis制作安装程序
                        arch: [
                            "x64", //64位
                        ]
                    }]
                },
                nsis: {
                    oneClick: false, // 是否一键安装
                    allowElevation: true, // 允许请求提升。 如果为false,则用户必须使用提升的权限重新启动安装程序。
                    allowToChangeInstallationDirectory: true, // 允许修改安装目录
                    installerIcon: "./public/aaa.ico", // 安装图标
                    uninstallerIcon: "./public/aaa.ico", //卸载图标
                    installerHeaderIcon: "./public/aaa.ico", // 安装时头部图标
                    createDesktopShortcut: true, // 创建桌面图标
                    createStartMenuShortcut: true, // 创建开始菜单图标
                    shortcutName: "aaa", // 图标名称
                },
                directories: {
                    output: "./aaa" //输出文件路径
                },
                // 自动更新目录
                publish: [{
                    provider: "generic",
                    url: "http://192.0.xx.xx:8080/", //隐藏版本服务器地址
                }],
            },
            externals: ['clipboard'],
            nodeIntegration: true
        }
    },

这下终于放心了。

开始启动 npm run electron:dev。

终于成功。一切竟是如此美妙。

第三步,改造项目

里边用到了Arcgis。所以需要使用arcgis的地图服务,包含瓦片、影像、航拍服务等。

这里的地址直接去arcgis里边配置就可以,arcgis是收费软件,所以做的也很傻瓜。

这里需要注意就是我们需要动态配置地图服务。

在backgroundjs中我们加了一个快捷键叫 ctrl+alt+s。 这是用来打开地图IP配置界面的。相应的我们在前端也要写一个配置窗口,界面如下:

界面启动之后,按下CTRL+ALT+S就可以开启。

这个配置界面的代码如下:

// vue 配置窗口文件

<!-- 设置地图服务IP -->
    <el-dialog
    :close-on-click-modal="false"
    title="设置"
    :visible.sync="setVisible"
    append-to-body>
        <el-form>
            <el-form-item label="ArcGis的IP和端口, 比如 http://172.17.11.124:8080 ">
                <el-input
                clearable 
                v-model="ARC_URL" 
                placeholder="请输入ArcGis的IP和端口">
                </el-input>
            </el-form-item>
            <el-form-item label="影像地址">
                <el-input
                clearable 
                v-model="YX_URL" 
                placeholder="请输入影像地址">
                </el-input>
            </el-form-item>
            <el-form-item label="航拍地址">
                <el-input
                clearable 
                v-model="HP_URL" 
                placeholder="请输入航拍地址">
                </el-input>
            </el-form-item>
        </el-form>
        <!-- 确定按钮 -->
        <span slot="footer" class="dialog-footer">
            <el-button
            type="success"
            @click="openDevTools"
            >打开开发者工具</el-button>
            <el-button
            type="primary"
            @click="handleClick"
            >保存设置</el-button>
            <el-button @click="handleConcel">取消</el-button>
        </span>
    </el-dialog>

 对应的方法和数据自行去写,不再赘述。

这里再写一下vue内部和electron之间的通信,比如打开开发者工具和保存设置刷新界面都需要通知electron采取相应的动作:

// vue 中打开开发者工具 和 刷新界面 
// 通过 ipcrender 通知electron

 // 打开开发者工具
    openDevTools () {
        ipcRenderer.send('open-dev');
        this.setVisible = false;
    },

// 刷新界面 
reloadPage () {
    ipcRenderer.send('force-refresh');
}




// background js
// electron 中接收这个信号
// 手动打开开发者工具
    ipcMain.on('open-dev', function () { // 收到渲染进程的窗口最小化操作的通知,并调用窗口最小化函数,执行该操作
        mainWindow.webContents.openDevTools({
            mode: 'bottom'
        })
    })

    // 清楚缓存刷新
    ipcMain.on('force-refresh', function () { // 收到渲染进程的窗口最小化操作的通知,并调用窗口最小化函数,执行该操作
        mainWindow.webContents.reloadIgnoringCache()
    })

 一发一收,很方便。

最后,有问题有报错不要怕,一步一步去解决就好。在此,强烈推荐bing搜索,真心好用(google用不了,退而求其次)。

就这样,结束。

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。